mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Batch block updates (#1313)
* Batch block updates * Apply review change requests * Allow blockUpdate to carry multiple block updates in single message * Read until there is nothing left * Use mesh_storage.BlockUpdate * Break instead of boolean * Restore client side neighbor updates * Move side check in blockUpdate out of the loop * Update src/utils.zig * Fix minor issues * Reverse ownership logic + change contains into liesInChunk * Update liesInChunk * No name for upadeBlock param * Apply review change requests * Fix formatting * Restore onBreakClient where it should be * Update src/renderer/chunk_meshing.zig * Update src/renderer/chunk_meshing.zig * Converge formatting with master * fix formatting (https://github.com/ziglang/zig-spec/issues/38 is so stupid) --------- Co-authored-by: IntegratedQuantum <jahe788@gmail.com>
This commit is contained in:
parent
e2a65d21d1
commit
64ce0ed991
@ -1654,7 +1654,8 @@ pub const Command = struct { // MARK: Command
|
|||||||
}) {
|
}) {
|
||||||
if(side == .server) {
|
if(side == .server) {
|
||||||
// Inform the client of the actual block:
|
// Inform the client of the actual block:
|
||||||
main.network.Protocols.blockUpdate.send(user.?.conn, self.pos[0], self.pos[1], self.pos[2], main.server.world.?.getBlock(self.pos[0], self.pos[1], self.pos[2]) orelse return);
|
const actualBlock = main.server.world.?.getBlock(self.pos[0], self.pos[1], self.pos[2]) orelse return;
|
||||||
|
main.network.Protocols.blockUpdate.send(user.?.conn, &.{.init(self.pos, actualBlock)});
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1662,7 +1663,7 @@ pub const Command = struct { // MARK: Command
|
|||||||
if(side == .server) {
|
if(side == .server) {
|
||||||
if(main.server.world.?.cmpxchgBlock(self.pos[0], self.pos[1], self.pos[2], self.oldBlock, self.newBlock)) |actualBlock| {
|
if(main.server.world.?.cmpxchgBlock(self.pos[0], self.pos[1], self.pos[2], self.oldBlock, self.newBlock)) |actualBlock| {
|
||||||
// Inform the client of the actual block:
|
// Inform the client of the actual block:
|
||||||
main.network.Protocols.blockUpdate.send(user.?.conn, self.pos[0], self.pos[1], self.pos[2], actualBlock);
|
main.network.Protocols.blockUpdate.send(user.?.conn, &.{.init(self.pos, actualBlock)});
|
||||||
return error.serverFailure;
|
return error.serverFailure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,7 @@ pub fn getIndex(x: i32, y: i32, z: i32) u32 {
|
|||||||
std.debug.assert((x & chunkMask) == x and (y & chunkMask) == y and (z & chunkMask) == z);
|
std.debug.assert((x & chunkMask) == x and (y & chunkMask) == y and (z & chunkMask) == z);
|
||||||
return (@as(u32, @intCast(x)) << chunkShift2) | (@as(u32, @intCast(y)) << chunkShift) | @as(u32, @intCast(z));
|
return (@as(u32, @intCast(x)) << chunkShift2) | (@as(u32, @intCast(y)) << chunkShift) | @as(u32, @intCast(z));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the x coordinate from a given index inside this chunk.
|
/// Gets the x coordinate from a given index inside this chunk.
|
||||||
fn extractXFromIndex(index: usize) i32 {
|
fn extractXFromIndex(index: usize) i32 {
|
||||||
return @intCast(index >> chunkShift2 & chunkMask);
|
return @intCast(index >> chunkShift2 & chunkMask);
|
||||||
@ -303,6 +304,11 @@ pub const Chunk = struct { // MARK: Chunk
|
|||||||
return self.data.getValue(index);
|
return self.data.getValue(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the given relative coordinates lie within the bounds of this chunk.
|
||||||
|
pub fn liesInChunk(self: *const Chunk, x: i32, y: i32, z: i32) bool {
|
||||||
|
return x >= 0 and x < self.width and y >= 0 and y < self.width and z >= 0 and z < self.width;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getLocalBlockIndex(self: *const Chunk, worldPos: Vec3i) u32 {
|
pub fn getLocalBlockIndex(self: *const Chunk, worldPos: Vec3i) u32 {
|
||||||
return getIndex(
|
return getIndex(
|
||||||
(worldPos[0] - self.pos.wx) >> self.voxelSizeShift,
|
(worldPos[0] - self.pos.wx) >> self.voxelSizeShift,
|
||||||
@ -376,7 +382,7 @@ pub const ServerChunk = struct { // MARK: ServerChunk
|
|||||||
|
|
||||||
/// Checks if the given relative coordinates lie within the bounds of this chunk.
|
/// Checks if the given relative coordinates lie within the bounds of this chunk.
|
||||||
pub fn liesInChunk(self: *const ServerChunk, x: i32, y: i32, z: i32) bool {
|
pub fn liesInChunk(self: *const ServerChunk, x: i32, y: i32, z: i32) bool {
|
||||||
return x >= 0 and x < self.super.width and y >= 0 and y < self.super.width and z >= 0 and z < self.super.width;
|
return self.super.liesInChunk(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is useful to convert for loops to work for reduced resolution:
|
/// This is useful to convert for loops to work for reduced resolution:
|
||||||
|
@ -20,6 +20,7 @@ const Vec3d = vec.Vec3d;
|
|||||||
const Vec3f = vec.Vec3f;
|
const Vec3f = vec.Vec3f;
|
||||||
const Vec3i = vec.Vec3i;
|
const Vec3i = vec.Vec3i;
|
||||||
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
|
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
|
||||||
|
const BlockUpdate = renderer.mesh_storage.BlockUpdate;
|
||||||
|
|
||||||
//TODO: Might want to use SSL or something similar to encode the message
|
//TODO: Might want to use SSL or something similar to encode the message
|
||||||
|
|
||||||
@ -943,23 +944,28 @@ pub const Protocols = struct {
|
|||||||
pub const id: u8 = 7;
|
pub const id: u8 = 7;
|
||||||
pub const asynchronous = false;
|
pub const asynchronous = false;
|
||||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||||
const x = try reader.readInt(i32);
|
|
||||||
const y = try reader.readInt(i32);
|
|
||||||
const z = try reader.readInt(i32);
|
|
||||||
const newBlock = Block.fromInt(try reader.readInt(u32));
|
|
||||||
if(conn.isServerSide()) {
|
if(conn.isServerSide()) {
|
||||||
return error.InvalidPacket;
|
return error.InvalidPacket;
|
||||||
} else {
|
}
|
||||||
renderer.mesh_storage.updateBlock(x, y, z, newBlock);
|
while(reader.remaining.len != 0) {
|
||||||
|
renderer.mesh_storage.updateBlock(.{
|
||||||
|
.x = try reader.readInt(i32),
|
||||||
|
.y = try reader.readInt(i32),
|
||||||
|
.z = try reader.readInt(i32),
|
||||||
|
.newBlock = Block.fromInt(try reader.readInt(u32)),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn send(conn: *Connection, x: i32, y: i32, z: i32, newBlock: Block) void {
|
pub fn send(conn: *Connection, updates: []const BlockUpdate) void {
|
||||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 16);
|
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, 16);
|
||||||
defer writer.deinit();
|
defer writer.deinit();
|
||||||
writer.writeInt(i32, x);
|
|
||||||
writer.writeInt(i32, y);
|
for(updates) |update| {
|
||||||
writer.writeInt(i32, z);
|
writer.writeInt(i32, update.x);
|
||||||
writer.writeInt(u32, newBlock.toInt());
|
writer.writeInt(i32, update.y);
|
||||||
|
writer.writeInt(i32, update.z);
|
||||||
|
writer.writeInt(u32, update.newBlock.toInt());
|
||||||
|
}
|
||||||
conn.send(.fast, id, writer.data.items);
|
conn.send(.fast, id, writer.data.items);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1111,7 +1111,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
|
|||||||
.newBlock = newBlock,
|
.newBlock = newBlock,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
mesh_storage.updateBlock(x, y, z, newBlock);
|
mesh_storage.updateBlock(.{.x = x, .y = y, .z = z, .newBlock = newBlock});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drawCube(projectionMatrix: Mat4f, viewMatrix: Mat4f, relativePositionToPlayer: Vec3d, min: Vec3f, max: Vec3f) void {
|
pub fn drawCube(projectionMatrix: Mat4f, viewMatrix: Mat4f, relativePositionToPlayer: Vec3d, min: Vec3f, max: Vec3f) void {
|
||||||
|
@ -1172,9 +1172,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateBlock(self: *ChunkMesh, _x: i32, _y: i32, _z: i32, _newBlock: Block) void {
|
pub fn updateBlock(self: *ChunkMesh, _x: i32, _y: i32, _z: i32, _newBlock: Block, lightRefreshList: *main.List(*ChunkMesh), regenerateMeshList: *main.List(*ChunkMesh)) void {
|
||||||
var lightRefreshList = main.List(*ChunkMesh).init(main.stackAllocator);
|
|
||||||
defer lightRefreshList.deinit();
|
|
||||||
const x: u5 = @intCast(_x & chunk.chunkMask);
|
const x: u5 = @intCast(_x & chunk.chunkMask);
|
||||||
const y: u5 = @intCast(_y & chunk.chunkMask);
|
const y: u5 = @intCast(_y & chunk.chunkMask);
|
||||||
const z: u5 = @intCast(_z & chunk.chunkMask);
|
const z: u5 = @intCast(_z & chunk.chunkMask);
|
||||||
@ -1194,24 +1192,31 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
|
|
||||||
var neighborBlocks: [6]Block = undefined;
|
var neighborBlocks: [6]Block = undefined;
|
||||||
@memset(&neighborBlocks, .{.typ = 0, .data = 0});
|
@memset(&neighborBlocks, .{.typ = 0, .data = 0});
|
||||||
|
|
||||||
for(chunk.Neighbor.iterable) |neighbor| {
|
for(chunk.Neighbor.iterable) |neighbor| {
|
||||||
const nx = x + neighbor.relX();
|
const nx = x + neighbor.relX();
|
||||||
const ny = y + neighbor.relY();
|
const ny = y + neighbor.relY();
|
||||||
const nz = z + neighbor.relZ();
|
const nz = z + neighbor.relZ();
|
||||||
|
|
||||||
if(nx & chunk.chunkMask != nx or ny & chunk.chunkMask != ny or nz & chunk.chunkMask != nz) {
|
if(nx & chunk.chunkMask != nx or ny & chunk.chunkMask != ny or nz & chunk.chunkMask != nz) {
|
||||||
|
const nnx: u5 = @intCast(nx & chunk.chunkMask);
|
||||||
|
const nny: u5 = @intCast(ny & chunk.chunkMask);
|
||||||
|
const nnz: u5 = @intCast(nz & chunk.chunkMask);
|
||||||
|
|
||||||
const neighborChunkMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.pos, self.pos.voxelSize, neighbor) orelse continue;
|
const neighborChunkMesh = mesh_storage.getNeighborAndIncreaseRefCount(self.pos, self.pos.voxelSize, neighbor) orelse continue;
|
||||||
defer neighborChunkMesh.decreaseRefCount();
|
defer neighborChunkMesh.decreaseRefCount();
|
||||||
const index = chunk.getIndex(nx & chunk.chunkMask, ny & chunk.chunkMask, nz & chunk.chunkMask);
|
|
||||||
|
const index = chunk.getIndex(nnx, nny, nnz);
|
||||||
|
|
||||||
neighborChunkMesh.mutex.lock();
|
neighborChunkMesh.mutex.lock();
|
||||||
var neighborBlock = neighborChunkMesh.chunk.data.getValue(index);
|
var neighborBlock = neighborChunkMesh.chunk.data.getValue(index);
|
||||||
if(neighborBlock.mode().dependsOnNeighbors) {
|
|
||||||
if(neighborBlock.mode().updateData(&neighborBlock, neighbor.reverse(), newBlock)) {
|
if(neighborBlock.mode().dependsOnNeighbors and neighborBlock.mode().updateData(&neighborBlock, neighbor.reverse(), newBlock)) {
|
||||||
neighborChunkMesh.chunk.data.setValue(index, neighborBlock);
|
neighborChunkMesh.chunk.data.setValue(index, neighborBlock);
|
||||||
neighborChunkMesh.mutex.unlock();
|
neighborChunkMesh.mutex.unlock();
|
||||||
neighborChunkMesh.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock, &lightRefreshList);
|
neighborChunkMesh.updateBlockLight(nnx, nny, nnz, neighborBlock, lightRefreshList);
|
||||||
neighborChunkMesh.generateMesh(&lightRefreshList);
|
appendIfNotContained(regenerateMeshList, neighborChunkMesh);
|
||||||
neighborChunkMesh.mutex.lock();
|
neighborChunkMesh.mutex.lock();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
neighborChunkMesh.mutex.unlock();
|
neighborChunkMesh.mutex.unlock();
|
||||||
neighborBlocks[neighbor.toInt()] = neighborBlock;
|
neighborBlocks[neighbor.toInt()] = neighborBlock;
|
||||||
@ -1219,11 +1224,9 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
const index = chunk.getIndex(nx, ny, nz);
|
const index = chunk.getIndex(nx, ny, nz);
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
var neighborBlock = self.chunk.data.getValue(index);
|
var neighborBlock = self.chunk.data.getValue(index);
|
||||||
if(neighborBlock.mode().dependsOnNeighbors) {
|
if(neighborBlock.mode().dependsOnNeighbors and neighborBlock.mode().updateData(&neighborBlock, neighbor.reverse(), newBlock)) {
|
||||||
if(neighborBlock.mode().updateData(&neighborBlock, neighbor.reverse(), newBlock)) {
|
self.chunk.data.setValue(index, neighborBlock);
|
||||||
self.chunk.data.setValue(index, neighborBlock);
|
self.updateBlockLight(@intCast(nx), @intCast(ny), @intCast(nz), neighborBlock, lightRefreshList);
|
||||||
self.updateBlockLight(@intCast(nx & chunk.chunkMask), @intCast(ny & chunk.chunkMask), @intCast(nz & chunk.chunkMask), neighborBlock, &lightRefreshList);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.mutex.unlock();
|
self.mutex.unlock();
|
||||||
neighborBlocks[neighbor.toInt()] = neighborBlock;
|
neighborBlocks[neighbor.toInt()] = neighborBlock;
|
||||||
@ -1242,9 +1245,9 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
class.onPlaceClient(.{_x, _y, _z}, self.chunk);
|
class.onPlaceClient(.{_x, _y, _z}, self.chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateBlockLight(x, y, z, newBlock, &lightRefreshList);
|
self.updateBlockLight(x, y, z, newBlock, lightRefreshList);
|
||||||
|
|
||||||
self.mutex.lock();
|
self.mutex.lock();
|
||||||
defer self.mutex.unlock();
|
|
||||||
// Update neighbor chunks:
|
// Update neighbor chunks:
|
||||||
if(x == 0) {
|
if(x == 0) {
|
||||||
self.lastNeighborsHigherLod[chunk.Neighbor.dirNegX.toInt()] = null;
|
self.lastNeighborsHigherLod[chunk.Neighbor.dirNegX.toInt()] = null;
|
||||||
@ -1268,16 +1271,18 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh
|
|||||||
self.lastNeighborsSameLod[chunk.Neighbor.dirUp.toInt()] = null;
|
self.lastNeighborsSameLod[chunk.Neighbor.dirUp.toInt()] = null;
|
||||||
}
|
}
|
||||||
self.mutex.unlock();
|
self.mutex.unlock();
|
||||||
self.generateMesh(&lightRefreshList); // TODO: Batch mesh updates instead of applying them for each block changes.
|
|
||||||
self.mutex.lock();
|
appendIfNotContained(regenerateMeshList, self);
|
||||||
for(lightRefreshList.items) |other| {
|
}
|
||||||
if(other.needsLightRefresh.load(.unordered)) {
|
|
||||||
other.scheduleLightRefreshAndDecreaseRefCount1();
|
fn appendIfNotContained(list: *main.List(*ChunkMesh), mesh: *ChunkMesh) void {
|
||||||
} else {
|
for(list.items) |other| {
|
||||||
other.decreaseRefCount();
|
if(other == mesh) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.uploadData();
|
mesh.increaseRefCount();
|
||||||
|
list.append(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clearNeighborA(self: *ChunkMesh, neighbor: chunk.Neighbor, comptime isLod: bool) void {
|
fn clearNeighborA(self: *ChunkMesh, neighbor: chunk.Neighbor, comptime isLod: bool) void {
|
||||||
|
@ -141,16 +141,7 @@ pub const ChannelChunk = struct {
|
|||||||
}
|
}
|
||||||
self.data.optimizeLayout();
|
self.data.optimizeLayout();
|
||||||
self.lock.unlockWrite();
|
self.lock.unlockWrite();
|
||||||
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| outer: {
|
self.addSelfToLightRefreshList(lightRefreshList);
|
||||||
for(lightRefreshList.items) |other| {
|
|
||||||
if(mesh == other) {
|
|
||||||
mesh.decreaseRefCount();
|
|
||||||
break :outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mesh.needsLightRefresh.store(true, .release);
|
|
||||||
lightRefreshList.append(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(chunk.Neighbor.iterable) |neighbor| {
|
for(chunk.Neighbor.iterable) |neighbor| {
|
||||||
if(neighborLists[neighbor.toInt()].items.len == 0) continue;
|
if(neighborLists[neighbor.toInt()].items.len == 0) continue;
|
||||||
@ -160,6 +151,19 @@ pub const ChannelChunk = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addSelfToLightRefreshList(self: *ChannelChunk, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) void {
|
||||||
|
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| {
|
||||||
|
for(lightRefreshList.items) |other| {
|
||||||
|
if(mesh == other) {
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mesh.needsLightRefresh.store(true, .release);
|
||||||
|
lightRefreshList.append(mesh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *main.ListUnmanaged(ChunkEntries), isFirstBlock: bool, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) main.ListUnmanaged(PositionEntry) {
|
fn propagateDestructive(self: *ChannelChunk, lightQueue: *main.utils.CircularBufferQueue(Entry), constructiveEntries: *main.ListUnmanaged(ChunkEntries), isFirstBlock: bool, lightRefreshList: *main.List(*chunk_meshing.ChunkMesh)) main.ListUnmanaged(PositionEntry) {
|
||||||
var neighborLists: [6]main.ListUnmanaged(Entry) = @splat(.{});
|
var neighborLists: [6]main.ListUnmanaged(Entry) = @splat(.{});
|
||||||
var constructiveList: main.ListUnmanaged(PositionEntry) = .{};
|
var constructiveList: main.ListUnmanaged(PositionEntry) = .{};
|
||||||
@ -230,16 +234,7 @@ pub const ChannelChunk = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.lock.unlockWrite();
|
self.lock.unlockWrite();
|
||||||
if(mesh_storage.getMeshAndIncreaseRefCount(self.ch.pos)) |mesh| outer: {
|
self.addSelfToLightRefreshList(lightRefreshList);
|
||||||
for(lightRefreshList.items) |other| {
|
|
||||||
if(mesh == other) {
|
|
||||||
mesh.decreaseRefCount();
|
|
||||||
break :outer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mesh.needsLightRefresh.store(true, .release);
|
|
||||||
lightRefreshList.append(mesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(chunk.Neighbor.iterable) |neighbor| {
|
for(chunk.Neighbor.iterable) |neighbor| {
|
||||||
if(neighborLists[neighbor.toInt()].items.len == 0) continue;
|
if(neighborLists[neighbor.toInt()].items.len == 0) continue;
|
||||||
|
@ -19,6 +19,7 @@ const Mat4f = vec.Mat4f;
|
|||||||
const EventStatus = main.entity_data.EventStatus;
|
const EventStatus = main.entity_data.EventStatus;
|
||||||
|
|
||||||
const chunk_meshing = @import("chunk_meshing.zig");
|
const chunk_meshing = @import("chunk_meshing.zig");
|
||||||
|
const ChunkMesh = chunk_meshing.ChunkMesh;
|
||||||
|
|
||||||
const ChunkMeshNode = struct {
|
const ChunkMeshNode = struct {
|
||||||
mesh: ?*chunk_meshing.ChunkMesh = null,
|
mesh: ?*chunk_meshing.ChunkMesh = null,
|
||||||
@ -44,12 +45,18 @@ var lastPy: i32 = 0;
|
|||||||
var lastPz: i32 = 0;
|
var lastPz: i32 = 0;
|
||||||
var lastRD: u16 = 0;
|
var lastRD: u16 = 0;
|
||||||
var mutex: std.Thread.Mutex = .{};
|
var mutex: std.Thread.Mutex = .{};
|
||||||
const BlockUpdate = struct {
|
|
||||||
|
pub const BlockUpdate = struct {
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
z: i32,
|
z: i32,
|
||||||
newBlock: blocks.Block,
|
newBlock: blocks.Block,
|
||||||
|
|
||||||
|
pub fn init(pos: Vec3i, block: blocks.Block) BlockUpdate {
|
||||||
|
return .{.x = pos[0], .y = pos[1], .z = pos[2], .newBlock = block};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var blockUpdateList: main.utils.ConcurrentQueue(BlockUpdate) = undefined;
|
var blockUpdateList: main.utils.ConcurrentQueue(BlockUpdate) = undefined;
|
||||||
|
|
||||||
var meshMemoryPool: main.heap.MemoryPool(chunk_meshing.ChunkMesh) = undefined;
|
var meshMemoryPool: main.heap.MemoryPool(chunk_meshing.ChunkMesh) = undefined;
|
||||||
@ -758,15 +765,8 @@ pub noinline fn updateAndGetRenderChunks(conn: *network.Connection, frustum: *co
|
|||||||
return meshList.items;
|
return meshList.items;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateMeshes(targetTime: i64) void { // MARK: updateMeshes()
|
pub fn updateMeshes(targetTime: i64) void { // MARK: updateMeshes()=
|
||||||
// First of all process all the block updates:
|
if(!blockUpdateList.empty()) batchUpdateBlocks();
|
||||||
while(blockUpdateList.dequeue()) |blockUpdate| {
|
|
||||||
const pos = chunk.ChunkPosition{.wx = blockUpdate.x, .wy = blockUpdate.y, .wz = blockUpdate.z, .voxelSize = 1};
|
|
||||||
if(getMeshAndIncreaseRefCount(pos)) |mesh| {
|
|
||||||
defer mesh.decreaseRefCount();
|
|
||||||
mesh.updateBlock(blockUpdate.x, blockUpdate.y, blockUpdate.z, blockUpdate.newBlock);
|
|
||||||
} // TODO: It seems like we simply ignore the block update if we don't have the mesh yet.
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
defer mutex.unlock();
|
defer mutex.unlock();
|
||||||
@ -859,6 +859,39 @@ pub fn updateMeshes(targetTime: i64) void { // MARK: updateMeshes()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn batchUpdateBlocks() void {
|
||||||
|
var lightRefreshList = main.List(*ChunkMesh).init(main.stackAllocator);
|
||||||
|
defer lightRefreshList.deinit();
|
||||||
|
|
||||||
|
var regenerateMeshList = main.List(*ChunkMesh).init(main.stackAllocator);
|
||||||
|
defer regenerateMeshList.deinit();
|
||||||
|
|
||||||
|
// First of all process all the block updates:
|
||||||
|
while(blockUpdateList.dequeue()) |blockUpdate| {
|
||||||
|
const pos = chunk.ChunkPosition{.wx = blockUpdate.x, .wy = blockUpdate.y, .wz = blockUpdate.z, .voxelSize = 1};
|
||||||
|
if(getMeshAndIncreaseRefCount(pos)) |mesh| {
|
||||||
|
mesh.updateBlock(blockUpdate.x, blockUpdate.y, blockUpdate.z, blockUpdate.newBlock, &lightRefreshList, ®enerateMeshList);
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
} // TODO: It seems like we simply ignore the block update if we don't have the mesh yet.
|
||||||
|
}
|
||||||
|
for(regenerateMeshList.items) |mesh| {
|
||||||
|
mesh.generateMesh(&lightRefreshList);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
for(lightRefreshList.items) |mesh| {
|
||||||
|
if(mesh.needsLightRefresh.load(.unordered)) {
|
||||||
|
mesh.scheduleLightRefreshAndDecreaseRefCount1();
|
||||||
|
} else {
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(regenerateMeshList.items) |mesh| {
|
||||||
|
mesh.uploadData();
|
||||||
|
mesh.decreaseRefCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: adders
|
// MARK: adders
|
||||||
|
|
||||||
pub fn addMeshToClearListAndDecreaseRefCount(mesh: *chunk_meshing.ChunkMesh) void {
|
pub fn addMeshToClearListAndDecreaseRefCount(mesh: *chunk_meshing.ChunkMesh) void {
|
||||||
@ -953,8 +986,8 @@ pub const MeshGenerationTask = struct { // MARK: MeshGenerationTask
|
|||||||
|
|
||||||
// MARK: updaters
|
// MARK: updaters
|
||||||
|
|
||||||
pub fn updateBlock(x: i32, y: i32, z: i32, newBlock: blocks.Block) void {
|
pub fn updateBlock(update: BlockUpdate) void {
|
||||||
blockUpdateList.enqueue(.{.x = x, .y = y, .z = z, .newBlock = newBlock});
|
blockUpdateList.enqueue(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateChunkMesh(mesh: *chunk.Chunk) void {
|
pub fn updateChunkMesh(mesh: *chunk.Chunk) void {
|
||||||
|
@ -1045,13 +1045,14 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
baseChunk.mutex.unlock();
|
baseChunk.mutex.unlock();
|
||||||
|
|
||||||
var newBlock = _newBlock;
|
var newBlock = _newBlock;
|
||||||
for(chunk.Neighbor.iterable) |neighbor| {
|
for(chunk.Neighbor.iterable) |neighbor| {
|
||||||
const nx = x + neighbor.relX();
|
const nx = x + neighbor.relX();
|
||||||
const ny = y + neighbor.relY();
|
const ny = y + neighbor.relY();
|
||||||
const nz = z + neighbor.relZ();
|
const nz = z + neighbor.relZ();
|
||||||
var ch = baseChunk;
|
var ch = baseChunk;
|
||||||
if(nx & chunk.chunkMask != nx or ny & chunk.chunkMask != ny or nz & chunk.chunkMask != nz) {
|
if(!ch.liesInChunk(nx, ny, nz)) {
|
||||||
ch = ChunkManager.getOrGenerateChunkAndIncreaseRefCount(.{
|
ch = ChunkManager.getOrGenerateChunkAndIncreaseRefCount(.{
|
||||||
.wx = baseChunk.super.pos.wx + nx & ~@as(i32, chunk.chunkMask),
|
.wx = baseChunk.super.pos.wx + nx & ~@as(i32, chunk.chunkMask),
|
||||||
.wy = baseChunk.super.pos.wy + ny & ~@as(i32, chunk.chunkMask),
|
.wy = baseChunk.super.pos.wy + ny & ~@as(i32, chunk.chunkMask),
|
||||||
@ -1062,13 +1063,13 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
|||||||
defer if(ch != baseChunk) {
|
defer if(ch != baseChunk) {
|
||||||
ch.decreaseRefCount();
|
ch.decreaseRefCount();
|
||||||
};
|
};
|
||||||
|
|
||||||
ch.mutex.lock();
|
ch.mutex.lock();
|
||||||
defer ch.mutex.unlock();
|
defer ch.mutex.unlock();
|
||||||
|
|
||||||
var neighborBlock = ch.getBlock(nx & chunk.chunkMask, ny & chunk.chunkMask, nz & chunk.chunkMask);
|
var neighborBlock = ch.getBlock(nx & chunk.chunkMask, ny & chunk.chunkMask, nz & chunk.chunkMask);
|
||||||
if(neighborBlock.mode().dependsOnNeighbors) {
|
if(neighborBlock.mode().dependsOnNeighbors and neighborBlock.mode().updateData(&neighborBlock, neighbor.reverse(), newBlock)) {
|
||||||
if(neighborBlock.mode().updateData(&neighborBlock, neighbor.reverse(), newBlock)) {
|
ch.updateBlockAndSetChanged(nx & chunk.chunkMask, ny & chunk.chunkMask, nz & chunk.chunkMask, neighborBlock);
|
||||||
ch.updateBlockAndSetChanged(nx & chunk.chunkMask, ny & chunk.chunkMask, nz & chunk.chunkMask, neighborBlock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(newBlock.mode().dependsOnNeighbors) {
|
if(newBlock.mode().dependsOnNeighbors) {
|
||||||
_ = newBlock.mode().updateData(&newBlock, neighbor, neighborBlock);
|
_ = newBlock.mode().updateData(&newBlock, neighbor, neighborBlock);
|
||||||
@ -1076,11 +1077,14 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
|||||||
}
|
}
|
||||||
baseChunk.mutex.lock();
|
baseChunk.mutex.lock();
|
||||||
defer baseChunk.mutex.unlock();
|
defer baseChunk.mutex.unlock();
|
||||||
|
|
||||||
baseChunk.updateBlockAndSetChanged(x, y, z, newBlock);
|
baseChunk.updateBlockAndSetChanged(x, y, z, newBlock);
|
||||||
|
|
||||||
const userList = server.getUserListAndIncreaseRefCount(main.stackAllocator);
|
const userList = server.getUserListAndIncreaseRefCount(main.stackAllocator);
|
||||||
defer server.freeUserListAndDecreaseRefCount(main.stackAllocator, userList);
|
defer server.freeUserListAndDecreaseRefCount(main.stackAllocator, userList);
|
||||||
|
|
||||||
for(userList) |user| {
|
for(userList) |user| {
|
||||||
main.network.Protocols.blockUpdate.send(user.conn, wx, wy, wz, _newBlock);
|
main.network.Protocols.blockUpdate.send(user.conn, &.{.{.x = wx, .y = wy, .z = wz, .newBlock = newBlock}});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user