Skip to content

Commit c83f8f7

Browse files
jstzwjsunnycase
authored andcommitted
Add chunk generator (#27)
* Update git ignore * Add ChunkGenratorFlat(without test) * Add densityMapGenerator and BlockGenerator Methods. * commit before merge * Add biomes * Add genlayer * Fix code style errors * Format the code * Finish the basic function of ChunkGeneratorFlat * Testing overworld generator * Basic function of flat generator * Basic test of overworld generator * modified to use new chunk storage * Fix some bugs in Overworld generator * Update ChunkGeneratorOverworld
1 parent 2d77299 commit c83f8f7

29 files changed

+1293
-133
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,6 @@ paket-files/
260260
__pycache__/
261261
*.pyc
262262
*.txt
263+
264+
# vscode
265+
.vscode/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace MineCase.Algorithm
5+
{
6+
public class MathHelper
7+
{
8+
public static float DenormalizeClamp(float min, float max, float value)
9+
{
10+
if (value < 0)
11+
{
12+
return min;
13+
}
14+
else if (value > 1)
15+
{
16+
return max;
17+
}
18+
else
19+
{
20+
return min + (max - min) * value;
21+
}
22+
}
23+
}
24+
}

src/MineCase.Algorithm/Noise/OctavedNoise.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void Noise(float[,,] noise, Vector3 offset, Vector3 scale)
4646

4747
for (int i = 0; i < _octaves; i++)
4848
{
49-
_innerNoise.AddNoise(noise, offset * frequency, scale * frequency, (float)amplitude);
49+
_innerNoise.AddNoise(noise, Vector3.Multiply(offset, scale) * frequency, scale * frequency, (float)amplitude);
5050
maxValue += amplitude;
5151
amplitude *= _persistence;
5252
frequency *= 2;

src/MineCase.Algorithm/Noise/PerlinNoise.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,4 @@ public static float Grad(int hash, float x, float y, float z)
233233
public static float Lerp(float a, float b, float x) =>
234234
a + x * (b - a);
235235
}
236-
}
236+
}

src/MineCase.Server.Grains/MineCase.Server.Grains.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
<PackageReference Include="Microsoft.Orleans.Core" Version="2.0.0-preview2-20170724" />
1515
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004" PrivateAssets="All" />
1616
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
17+
<PackageReference Include="System.Numerics.Vectors" Version="4.4.0" />
1718
</ItemGroup>
1819

1920
<ItemGroup>
21+
<ProjectReference Include="..\MineCase.Algorithm\MineCase.Algorithm.csproj" />
2022
<ProjectReference Include="..\MineCase.Protocol\MineCase.Protocol.csproj" />
2123
<ProjectReference Include="..\MineCase.Server.Interfaces\MineCase.Server.Interfaces.csproj" />
2224
</ItemGroup>

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

Lines changed: 11 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -124,56 +124,8 @@ public Task SendChatMessage(Chat jsonData, Byte position)
124124
});
125125
}
126126

