mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Use a SparseSet in BlockEntity data, instead of manually managing a dense list. (#1470)
fixes #1453
This commit is contained in:
parent
2e705d9cc9
commit
a4809555e9
@ -1,7 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const main = @import("main.zig");
|
const main = @import("main.zig");
|
||||||
const List = main.List;
|
|
||||||
const Vec3i = main.vec.Vec3i;
|
const Vec3i = main.vec.Vec3i;
|
||||||
const Block = main.blocks.Block;
|
const Block = main.blocks.Block;
|
||||||
const Chunk = main.chunk.Chunk;
|
const Chunk = main.chunk.Chunk;
|
||||||
@ -11,7 +10,7 @@ const server = main.server;
|
|||||||
const User = server.User;
|
const User = server.User;
|
||||||
const mesh_storage = main.renderer.mesh_storage;
|
const mesh_storage = main.renderer.mesh_storage;
|
||||||
|
|
||||||
pub const BlockEntityIndex = u32;
|
pub const BlockEntityIndex = main.utils.DenseId(u32);
|
||||||
|
|
||||||
pub const BlockEntityType = struct {
|
pub const BlockEntityType = struct {
|
||||||
id: []const u8,
|
id: []const u8,
|
||||||
@ -77,31 +76,40 @@ pub const EventStatus = enum {
|
|||||||
ignored,
|
ignored,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn BlockEntityDataStorage(comptime side: enum {client, server}, T: type) type {
|
fn BlockEntityDataStorage(T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
pub const DataT = T;
|
pub const DataT = T;
|
||||||
pub const EntryT = struct {
|
pub const EntryT = struct {
|
||||||
absoluteBlockPosition: Vec3i,
|
absoluteBlockPosition: Vec3i,
|
||||||
data: DataT,
|
data: DataT,
|
||||||
};
|
};
|
||||||
var storage: List(EntryT) = undefined;
|
var freeIndexList: main.ListUnmanaged(BlockEntityIndex) = .{};
|
||||||
|
var nextIndex: BlockEntityIndex = @enumFromInt(0);
|
||||||
|
var storage: main.utils.SparseSet(EntryT, BlockEntityIndex) = .{};
|
||||||
pub var mutex: std.Thread.Mutex = .{};
|
pub var mutex: std.Thread.Mutex = .{};
|
||||||
|
|
||||||
pub fn init() void {
|
pub fn init() void {
|
||||||
storage = .init(main.globalAllocator);
|
storage = .{};
|
||||||
|
freeIndexList = .{};
|
||||||
}
|
}
|
||||||
pub fn deinit() void {
|
pub fn deinit() void {
|
||||||
storage.deinit();
|
storage.deinit(main.globalAllocator);
|
||||||
|
freeIndexList.deinit(main.globalAllocator);
|
||||||
|
nextIndex = @enumFromInt(0);
|
||||||
}
|
}
|
||||||
pub fn reset() void {
|
pub fn reset() void {
|
||||||
storage.clearRetainingCapacity();
|
storage.clear();
|
||||||
|
freeIndexList.clearRetainingCapacity();
|
||||||
}
|
}
|
||||||
pub fn add(pos: Vec3i, value: DataT, chunk: *Chunk) void {
|
pub fn add(pos: Vec3i, value: DataT, chunk: *Chunk) void {
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
defer mutex.unlock();
|
defer mutex.unlock();
|
||||||
|
|
||||||
const dataIndex = storage.items.len;
|
const dataIndex: BlockEntityIndex = freeIndexList.popOrNull() orelse blk: {
|
||||||
storage.append(.{.absoluteBlockPosition = pos, .data = value});
|
defer nextIndex = @enumFromInt(@intFromEnum(nextIndex) + 1);
|
||||||
|
break :blk nextIndex;
|
||||||
|
};
|
||||||
|
storage.set(main.globalAllocator, dataIndex, value);
|
||||||
|
|
||||||
const blockIndex = chunk.getLocalBlockIndex(pos);
|
const blockIndex = chunk.getLocalBlockIndex(pos);
|
||||||
|
|
||||||
@ -120,41 +128,15 @@ fn BlockEntityDataStorage(comptime side: enum {client, server}, T: type) type {
|
|||||||
chunk.blockPosToEntityDataMapMutex.unlock();
|
chunk.blockPosToEntityDataMapMutex.unlock();
|
||||||
|
|
||||||
const entry = entityNullable orelse {
|
const entry = entityNullable orelse {
|
||||||
std.log.warn("Couldn't remove entity data of block at position {}", .{pos});
|
std.log.err("Couldn't remove entity data of block at position {}", .{pos});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
const dataIndex = entry.value;
|
const dataIndex = entry.value;
|
||||||
_ = storage.swapRemove(dataIndex);
|
freeIndexList.append(main.globalAllocator, dataIndex);
|
||||||
if(dataIndex == storage.items.len) {
|
storage.remove(dataIndex) catch |err| {
|
||||||
return;
|
std.log.err("Error while remvoing block entity at position {}: {s}", .{pos, @errorName(err)});
|
||||||
}
|
};
|
||||||
|
|
||||||
const movedEntry = storage.items[dataIndex];
|
|
||||||
switch(side) {
|
|
||||||
.server => propagateRemoveServer(movedEntry.absoluteBlockPosition, dataIndex),
|
|
||||||
.client => propagateRemoveClient(movedEntry.absoluteBlockPosition, dataIndex),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn propagateRemoveServer(pos: Vec3i, index: BlockEntityIndex) void {
|
|
||||||
const severChunk = server.world.?.getChunkFromCacheAndIncreaseRefCount(ChunkPosition.initFromWorldPos(pos, 1)).?;
|
|
||||||
defer severChunk.decreaseRefCount();
|
|
||||||
|
|
||||||
severChunk.super.blockPosToEntityDataMapMutex.lock();
|
|
||||||
defer severChunk.super.blockPosToEntityDataMapMutex.unlock();
|
|
||||||
|
|
||||||
const otherDataIndex = severChunk.super.getLocalBlockIndex(pos);
|
|
||||||
severChunk.super.blockPosToEntityDataMap.put(main.globalAllocator.allocator, otherDataIndex, index) catch unreachable;
|
|
||||||
}
|
|
||||||
fn propagateRemoveClient(pos: Vec3i, index: BlockEntityIndex) void {
|
|
||||||
const mesh = mesh_storage.getMeshAndIncreaseRefCount(ChunkPosition.initFromWorldPos(pos, 1)).?;
|
|
||||||
defer mesh.decreaseRefCount();
|
|
||||||
|
|
||||||
mesh.chunk.blockPosToEntityDataMapMutex.lock();
|
|
||||||
defer mesh.chunk.blockPosToEntityDataMapMutex.unlock();
|
|
||||||
|
|
||||||
const otherDataIndex = mesh.chunk.getLocalBlockIndex(pos);
|
|
||||||
mesh.chunk.blockPosToEntityDataMap.put(main.globalAllocator.allocator, otherDataIndex, index) catch unreachable;
|
|
||||||
}
|
}
|
||||||
pub fn get(pos: Vec3i, chunk: *Chunk) ?*DataT {
|
pub fn get(pos: Vec3i, chunk: *Chunk) ?*DataT {
|
||||||
main.utils.assertLocked(&mutex);
|
main.utils.assertLocked(&mutex);
|
||||||
@ -176,7 +158,6 @@ fn BlockEntityDataStorage(comptime side: enum {client, server}, T: type) type {
|
|||||||
pub const BlockEntityTypes = struct {
|
pub const BlockEntityTypes = struct {
|
||||||
pub const Chest = struct {
|
pub const Chest = struct {
|
||||||
const StorageServer = BlockEntityDataStorage(
|
const StorageServer = BlockEntityDataStorage(
|
||||||
.server,
|
|
||||||
struct {
|
struct {
|
||||||
id: ?u32,
|
id: ?u32,
|
||||||
},
|
},
|
||||||
|
@ -1927,6 +1927,12 @@ pub fn SparseSet(comptime T: type, comptime IdType: type) type { // MARK: Sparse
|
|||||||
denseToSparseIndex: main.ListUnmanaged(IdType) = .{},
|
denseToSparseIndex: main.ListUnmanaged(IdType) = .{},
|
||||||
sparseToDenseIndex: main.ListUnmanaged(IdType) = .{},
|
sparseToDenseIndex: main.ListUnmanaged(IdType) = .{},
|
||||||
|
|
||||||
|
pub fn clear(self: *Self) void {
|
||||||
|
self.dense.clearRetainingCapacity();
|
||||||
|
self.denseToSparseIndex.clearRetainingCapacity();
|
||||||
|
self.sparseToDenseIndex.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self, allocator: NeverFailingAllocator) void {
|
pub fn deinit(self: *Self, allocator: NeverFailingAllocator) void {
|
||||||
self.dense.deinit(allocator);
|
self.dense.deinit(allocator);
|
||||||
self.denseToSparseIndex.deinit(allocator);
|
self.denseToSparseIndex.deinit(allocator);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user