From c3c4501c5762bfea4c76171a3fc7c7c1cbe1bbc8 Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Tue, 25 Mar 2025 20:01:21 +0100 Subject: [PATCH 1/2] initial generation --- OpenPolytopia.Common/City.cs | 2 + OpenPolytopia.Common/Grid.cs | 22 +++++- OpenPolytopia.Common/Player.cs | 4 ++ OpenPolytopia.Common/TerrainGeneration.cs | 83 +++++++++++++++++++++++ OpenPolytopia/test/src/GridTest.cs | 6 ++ 5 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 OpenPolytopia.Common/Player.cs create mode 100644 OpenPolytopia.Common/TerrainGeneration.cs diff --git a/OpenPolytopia.Common/City.cs b/OpenPolytopia.Common/City.cs index a0e53e8..2a31e10 100644 --- a/OpenPolytopia.Common/City.cs +++ b/OpenPolytopia.Common/City.cs @@ -11,6 +11,8 @@ namespace OpenPolytopia.Common; public class CityManager(Grid grid) { private readonly List _cities = []; + public IEnumerable Cities => _cities; + /// /// Access to the /// diff --git a/OpenPolytopia.Common/Grid.cs b/OpenPolytopia.Common/Grid.cs index a81c3b7..b34ca5f 100644 --- a/OpenPolytopia.Common/Grid.cs +++ b/OpenPolytopia.Common/Grid.cs @@ -64,6 +64,19 @@ public Tile this[uint index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint GridPositionToIndex(int x, int y) => (uint)((y * size) + x); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector2I IndexToGridPosition(uint index) { + var x = index % size; + var y = (index - x) / size; + return new Vector2I((int)x, (int)y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void IndexToGridPosition(uint index, out uint x, out uint y) { + x = index % size; + y = (index - x) / size; + } + /// /// Modifies a given tile /// @@ -215,7 +228,7 @@ public static Type GetModifier(TileKind kind) => /// Using 0 as the left-most bit and 63 as the right-most bit /// /// 0 -> 1: has road; 0 doesn't have any road; (bridge if on water) - /// 1 -> 1: has ancient ruin; 0 doesn't have any ruin + /// 1 -> 2: has ancient ruin; 0 doesn't have any ruin /// [2, 4] -> /// [5, 6] -> Tile modifier /// [7, 9] -> Tile buildings @@ -251,7 +264,12 @@ public bool Ruin { /// /// The type of the tile /// - public TileKind Kind => (TileKind)_inner.GetBits(THREE_BITS, TILEKIND_POSITION); + public TileKind Kind { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (TileKind)_inner.GetBits(THREE_BITS, TILEKIND_POSITION); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => _inner.SetBits((ulong)value, THREE_BITS, TILEKIND_POSITION); + } /// /// The tile modifier castable to the corresponding enum diff --git a/OpenPolytopia.Common/Player.cs b/OpenPolytopia.Common/Player.cs new file mode 100644 index 0000000..3f6915e --- /dev/null +++ b/OpenPolytopia.Common/Player.cs @@ -0,0 +1,4 @@ +namespace OpenPolytopia.Common; + +public record Player(TribeType Tribe, int Id) { +} diff --git a/OpenPolytopia.Common/TerrainGeneration.cs b/OpenPolytopia.Common/TerrainGeneration.cs new file mode 100644 index 0000000..b212544 --- /dev/null +++ b/OpenPolytopia.Common/TerrainGeneration.cs @@ -0,0 +1,83 @@ +namespace OpenPolytopia.Common; + +using System.Runtime.CompilerServices; + +public class TerrainGeneration( + Grid grid, + CityManager cityManager, + TribeManager tribeManager, + Player[] players, + int? seed = null) { + // create the random number generator from a seed if set + private readonly Random _rng = seed == null ? new Random() : new Random(seed.Value); + + /// + /// Generates the map ready to use in-game + /// + /// + /// + /// var terrainGeneration = new TerrainGeneration(grid, cityManager, tribeManager); + /// await terrainGeneration.GenerateMapAsync(); + /// + /// + public async Task GenerateMapAsync() { + await GenerateInitialCitiesAsync(); + await GenerateTerrainAsync(); + await GenerateCitiesAsync(); + await GenerateResourcesAsync(); + } + + private async Task GenerateInitialCitiesAsync() { + // for each player + foreach (var player in players) { + // yield to the task executor + await Task.Yield(); + + // compute the index position of a random tile in the grid + var index = (uint)_rng.Next(0, (int)(grid.Size * grid.Size)); + + // check if the computed index is valid + var valid = false; + while (!valid) { + if (IsCityValid(index)) { + valid = true; + } + else { + index = (uint)_rng.Next(0, (int)(grid.Size * grid.Size)); + } + } + + // register the city + var cityId = cityManager.RegisterCity(index); + + // set all data for the tile in the grid + grid.ModifyTile(index, (ref Tile tile) => { + tile.Owner = player.Id; + tile.Kind = TileKind.Village; + tile.Modifier = (int)VillageTileModifier.City; + }); + + // set all data for the city + cityManager.ModifyCity(cityId, (ref CityData city) => { + city.Capital = true; + city.Owner = player.Id; + city.Level = 1; + }); + } + } + + private async Task GenerateTerrainAsync() { + } + + private async Task GenerateCitiesAsync() { + } + + private async Task GenerateResourcesAsync() { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsCityValid(uint index) { + grid.IndexToGridPosition(index, out var x, out var y); + return grid[index].Owner == 0 && x > 0 && y > 0 && x < grid.Size - 1 && y < grid.Size - 1; + } +} diff --git a/OpenPolytopia/test/src/GridTest.cs b/OpenPolytopia/test/src/GridTest.cs index 0a7a2ec..fc18e71 100644 --- a/OpenPolytopia/test/src/GridTest.cs +++ b/OpenPolytopia/test/src/GridTest.cs @@ -12,6 +12,12 @@ public void TestPositionToIndex() { grid.GridPositionToIndex(new Vector2I(2, 2)).ShouldBe(22u); } + [Test] + public void TestIndexToPosition() { + var grid = new Grid(10); + grid.IndexToGridPosition(22u).ShouldBe(new Vector2I(2, 2)); + } + [Test] public void TestModifyTile() { var grid = new Grid(10); From 18506b24f8c94b216d272e6502cad30d7da089d0 Mon Sep 17 00:00:00 2001 From: Enn3Developer Date: Wed, 15 Oct 2025 16:49:41 +0200 Subject: [PATCH 2/2] added doc comments --- OpenPolytopia.Common/TerrainGeneration.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/OpenPolytopia.Common/TerrainGeneration.cs b/OpenPolytopia.Common/TerrainGeneration.cs index b212544..90912db 100644 --- a/OpenPolytopia.Common/TerrainGeneration.cs +++ b/OpenPolytopia.Common/TerrainGeneration.cs @@ -2,6 +2,14 @@ namespace OpenPolytopia.Common; using System.Runtime.CompilerServices; +/// +/// Terrain generation system +/// +/// the grid to use +/// the city manager to use +/// the tribe manager to use +/// all the players in the game +/// the optional random seed public class TerrainGeneration( Grid grid, CityManager cityManager,