Refactor how block entity unloading works and unloading things on the client side (#1475)

extracted from #1446
This commit is contained in:
IntegratedQuantum 2025-05-21 20:42:17 +02:00 committed by GitHub
parent a4809555e9
commit c852393076
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 42 additions and 12 deletions

View File

@ -18,9 +18,9 @@ pub const BlockEntityType = struct {
const VTable = struct {
onLoadClient: *const fn(pos: Vec3i, chunk: *Chunk) void,
onUnloadClient: *const fn(pos: Vec3i, chunk: *Chunk) void,
onUnloadClient: *const fn(dataIndex: BlockEntityIndex) void,
onLoadServer: *const fn(pos: Vec3i, chunk: *Chunk) void,
onUnloadServer: *const fn(pos: Vec3i, chunk: *Chunk) void,
onUnloadServer: *const fn(dataIndex: BlockEntityIndex) void,
onPlaceClient: *const fn(pos: Vec3i, chunk: *Chunk) void,
onBreakClient: *const fn(pos: Vec3i, chunk: *Chunk) void,
onPlaceServer: *const fn(pos: Vec3i, chunk: *Chunk) void,
@ -45,14 +45,14 @@ pub const BlockEntityType = struct {
pub inline fn onLoadClient(self: *BlockEntityType, pos: Vec3i, chunk: *Chunk) void {
return self.vtable.onLoadClient(pos, chunk);
}
pub inline fn onUnloadClient(self: *BlockEntityType, pos: Vec3i, chunk: *Chunk) void {
return self.vtable.onUnloadClient(pos, chunk);
pub inline fn onUnloadClient(self: *BlockEntityType, dataIndex: BlockEntityIndex) void {
return self.vtable.onUnloadClient(dataIndex);
}
pub inline fn onLoadServer(self: *BlockEntityType, pos: Vec3i, chunk: *Chunk) void {
return self.vtable.onLoadServer(pos, chunk);
}
pub inline fn onUnloadServer(self: *BlockEntityType, pos: Vec3i, chunk: *Chunk) void {
return self.vtable.onUnloadServer(pos, chunk);
pub inline fn onUnloadServer(self: *BlockEntityType, dataIndex: BlockEntityIndex) void {
return self.vtable.onUnloadServer(dataIndex);
}
pub inline fn onPlaceClient(self: *BlockEntityType, pos: Vec3i, chunk: *Chunk) void {
return self.vtable.onPlaceClient(pos, chunk);
@ -117,6 +117,13 @@ fn BlockEntityDataStorage(T: type) type {
chunk.blockPosToEntityDataMap.put(main.globalAllocator.allocator, blockIndex, @intCast(dataIndex)) catch unreachable;
chunk.blockPosToEntityDataMapMutex.unlock();
}
pub fn removeAtIndex(dataIndex: BlockEntityIndex) void {
main.utils.assertLocked(&mutex);
freeIndexList.append(main.globalAllocator, dataIndex);
storage.remove(dataIndex) catch |err| {
std.log.err("Error while removing block entity: {s}", .{@errorName(err)});
};
}
pub fn remove(pos: Vec3i, chunk: *Chunk) void {
mutex.lock();
defer mutex.unlock();
@ -133,10 +140,7 @@ fn BlockEntityDataStorage(T: type) type {
};
const dataIndex = entry.value;
freeIndexList.append(main.globalAllocator, dataIndex);
storage.remove(dataIndex) catch |err| {
std.log.err("Error while remvoing block entity at position {}: {s}", .{pos, @errorName(err)});
};
removeAtIndex(dataIndex);
}
pub fn get(pos: Vec3i, chunk: *Chunk) ?*DataT {
main.utils.assertLocked(&mutex);
@ -175,9 +179,13 @@ pub const BlockEntityTypes = struct {
}
pub fn onLoadClient(_: Vec3i, _: *Chunk) void {}
pub fn onUnloadClient(_: Vec3i, _: *Chunk) void {}
pub fn onUnloadClient(_: BlockEntityIndex) void {}
pub fn onLoadServer(_: Vec3i, _: *Chunk) void {}
pub fn onUnloadServer(_: Vec3i, _: *Chunk) void {}
pub fn onUnloadServer(dataIndex: BlockEntityIndex) void {
StorageServer.mutex.lock();
defer StorageServer.mutex.unlock();
StorageServer.removeAtIndex(dataIndex);
}
pub fn onPlaceClient(_: Vec3i, _: *Chunk) void {}
pub fn onBreakClient(_: Vec3i, _: *Chunk) void {}
pub fn onPlaceServer(_: Vec3i, _: *Chunk) void {}

View File

@ -284,6 +284,27 @@ pub const Chunk = struct { // MARK: Chunk
memoryPool.destroy(@alignCast(self));
}
pub fn unloadBlockEntities(self: *Chunk, comptime side: main.utils.Side) void {
self.blockPosToEntityDataMapMutex.lock();
defer self.blockPosToEntityDataMapMutex.unlock();
var iterator = self.blockPosToEntityDataMap.iterator();
while(iterator.next()) |elem| {
const index = elem.key_ptr.*;
const entityDataIndex = elem.value_ptr.*;
const block = self.data.getValue(index);
const blockEntity = block.blockEntity() orelse unreachable;
switch(side) {
.client => {
blockEntity.onUnloadClient(entityDataIndex);
},
.server => {
blockEntity.onUnloadServer(entityDataIndex);
},
}
}
self.blockPosToEntityDataMap.clearRetainingCapacity();
}
/// Updates a block if it is inside this chunk.
/// Does not do any bound checks. They are expected to be done with the `liesInChunk` function.
pub fn updateBlock(self: *Chunk, _x: i32, _y: i32, _z: i32, newBlock: Block) void {

View File

@ -694,6 +694,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
chunkBuffer.free(self.chunkAllocation);
self.opaqueMesh.deinit();
self.transparentMesh.deinit();
self.chunk.unloadBlockEntities(.client);
self.chunk.deinit();
main.globalAllocator.free(self.currentSorting);
main.globalAllocator.free(self.sortingOutputBuffer);