Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix/freakingpartialchunksagain #349

Merged
merged 6 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Obsidian.API/_Enums/ChunkStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Obsidian.API;
public enum ChunkStatus
{
empty,
structure_starts,
structure_references,
biomes,
noise,
surface,
carvers,
liquid_carvers,
features,
light,
spawn,
heightmaps,
full
}
2 changes: 1 addition & 1 deletion Obsidian/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ await QueuePacketAsync(new LoginSuccess(Player.Uuid, Player.Username)

await SendPlayerListDecoration();
await SendPlayerInfoAsync();
await Player.UpdateChunksAsync(distance: 2);
await Player.UpdateChunksAsync(distance: 7);
await SendInfoAsync();
await Server.Events.InvokePlayerJoinAsync(new PlayerJoinEventArgs(Player, DateTimeOffset.Now));
}
Expand Down
4 changes: 2 additions & 2 deletions Obsidian/Entities/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public async Task UpdatePositionAsync(VectorF pos, bool onGround = true)
{
var (x, z) = pos.ToChunkCoord();
var chunk = await this.World.GetChunkAsync(x, z, false);
if (chunk != null && chunk.isGenerated)
if (chunk != null && chunk.IsGenerated)
{
this.Position = pos;
}
Expand All @@ -184,7 +184,7 @@ public async Task UpdatePositionAsync(VectorF pos, Angle yaw, Angle pitch, bool
var (x, z) = pos.ToChunkCoord();
var chunk = await this.World.GetChunkAsync(x, z, false);

if (chunk != null && chunk.isGenerated)
if (chunk != null && chunk.IsGenerated)
{
this.Position = pos;
}
Expand Down
8 changes: 4 additions & 4 deletions Obsidian/Entities/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -956,8 +956,8 @@ internal async Task UpdateChunksAsync(bool unloadAll = false, int distance = 0)

(int playerChunkX, int playerChunkZ) = Position.ToChunkCoord();
(int lastPlayerChunkX, int lastPlayerChunkZ) = LastPosition.ToChunkCoord();

int dist = distance < 1? ((client.ClientSettings?.ViewDistance ?? 14) - 2) : 2;
int dist = distance < 1 ? client.ClientSettings?.ViewDistance ?? 7 : distance;
for (int x = playerChunkX + dist; x > playerChunkX - dist; x--)
for (int z = playerChunkZ + dist; z > playerChunkZ - dist; z--)
clientNeededChunks.Add((x, z));
Expand All @@ -978,10 +978,10 @@ internal async Task UpdateChunksAsync(bool unloadAll = false, int distance = 0)
client.LoadedChunks.TryRemove(chunkLoc);
});

await Parallel.ForEachAsync(clientNeededChunks.Take(100), async (chunkLoc, _) =>
await Parallel.ForEachAsync(clientNeededChunks, async (chunkLoc, _) =>
{
var chunk = await World.GetChunkAsync(chunkLoc.X, chunkLoc.Z);
if (chunk is not null && chunk.isGenerated)
if (chunk is not null && chunk.IsGenerated)
{
await client.SendChunkAsync(chunk);
client.LoadedChunks.Add((chunk.X, chunk.Z));
Expand Down
2 changes: 1 addition & 1 deletion Obsidian/Net/Packets/Play/Serverbound/SwingArmPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class SwingArmPacket : IServerboundPacket

public async ValueTask HandleAsync(Server server, Player player)
{
var entities = player.GetEntitiesNear(player.client.ClientSettings.ViewDistance);
var entities = player.GetEntitiesNear(player.client.ClientSettings?.ViewDistance ?? 8);
foreach (var otherEntity in entities)
{
if (otherEntity is not Player otherPlayer)
Expand Down
12 changes: 7 additions & 5 deletions Obsidian/WorldData/Chunk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ public class Chunk
public int X { get; }
public int Z { get; }

public bool isGenerated = false;
public bool IsGenerated => chunkStatus == ChunkStatus.full;

public ChunkStatus chunkStatus = ChunkStatus.empty;

private const int width = 16;
private const int worldHeight = 320;
Expand Down Expand Up @@ -44,15 +46,13 @@ public Chunk(int x, int z)
}
}

private Chunk(int x, int z, ChunkSection[] sections, Dictionary<HeightmapType, Heightmap> heightmaps, bool isGenerated)
private Chunk(int x, int z, ChunkSection[] sections, Dictionary<HeightmapType, Heightmap> heightmaps)
{
X = x;
Z = z;

Heightmaps = heightmaps;
Sections = sections;

this.isGenerated = isGenerated;
}

public IBlock GetBlock(Vector position) => GetBlock(position.X, position.Y, position.Z);
Expand Down Expand Up @@ -280,13 +280,15 @@ public Chunk Clone(int x, int z)

var heightmaps = new Dictionary<HeightmapType, Heightmap>();

var chunk = new Chunk(x, z, sections, heightmaps, isGenerated);
var chunk = new Chunk(x, z, sections, heightmaps);

foreach (var (type, heightmap) in Heightmaps)
{
heightmaps.Add(type, heightmap.Clone(chunk));
}

chunk.chunkStatus = chunkStatus;

return chunk;
}

Expand Down
6 changes: 3 additions & 3 deletions Obsidian/WorldData/Generators/EmptyWorldGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ static EmptyWorldGenerator()
}
}

empty.isGenerated = true;
spawn.isGenerated = true;
empty.chunkStatus = ChunkStatus.full;
spawn.chunkStatus = ChunkStatus.full;
}