127-
public Task ChunkData(Dimension dimension, int chunkX, int chunkZ, ChunkColumn chunkColumn)
127+
public Task ChunkData(Dimension dimension, int chunkX, int chunkZ, ChunkColumnStorage chunkColumn)
128128
{
129-
ulong[] CompactBlockIds(Block[] blocks)
130-
{
131-
var result = new ulong[16 * 16 * 16 * 13 / 64];
132-
int byteIndex = 0;
133-
int bitIndex = 0;
134-
foreach (var block in blocks)
135-
{
136-
ulong id = (block.Id << 4) | (block.MetaValue & 0b1111);
137-
var availBits = 64 - bitIndex;
138-
var bitsToWrite = Math.Min(13, availBits);
139-
var shiftBits = 13 - bitsToWrite;
140-
result[byteIndex] |= id << bitIndex;
141-
bitIndex += bitsToWrite;
142-
if (bitIndex == 64)
143-
{
144-
byteIndex++;
145-
bitIndex = 0;
146-
}
147-
148-
if (shiftBits > 0)
149-
{
150-
bitsToWrite = shiftBits;
151-
result[byteIndex] = id >> (13 - shiftBits);
152-
bitIndex += bitsToWrite;
153-
}
154-
155-
if (bitIndex == 64)
156-
{
157-
byteIndex++;
158-
bitIndex = 0;
159-
}
160-
}
161-
162-
return result;
163-
}
164-
165-
Protocol.Play.ChunkSection ToChunkSection(World.ChunkSection chunkSection)
166-
{
167-
return new Protocol.Play.ChunkSection
168-
{
169-
BitsPerBlock = chunkSection.BitsPerBlock,
170-
PaletteLength = 0,
171-
BlockLight = CompactBy2(chunkSection.Blocks.Select(o => o.BlockLight).ToArray()),
172-
SkyLight = dimension == Dimension.Overworld ? CompactBy2(chunkSection.Blocks.Select(o => o.SkyLight).ToArray()) : null,
173-
DataArray = CompactBlockIds(chunkSection.Blocks)
174-
};
175-
}
176-
177129
return Sink.SendPacket(new ChunkData
178130
{
179131
ChunkX = chunkX,
@@ -182,19 +134,19 @@ Protocol.Play.ChunkSection ToChunkSection(World.ChunkSection chunkSection)
182134
Biomes = chunkColumn.Biomes,
183135
PrimaryBitMask = chunkColumn.SectionBitMask,
184136
NumberOfBlockEntities = 0,
185-
Data = (from s in chunkColumn.Sections select ToChunkSection(s)).ToArray()
137+
Data = (from c in chunkColumn.Sections
138+
where c != null
139+
select new Protocol.Play.ChunkSection
140+
{
141+
PaletteLength = 0,
142+
BitsPerBlock = c.BitsPerBlock,
143+
SkyLight = c.SkyLight.Storage,
144+
BlockLight = c.BlockLight.Storage,
145+
DataArray = c.Data.Storage
146+
}).ToArray()
186147
});
187148
}
188149

