Skip to content

Commit a9b4e26

Browse files
authored
Optimize map generation (#62)
* 分离出访问更快的chunk storage * 分离出访问更快的 chunk storage
1 parent bc82851 commit a9b4e26

26 files changed

+259
-136
lines changed

src/MineCase.Server.Interfaces/World/ChunkColumnStorage.cs renamed to src/MineCase.Core/World/ChunkColumnCompactStorage.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using System.Runtime.InteropServices;
44
using System.Text;
55

6-
namespace MineCase.Server.World
6+
namespace MineCase.World
77
{
88
public static class ChunkConstants
99
{
@@ -14,7 +14,7 @@ public static class ChunkConstants
1414
public const int BlocksInSection = BlockEdgeWidthInSection * BlockEdgeWidthInSection * BlockEdgeWidthInSection;
1515
}
1616

17-
public sealed class ChunkColumnStorage
17+
public sealed class ChunkColumnCompactStorage
1818
{
1919
public uint SectionBitMask
2020
{
@@ -32,7 +32,7 @@ public uint SectionBitMask
3232
}
3333
}
3434

35-
public ChunkSectionStorage[] Sections { get; } = new ChunkSectionStorage[ChunkConstants.SectionsPerChunk];
35+
public ChunkSectionCompactStorage[] Sections { get; } = new ChunkSectionCompactStorage[ChunkConstants.SectionsPerChunk];
3636

3737
public byte[] Biomes { get; } = new byte[256];
3838

@@ -43,14 +43,14 @@ public uint SectionBitMask
4343
}
4444
}
4545

46-
public sealed class ChunkSectionStorage
46+
public sealed class ChunkSectionCompactStorage
4747
{
4848
private const byte _bitsId = 9;
4949
private const byte _bitsMeta = 4;
5050
private const byte _bitsPerBlock = _bitsId + _bitsMeta;
5151
private const uint _idMask = (1u << _bitsId) - 1;
5252
private const uint _metaMask = (1u << _bitsMeta) - 1;
53-
private const ulong _blockMask = (1u << _bitsPerBlock) - 1;
53+
public const ulong BlockMask = (1u << _bitsPerBlock) - 1;
5454

5555
public byte BitsPerBlock => _bitsPerBlock;
5656

@@ -60,7 +60,7 @@ public sealed class ChunkSectionStorage
6060

6161
public NibbleArray SkyLight { get; }
6262

63-
public ChunkSectionStorage(bool hasSkylight)
63+
public ChunkSectionCompactStorage(bool hasSkylight)
6464
{
6565
if (hasSkylight)
6666
SkyLight = new NibbleArray();
@@ -88,7 +88,7 @@ public sealed class DataArray
8888
var stgValue = ((ulong)value.Id << _bitsMeta) | (value.MetaValue & _metaMask);
8989
var offset = GetOffset(x, y, z);
9090
var tmpValue = Storage[offset.indexOffset];
91-
var mask = _blockMask << offset.bitOffset;
91+
var mask = BlockMask << offset.bitOffset;
9292
var toWrite = Math.Min(_bitsPerBlock, 64 - offset.bitOffset);
9393
Storage[offset.indexOffset] = (tmpValue & ~mask) | (stgValue << offset.bitOffset);
9494
var rest = _bitsPerBlock - toWrite;
@@ -139,7 +139,7 @@ private static int GetBlockSerialIndex(int x, int y, int z)
139139
return ((y * ChunkConstants.BlockEdgeWidthInSection) + z) * ChunkConstants.BlockEdgeWidthInSection + x;
140140
}
141141

142-
internal static uint ToUInt32(ref BlockState blockState)
142+
public static uint ToUInt32(ref BlockState blockState)
143143
{
144144
return ((blockState.Id & _idMask) << _bitsMeta) | (blockState.MetaValue & _metaMask);
145145
}

src/MineCase.Server.Grains/Network/Play/ClientPlayPacketGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
using System.Numerics;
66
using System.Text;
77
using System.Threading.Tasks;
8-
98
using MineCase.Protocol.Play;
109
using MineCase.Serialization;
1110
using MineCase.Server.Game;
1211
using MineCase.Server.Game.Entities;
1312
using MineCase.Server.Game.Entities.EntityMetadata;
1413
using MineCase.Server.World;
14+
using MineCase.World;
1515
using Orleans.Concurrency;
1616

1717
namespace MineCase.Server.Network.Play
@@ -247,7 +247,7 @@ public Task CollectItem(uint collectedEntityId, uint entityId, uint itemCount)
247247
});
248248
}
249249