public async Task<Chunk> GenerateChunkAsync(int x, int z, Chunk? chunk = null)
{
if (chunk is { isGenerated: true })
if (chunk is { IsGenerated: true })
return chunk;

if (x == 0 && z == 0)
Expand Down
4 changes: 2 additions & 2 deletions Obsidian/WorldData/Generators/OverworldGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public async Task<Chunk> GenerateChunkAsync(int cx, int cz, Chunk? chunk = null)
chunk ??= new Chunk(cx, cz);

// Sanity checks
if (chunk.isGenerated)
if (chunk.IsGenerated)
return chunk;
if (helper is null)
throw new NullReferenceException("GenHelper must not be null. Call Init()");
Expand Down Expand Up @@ -97,7 +97,7 @@ public async Task<Chunk> GenerateChunkAsync(int cx, int cz, Chunk? chunk = null)
//ChunkBuilder.CarveCaves(helper, chunk);
await OverworldDecorator.DecorateAsync(chunk, helper);

chunk.isGenerated = true;
chunk.chunkStatus = ChunkStatus.full;
return chunk;
}

Expand Down
4 changes: 2 additions & 2 deletions Obsidian/WorldData/Generators/SuperflatGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ static SuperflatGenerator()
}
}

model.isGenerated = true;
model.chunkStatus = ChunkStatus.full;
}