189-
private static byte[] CompactBy2(byte[] source)
190-
{
191-
if (source.Length % 2 != 0) throw new ArgumentException("source array's length must be even.");
192-
var result = new byte[source.Length / 2];
193-
for (int i = 0; i < result.Length; i++)
194-
result[i] = (byte)(source[i * 2] | (source[i * 2 + 1] << 4));
195-
return result;
196-
}
197-
198150
public Task SendPacket(uint packetId, byte[] data)
199151
{
200152
return Sink.SendPacket(packetId, data.AsImmutable());

src/MineCase.Server.Grains/User/UserGrain.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ public async Task JoinGame()
8686
_sendKeepAliveTimer = RegisterTimer(OnSendKeepAliveRequests, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
8787

8888
// _worldTimeSyncTimer = RegisterTimer(OnSyncWorldTime, null, TimeSpan.Zero, )
89+
90+
// 设置出生点
91+
await _player.SetPosition(0, 200, 0, false);
8992
}
9093

9194
private async Task SendTimeUpdate()

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

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Text;
55
using System.Threading.Tasks;
6+
using MineCase.Server.World.Generation;
67
using Orleans;
78

89
namespace MineCase.Server.World
@@ -13,53 +14,85 @@ internal class ChunkColumnGrain : Grain, IChunkColumn
1314
private int _chunkX;
1415
private int _chunkZ;
1516

16-
public Task<ChunkColumn> GetState()
17+
private ChunkColumnStorage _state;
18+
19+
public Task<ChunkColumnStorage> GetState() => Task.FromResult(_state);
20+
/*
21+
var generator = GrainFactory.GetGrain<IChunkGeneratorOverworld>(1);
22+
GeneratorSettings settings = new GeneratorSettings
23+
{
24+
Seed = 1,
25+
};
26+
ChunkColumn chunkColumn = await generator.Generate(_chunkX, _chunkZ, settings);
27+
return chunkColumn;
28+
*/
29+
30+
/*
31+
var blocks = new Block[16 * 16 * 16];
32+
var index = 0;
33+
for (int y = 0; y < 16; y++)
1734
{
18-
var blocks = new Block[16 * 16 * 16];
19-
var index = 0;
20-
for (int y = 0; y < 16; y++)
35+
for (int x = 0; x < 16; x++)
2136
{
22-
for (int x = 0; x < 16; x++)
37+
for (int z = 0; z < 16; z++)
2338
{
24-
for (int z = 0; z < 16; z++)
25-
{
26-
if (y == 0)
27-
blocks[index] = new Block { Id = 1, SkyLight = 0xF };
28-
else
29-
blocks[index] = new Block { Id = 0, SkyLight = 0xF };
30-
index++;
31-
}
39+
if (y == 0)
40+
blocks[index] = new Block { Id = 1, SkyLight = 0xF };
41+
else
42+
blocks[index] = new Block { Id = 0, SkyLight = 0xF };
43+
index++;
3244
}
3345
}
46+
}
3447
35-
return Task.FromResult(new ChunkColumn
48+
return Task.FromResult(new ChunkColumn
49+
{
50+
Biomes = Enumerable.Repeat<byte>(0, 256).ToArray(),
51+
SectionBitMask = 0b1111_1111_1111_1111,
52+
Sections = new[]
3653
{
37-
Biomes = Enumerable.Repeat<byte>(0, 256).ToArray(),
38-
SectionBitMask = 0b1111_1111_1111_1111,
39-
Sections = new[]
54+
new ChunkSection
4055
{
41-
new ChunkSection
42-
{
43-
BitsPerBlock = 13,
44-
Blocks = blocks
45-
}
46-
}.Concat(Enumerable.Repeat(
47-
new ChunkSection
48-
{
49-
BitsPerBlock = 13,
50-
Blocks = Enumerable.Repeat(new Block { Id = 0, SkyLight = 0xF }, 16 * 16 * 16).ToArray()
51-
}, 15)).ToArray()
52-
});
53-
}
56+
BitsPerBlock = 13,
57+
Blocks = blocks
58+
}
59+
}.Concat(Enumerable.Repeat(
60+
new ChunkSection
61+
{
62+
BitsPerBlock = 13,
63+
Blocks = Enumerable.Repeat(new Block { Id = 0, SkyLight = 0xF }, 16 * 16 * 16).ToArray()
64+
}, 15)).ToArray()
65+
});
66+
*/
5467

55-
public override Task OnActivateAsync()
68+
public override async Task OnActivateAsync()
5669
{
5770
var key = this.GetWorldAndChunkPosition();
5871
_world = GrainFactory.GetGrain<IWorld>(key.worldKey);
5972
_chunkX = key.x;
6073
_chunkZ = key.z;
6174

62-
return base.OnActivateAsync();
75+
await EnsureChunkGenerated();
76+
}
77+
78+
private async Task EnsureChunkGenerated()
79+
{
80+
/*
81+
var generator = GrainFactory.GetGrain<IChunkGeneratorFlat>(1);
82+
GeneratorSettings settings = new GeneratorSettings
83+
{
84+
FlatGeneratorInfo = new FlatGeneratorInfo
85+
{
86+
FlatBlockId = new BlockState?[] { BlockStates.Stone(), BlockStates.Dirt(), BlockStates.Grass() }
87+
}
88+
};
89+
_state = await generator.Generate(_chunkX, _chunkZ, settings);
90+
*/
91+
var generator = GrainFactory.GetGrain<IChunkGeneratorOverworld>(1);
92+
GeneratorSettings settings = new GeneratorSettings
93+
{
94+
};
95+
_state = await generator.Generate(_chunkX, _chunkZ, settings);
6396
}
6497
}
6598
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using Microsoft.Extensions.Logging;
5+
using MineCase.Server.World.Biomes;
6+
using MineCase.Server.World.Layer;
7+
using Newtonsoft.Json;
8+
using Orleans;
9+
using Orleans.Concurrency;
10+
using Orleans.Runtime;
11+
12+
namespace MineCase.Server.World.Generation
13+
{
14+
[StatelessWorker]
15+
internal class BiomeGeneratorFlatGrain : Grain, IBiomeGenerator
16+
{
17+
// private GenLayer _genBiomes;
18+
// private GenLayer _biomeIndexLayer;
19+
20+
// private int _seed;
21+
22+
/*
23+
public override Task OnActivateAsync()
24+
{
25+
_seed = (int)this.GetPrimaryKeyLong();
26+
GenLayer[] agenlayer = GenLayer.initializeAllBiomeGenerators(_seed, worldTypeIn, settings);
27+
agenlayer = getModdedBiomeGenerators(worldTypeIn, seed, agenlayer);
28+
_genBiomes = agenlayer[0];
29+
_biomeIndexLayer = agenlayer[1];
30+
return Task.CompletedTask;
31+
}
32+
33+
/// <summary>
34+
/// Returns an array of biomes for the location input.
35+
/// </summary>
36+
public void GetBiomesForGeneration(Biome[] biomes, int x, int z, int width, int height)
37+
{
38+
if (biomes == null || biomes.Length < width * height)
39+
{
40+
biomes = new Biome[width * height];
41+
}
42+
43+
int[] aint = _genBiomes.getInts(x, z, width, height);
44+
45+
for (int i = 0; i < width * height; ++i)
46+
{
47+
biomes[i] = Biome.GetBiome(aint[i]);
48+
}
49+
}
50+
*/
51+
}
52+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using System.IO;
3+
using System.Threading.Tasks;
4+
using Microsoft.Extensions.Logging;
5+
using Newtonsoft.Json;
6+
using Orleans;
7+
using Orleans.Concurrency;
8+
using Orleans.Runtime;
9+
10+
namespace MineCase.Server.World.Generation
11+
{
12+
[StatelessWorker]
13+
internal class ChunkGeneratorFlatGrain : Grain, IChunkGeneratorFlat
14+
{
15+
public Task<ChunkColumnStorage> Generate(int x, int z, GeneratorSettings settings)
16+
{
17+
var chunkColumn = new ChunkColumnStorage();
18+
for (int i = 0; i < chunkColumn.Sections.Length; ++i)
19+
chunkColumn.Sections[i] = new ChunkSectionStorage(true);
20+
21+
GenerateChunk(chunkColumn, x, z, settings);
22+
PopulateChunk(chunkColumn, x, z, settings);
23+
return Task.FromResult(chunkColumn);
24+
}
25+
26+
private void GenerateChunk(ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
27+
{
28+
// 按照flat模式每层的设置给chunk赋值
29+
for (int y = 0; y < settings.FlatGeneratorInfo.FlatBlockId.Length; ++y)
30+
{
31+
var section = chunk.Sections[y / 16];
32+
var state = settings.FlatGeneratorInfo.FlatBlockId[y];
33+
if (state != null)
34+
{
35+
for (int j = 0; j < 16; ++j)
36+
{
37+
for (int k = 0; k < 16; ++k)
38+
section.Data[j, y % 16, k] = new BlockState { Id = state.Value.Id, MetaValue = state.Value.MetaValue };
39+
}
40+
}
41+
42+
for (int i = 0; i < section.SkyLight.Storage.Length; i++)
43+
section.SkyLight.Storage[i] = 0xFF;
44+
}
45+
46+
// todo biomes
47+
}
48+
49+
private void PopulateChunk(ChunkColumnStorage chunk, int x, int z, GeneratorSettings settings)
50+
{
51+
// TODO generator tree, grass, structures\
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)