250-
public Task ChunkData(Dimension dimension, int chunkX, int chunkZ, ChunkColumnStorage chunkColumn)
250+
public Task ChunkData(Dimension dimension, int chunkX, int chunkZ, ChunkColumnCompactStorage chunkColumn)
251251
{
252252
return Sink.SendPacket(new ChunkData
253253
{

src/MineCase.Server.Grains/World/ChunkColumnGrain.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using MineCase.Server.Network.Play;
1111
using MineCase.Server.Settings;
1212
using MineCase.Server.World.Generation;
13+
using MineCase.World;
1314
using Orleans;
1415
using Orleans.Concurrency;
1516

@@ -23,7 +24,7 @@ internal class ChunkColumnGrain : Grain, IChunkColumn
2324
private int _chunkZ;
2425

2526
private bool _generated = false;
26-
private ChunkColumnStorage _state;
27+
private ChunkColumnCompactStorage _state;
2728
private Dictionary<BlockChunkPos, IBlockEntity> _blockEntities;
2829

2930
public async Task<BlockState> GetBlockState(int x, int y, int z)
@@ -32,7 +33,7 @@ public async Task<BlockState> GetBlockState(int x, int y, int z)
3233
return _state[x, y, z];
3334
}
3435

35-
public async Task<ChunkColumnStorage> GetState()
36+
public async Task<ChunkColumnCompactStorage> GetState()
3637
{
3738
await EnsureChunkGenerated();
3839
return _state;

src/MineCase.Server.Grains/World/Generation/ChunkGeneratorFlatGrain.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.IO;
33
using System.Threading.Tasks;
44
using Microsoft.Extensions.Logging;
5+
using MineCase.World;
56
using Newtonsoft.Json;
67
using Orleans;
78
using Orleans.Concurrency;
@@ -12,18 +13,18 @@ namespace MineCase.Server.World.Generation
1213
[StatelessWorker]
1314
internal class ChunkGeneratorFlatGrain : Grain, IChunkGeneratorFlat
1415
{
15-
public Task<ChunkColumnStorage> Generate(IWorld world, int x, int z, GeneratorSettings settings)
16+
public Task<ChunkColumnCompactStorage> Generate(IWorld world, int x, int z, GeneratorSettings settings)
1617
{
17-
var chunkColumn = new ChunkColumnStorage();
18+
var chunkColumn = new ChunkColumnCompactStorage();
1819
for (int i = 0; i < chunkColumn.Sections.Length; ++i)
19-
chunkColumn.Sections[i] = new ChunkSectionStorage(true);
20+
chunkColumn.Sections[i] = new ChunkSectionCompactStorage(true);
2021

2122
GenerateChunk(world, chunkColumn, x, z, settings);
2223
PopulateChunk(world, chunkColumn, x, z, settings);
2324
return Task.FromResult(chunkColumn);
2425
}
2526

26-
private void GenerateChunk(IWorld world, ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
27+
private void GenerateChunk(IWorld world, ChunkColumnCompactStorage chunk, int x, int z, GeneratorSettings settings)
2728
{
2829
// 按照flat模式每层的设置给chunk赋值
2930
for (int y = 0; y < settings.FlatBlockId.Length; ++y)
@@ -46,7 +47,7 @@ private void GenerateChunk(IWorld world, ChunkColumnStorage chunk, int x, int z,
4647
// todo biomes
4748
}
4849

49-
private void PopulateChunk(IWorld world, ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
50+
private void PopulateChunk(IWorld world, ChunkColumnCompactStorage chunk, int x, int z, GeneratorSettings settings)
5051
{
5152
// TODO generator tree, grass, structures\
5253
}

src/MineCase.Server.Grains/World/Generation/ChunkGeneratorOverworldGrain.cs

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using MineCase.Server.World.Biomes;
1111
using MineCase.Server.World.Layer;
1212
using MineCase.Server.World.Mine;
13+
using MineCase.World;
1314
using Newtonsoft.Json;
1415
using Orleans;
1516
using Orleans.Concurrency;
@@ -33,6 +34,7 @@ internal class ChunkGeneratorOverWorldGrain : Grain, IChunkGeneratorOverworld
3334
private OctavedNoise<PerlinNoise> _minNoise;
3435
private OctavedNoise<PerlinNoise> _surfaceNoise;
3536

37+
private int _seed;
3638
private Random _random;
3739

3840
private float[,] _biomeWeights;
@@ -50,8 +52,8 @@ public override Task OnActivateAsync()
5052
_maxLimitMap = new float[5, 33, 5];
5153
_surfaceMap = new float[16, 1, 16];
5254

53-
int seed = (int)this.GetPrimaryKeyLong();
54-
_random = new Random(seed);
55+
_seed = (int)this.GetPrimaryKeyLong();
56+
_random = new Random(_seed);
5557
_depthNoise = new OctavedNoise<PerlinNoise>(new PerlinNoise(_random.Next()), 8, 0.5F);
5658
_mainNoise = new OctavedNoise<PerlinNoise>(new PerlinNoise(_random.Next()), 8, 0.5F);
5759
_maxNoise = new OctavedNoise<PerlinNoise>(new PerlinNoise(_random.Next()), 8, 0.5F);
@@ -70,23 +72,27 @@ public override Task OnActivateAsync()
7072

7173
_biomesForGeneration = new Biome[16, 16];
7274

73-
_genlayer = GenLayer.InitAllLayer(seed);
75+
_genlayer = GenLayer.InitAllLayer(_seed);
7476

7577
return Task.CompletedTask;
7678
}
7779

78-
public async Task<ChunkColumnStorage> Generate(IWorld world, int x, int z, GeneratorSettings settings)
80+
public async Task<ChunkColumnCompactStorage> Generate(IWorld world, int x, int z, GeneratorSettings settings)
7981
{
8082
var chunkColumn = new ChunkColumnStorage();
8183
for (int i = 0; i < chunkColumn.Sections.Length; ++i)
8284
chunkColumn.Sections[i] = new ChunkSectionStorage(true);
8385

84-
await GenerateChunk(world, chunkColumn, x, z, settings);
85-
await PopulateChunk(world, chunkColumn, x, z, settings);
86-
return chunkColumn;
86+
var info = new MapGenerationInfo
87+
{
88+
Seed = await world.GetSeed()
89+
};
90+
GenerateChunk(info, chunkColumn, x, z, settings);
91+
PopulateChunk(world, chunkColumn, x, z, settings);
92+
return chunkColumn.Compact();
8793
}
8894

89-
public async Task GenerateChunk(IWorld world, ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
95+
private void GenerateChunk(MapGenerationInfo info, ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
9096
{
9197
// 生物群系生成
9298
// 获取生物群系
@@ -101,7 +107,7 @@ public async Task GenerateChunk(IWorld world, ChunkColumnStorage chunk, int x, i
101107
}
102108

103109
// 基本地形生成
104-
await GenerateBasicTerrain(chunk, x, z, settings);
110+
GenerateBasicTerrain(chunk, x, z, settings);
105111

106112
// 获取生物群系
107113
biomeIds = _genlayer.GetInts(x * 16, z * 16, 16, 16);
@@ -124,33 +130,33 @@ public async Task GenerateChunk(IWorld world, ChunkColumnStorage chunk, int x, i
124130
}
125131

126132
// 添加生物群系特有方块
127-
await ReplaceBiomeBlocks(settings, x, z, chunk, _biomesForGeneration);
133+
ReplaceBiomeBlocks(settings, x, z, chunk, _biomesForGeneration);
128134

129135
// Todo genrate structure
130136
// 生成洞穴
131137
if (settings.UseCaves)
132138
{
133-
CavesGenerator generator = new CavesGenerator(world);
134-
await generator.Generate(world, x, z, chunk);
139+
CavesGenerator generator = new CavesGenerator(info);
140+
generator.Generate(info, x, z, chunk);
135141
}
136142

137143
// 计算skylight
138-
await GenerateSkylightMap(chunk);
144+
GenerateSkylightMap(chunk);
139145
}
140146

141-
public async Task PopulateChunk(IWorld world, ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
147+
public void PopulateChunk(IWorld world, ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
142148
{
143149
int blockX = x * 16;
144150
int blockZ = z * 16;
145151
Biome chunkBiome = Biome.GetBiome(chunk.Biomes[7 * 16 + 7], settings);
146152

147-
await chunkBiome.Decorate(world, GrainFactory, chunk, _random, new BlockWorldPos { X = blockX, Y = 0, Z = blockZ });
153+
chunkBiome.Decorate(world, GrainFactory, chunk, _random, new BlockWorldPos { X = blockX, Y = 0, Z = blockZ });
148154
}
149155

150-
private async Task GenerateBasicTerrain(ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
156+
private void GenerateBasicTerrain(ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
151157
{
152158
// 产生高度图
153-
await GenerateDensityMap(_densityMap, x * 4, 0, z * 4, settings);
159+
GenerateDensityMap(_densityMap, x * 4, 0, z * 4, settings);
154160

155161
// 进行线性插值
156162
for (int xHigh = 0; xHigh < 4; ++xHigh)
@@ -213,7 +219,7 @@ private async Task GenerateBasicTerrain(ChunkColumnStorage chunk, int x, int z,
213219
}
214220
}
215221

216-
private Task GenerateDensityMap(float[,,] densityMap, int xOffset, int yOffset, int zOffset, GeneratorSettings settings)
222+
private void GenerateDensityMap(float[,,] densityMap, int xOffset, int yOffset, int zOffset, GeneratorSettings settings)
217223
{
218224
_depthNoise.Noise(
219225
_depthMap,
@@ -361,10 +367,9 @@ private Task GenerateDensityMap(float[,,] densityMap, int xOffset, int yOffset,
361367
}
362368

363369
densityMap = _densityMap;
364-
return Task.CompletedTask;
365370
}
366371

367-
private Task ReplaceBiomeBlocks(GeneratorSettings settings, int x, int z, ChunkColumnStorage chunk, Biome[,] biomesIn)
372+
private void ReplaceBiomeBlocks(GeneratorSettings settings, int x, int z, ChunkColumnStorage chunk, Biome[,] biomesIn)
368373
{
369374
_surfaceNoise.Noise(
370375
_surfaceMap,
@@ -379,30 +384,34 @@ private Task ReplaceBiomeBlocks(GeneratorSettings settings, int x, int z, ChunkC
379384
biome.GenerateBiomeTerrain(settings.SeaLevel, _random, chunk, x, z, x1, z1, (_surfaceMap[x1, 0, z1] - 0.5) * 2);
380385
}
381386
}
382-
383-
return Task.CompletedTask;
384387
}
385388

386-
private Task GenerateSkylightMap(ChunkColumnStorage chunk)
389+
private void GenerateSkylightMap(ChunkColumnStorage chunk)
387390
{
388-
for (int y = 0; y < 256; ++y)
391+
for (int i = 0; i < ChunkConstants.SectionsPerChunk; ++i)
389392
{
390-
var section = chunk.Sections[y / 16];
391-
for (int i = 0; i < section.SkyLight.Storage.Length; i++)
392-
section.SkyLight.Storage[i] = 0xFF;
393+
var skyLight = chunk.Sections[i].SkyLight;
394+
for (int y = 0; y < ChunkConstants.BlockEdgeWidthInSection; y++)
395+
{
396+
for (int z = 0; z < ChunkConstants.BlockEdgeWidthInSection; z++)
397+
{
398+
for (int x = 0; x < ChunkConstants.BlockEdgeWidthInSection; x++)
399+
{
400+
skyLight[x, y, z] = 0xF;
401+
}
402+
}
403+
}
393404
}
394-
395-
return Task.CompletedTask;
396405
}
397406

398-
private Task<int> GetDensityMapIndex(int x, int y, int z)
407+
private int GetDensityMapIndex(int x, int y, int z)
399408
{
400-
return Task.FromResult((x * 5 + z) * 33 + y);
409+
return (x * 5 + z) * 33 + y;
401410
}
402411

403-
private Task<double> GetDensityMapValue(double[] densityMap, int x, int y, int z)
412+
private double GetDensityMapValue(double[] densityMap, int x, int y, int z)
404413
{
405-
return Task.FromResult(densityMap[(x * 5 + z) * 33 + y]);
414+
return densityMap[(x * 5 + z) * 33 + y];
406415
}
407416
}
408417
}

src/MineCase.Server.Interfaces/World/Biomes/Biome.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using MineCase.Server.World.Generation;
77
using MineCase.Server.World.Mine;
88
using MineCase.Server.World.Plants;
9+
using MineCase.World;
910
using Orleans;
1011

1112
namespace MineCase.Server.World.Biomes
@@ -252,7 +253,7 @@ public void GenerateOre(MinableGenerator generator, IWorld world, IGrainFactory
252253
}
253254

254255
// 后期添加一些方块,Biome基类主要生成矿物
255-
public virtual Task Decorate(IWorld world, IGrainFactory grainFactory, ChunkColumnStorage chunk, Random rand, BlockWorldPos pos)
256+
public virtual void Decorate(IWorld world, IGrainFactory grainFactory, ChunkColumnStorage chunk, Random rand, BlockWorldPos pos)
256257
{
257258
GenerateOre(_dirtGen, world, grainFactory, chunk, rand, pos, _genSettings.DirtCount, _genSettings.DirtMaxHeight, _genSettings.DirtMinHeight);
258259
GenerateOre(_gravelOreGen, world, grainFactory, chunk, rand, pos, _genSettings.GravelCount, _genSettings.GravelMaxHeight, _genSettings.GravelMinHeight);
@@ -266,7 +267,6 @@ public virtual Task Decorate(IWorld world, IGrainFactory grainFactory, ChunkColu
266267
GenerateOre(_redstoneGen, world, grainFactory, chunk, rand, pos, _genSettings.RedstoneCount, _genSettings.RedstoneMaxHeight, _genSettings.RedstoneMinHeight);
267268
GenerateOre(_diamondGen, world, grainFactory, chunk, rand, pos, _genSettings.DiamondCount, _genSettings.DiamondMaxHeight, _genSettings.DiamondMinHeight);
268269
GenerateOre(_lapisGen, world, grainFactory, chunk, rand, pos, _genSettings.LapisCount, _genSettings.LapisCenterHeight + _genSettings.LapisSpread, _genSettings.LapisCenterHeight - _genSettings.LapisSpread);
269-
return Task.CompletedTask;
270270
}
271271

272272
// 产生生物群系特有的方块

0 commit comments

Comments
 (0)