public async Task<Chunk> GenerateChunkAsync(int x, int z, Chunk? chunk = null)
{
if (chunk is { isGenerated: true })
if (chunk is { IsGenerated: true })
return chunk;

return model.Clone(x, z);
Expand Down
17 changes: 11 additions & 6 deletions Obsidian/WorldData/Region.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Obsidian.ChunkData;
using Obsidian.Blocks;
using Obsidian.ChunkData;
using Obsidian.Entities;
using Obsidian.Nbt;
using Obsidian.Registries;
Expand All @@ -23,7 +24,7 @@ public class Region : IAsyncDisposable

public ConcurrentDictionary<int, Entity> Entities { get; } = new();

public int LoadedChunkCount => loadedChunks.Count(c => c.isGenerated);
public int LoadedChunkCount => loadedChunks.Count(c => c.IsGenerated);

private DenseCollection<Chunk> loadedChunks { get; } = new(cubicRegionSize, cubicRegionSize);

Expand Down Expand Up @@ -62,18 +63,20 @@ internal async Task FlushAsync()

internal async ValueTask<Chunk> GetChunkAsync(int x, int z)
{
(x, z) = (NumericsHelper.Modulo(x, cubicRegionSize), NumericsHelper.Modulo(z, cubicRegionSize));
var chunk = loadedChunks[x, z];
if (chunk is null)
{
chunk = await GetChunkFromFileAsync(x, z); // Still might be null but that's okay.
loadedChunks[x, z] = chunk;
loadedChunks[x, z] = chunk!;
}

return chunk;
return chunk!;
}

internal async Task UnloadChunk(int x, int z)
{
(x, z) = (NumericsHelper.Modulo(x, cubicRegionSize), NumericsHelper.Modulo(z, cubicRegionSize));
var chunk = loadedChunks[x, z];
if (chunk is null) { return; }
await SerializeChunkAsync(chunk);
Expand All @@ -97,7 +100,7 @@ internal IEnumerable<Chunk> GeneratedChunks()
{
foreach (var c in loadedChunks)
{
if (c is not null && c.isGenerated)
if (c is not null && c.IsGenerated)
{
yield return c;
}
Expand Down Expand Up @@ -241,7 +244,7 @@ private static Chunk DeserializeChunk(NbtCompound chunkCompound)
chunk.SetBlockEntity(tileEntityCompound.GetInt("x"), tileEntityCompound.GetInt("y"), tileEntityCompound.GetInt("z"), tileEntityCompound);
}

chunk.isGenerated = !chunk.Sections.All(c => c.IsEmpty);
chunk.chunkStatus = (ChunkStatus)(Enum.TryParse(typeof(ChunkStatus), chunkCompound.GetString("Status"), out var status) ? status : ChunkStatus.empty);

return chunk;
}
Expand Down Expand Up @@ -313,6 +316,8 @@ private static NbtCompound SerializeChunk(Chunk chunk)
{
new NbtTag<int>("xPos", chunk.X),
new NbtTag<int>("zPos", chunk.Z),
new NbtTag<int>("yPos", -4),
new NbtTag<string>("Status", chunk.chunkStatus.ToString()),
new NbtCompound("Heightmaps")
{
new NbtArray<long>("MOTION_BLOCKING", chunk.Heightmaps[HeightmapType.MotionBlocking].data.storage),
Expand Down
10 changes: 4 additions & 6 deletions Obsidian/WorldData/RegionFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ public async Task SetChunkAsync(int x, int z, byte[] bytes, NbtCompression compr

var (offset, size) = this.GetLocation(tableIndex);

this.ResetPosition();

if (offset == 0 && size == 0)
{
await this.WriteNewChunkAsync(bytes, chunkSectionSize, tableIndex);
Expand All @@ -101,10 +103,6 @@ public async Task SetChunkAsync(int x, int z, byte[] bytes, NbtCompression compr
return;
}

this.ResetPosition();

this.regionFileStream.Position = offset;

using var mem = new RentedArray<byte>(size);

if (chunkSectionSize * sectionSize > size)// gotta allocate new sector now
Expand Down Expand Up @@ -133,7 +131,7 @@ public async Task SetChunkAsync(int x, int z, byte[] bytes, NbtCompression compr
mem.Span[4] = (byte)compression;

bytes.CopyTo(mem.Span[5..]);

this.regionFileStream.Position = offset;
await this.regionFileStream.WriteAsync(mem);

this.semaphore.Release();
Expand Down Expand Up @@ -213,7 +211,7 @@ private async Task WriteChunkHeaderAsync(int length, byte compression)
this.Timestamps[tableIndex] = time;

private void SetLocation(int tableIndex, int offset, int size) =>
this.Locations[tableIndex] = (offset << 8) | (size & 0xFF);
this.Locations[tableIndex] = ((offset + 2) << 8) | (size & 0xFF);

private int CalculateChunkSize(long length) =>
(int)Math.Ceiling((length + 5) / (double)sectionSize);
Expand Down
8 changes: 4 additions & 4 deletions Obsidian/WorldData/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public async Task<bool> DestroyEntityAsync(Entity entity)

if (chunk is not null)
{
if (!chunk.isGenerated && scheduleGeneration)
if (!chunk.IsGenerated && scheduleGeneration)
{
if (!ChunksToGen.Contains((chunkX, chunkZ)))
ChunksToGen.Enqueue((chunkX, chunkZ));
Expand All @@ -139,7 +139,7 @@ public async Task<bool> DestroyEntityAsync(Entity entity)
// Create a partial chunk.
chunk = new Chunk(chunkX, chunkZ)
{
isGenerated = false // Not necessary; just being explicit.
chunkStatus = ChunkStatus.structure_starts
};
region.SetChunk(chunk);
return chunk;
Expand Down Expand Up @@ -503,12 +503,12 @@ public async Task ManageChunksAsync()
{
c = new Chunk(job.x, job.z)
{
isGenerated = false // Not necessary; just being explicit.
chunkStatus = ChunkStatus.structure_starts
};
// Set chunk now so that it no longer comes back as null. #threadlyfe
region.SetChunk(c);
}
if (!c.isGenerated)
if (!c.IsGenerated)
{
c = await Generator.GenerateChunkAsync(job.x, job.z, c);
await worldLight.ProcessSkyLightForChunk(c);
Expand Down
2 changes: 1 addition & 1 deletion Obsidian/WorldData/WorldLight.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public async Task ProcessSkyLightForChunk(Chunk chunk)
public async Task SetLightAndSpread(Vector pos, LightType lt, int level, Chunk chunk)
{
if (chunk is null) { return; }
if (!chunk.isGenerated) { return; }
if (!chunk.IsGenerated) { return; }

int curLevel = chunk.GetLightLevel(pos, lt);
if (level <= curLevel) { return; }
Expand Down
Loading