From f8a8d197596c6227848ea42879f1804ee1a43fbb Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 2 Feb 2025 22:42:47 +0100 Subject: [PATCH] Fix discrepancy between client-side and server-side torch placement. fixes #993 --- src/renderer.zig | 11 +++++--- src/rotation.zig | 70 +++++++++++++----------------------------------- 2 files changed, 26 insertions(+), 55 deletions(-) diff --git a/src/renderer.zig b/src/renderer.zig index 26d117d0..4c967100 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -704,6 +704,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection } var posBeforeBlock: Vec3i = undefined; + var neighborOfSelection: chunk.Neighbor = undefined; pub var selectedBlockPos: ?Vec3i = null; var lastSelectedBlockPos: Vec3i = undefined; var currentBlockProgress: f32 = 0; @@ -752,20 +753,24 @@ pub const MeshSelection = struct { // MARK: MeshSelection voxelPos[0] +%= step[0]; total_tMax = tMax[0]; tMax[0] += tDelta[0]; + neighborOfSelection = if(step[0] == 1) .dirPosX else .dirNegX; } else { voxelPos[2] +%= step[2]; total_tMax = tMax[2]; tMax[2] += tDelta[2]; + neighborOfSelection = if(step[2] == 1) .dirUp else .dirDown; } } else { if(tMax[1] < tMax[2]) { voxelPos[1] +%= step[1]; total_tMax = tMax[1]; tMax[1] += tDelta[1]; + neighborOfSelection = if(step[1] == 1) .dirPosY else .dirNegY; } else { voxelPos[2] +%= step[2]; total_tMax = tMax[2]; tMax[2] += tDelta[2]; + neighborOfSelection = if(step[2] == 1) .dirUp else .dirDown; } } } @@ -792,7 +797,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection // Check if stuff can be added to the block itself: if(itemBlock == block.typ) { const relPos: Vec3f = @floatCast(lastPos - @as(Vec3d, @floatFromInt(selectedPos))); - if(rotationMode.generateData(main.game.world.?, selectedPos, relPos, lastDir, neighborDir, &block, .{.typ = 0, .data = 0}, false)) { + if(rotationMode.generateData(main.game.world.?, selectedPos, relPos, lastDir, neighborDir, null, &block, .{.typ = 0, .data = 0}, false)) { if(!canPlaceBlock(selectedPos, block)) return; updateBlockAndSendUpdate(inventory, slot, selectedPos[0], selectedPos[1], selectedPos[2], oldBlock, block); return; @@ -806,7 +811,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection oldBlock = mesh_storage.getBlock(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return; block = oldBlock; if(block.typ == itemBlock) { - if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, neighborBlock, false)) { + if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, neighborOfSelection, &block, neighborBlock, false)) { if(!canPlaceBlock(neighborPos, block)) return; updateBlockAndSendUpdate(inventory, slot, neighborPos[0], neighborPos[1], neighborPos[2], oldBlock, block); return; @@ -815,7 +820,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection if(block.solid()) return; block.typ = itemBlock; block.data = 0; - if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, neighborBlock, true)) { + if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, neighborOfSelection, &block, neighborBlock, true)) { if(!canPlaceBlock(neighborPos, block)) return; updateBlockAndSendUpdate(inventory, slot, neighborPos[0], neighborPos[1], neighborPos[2], oldBlock, block); return; diff --git a/src/rotation.zig b/src/rotation.zig index 1e7aa6d0..53677ef1 100644 --- a/src/rotation.zig +++ b/src/rotation.zig @@ -26,7 +26,7 @@ pub const RotationMode = struct { // MARK: RotationMode fn model(block: Block) u16 { return blocks.meshes.modelIndexStart(block); } - fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: *Block, _: Block, blockPlacing: bool) bool { + fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, _: *Block, _: Block, blockPlacing: bool) bool { return blockPlacing; } fn createBlockModel(modelId: []const u8) u16 { @@ -110,7 +110,7 @@ pub const RotationMode = struct { // MARK: RotationMode /// Updates the block data of a block in the world or places a block in the world. /// return true if the placing was successful, false otherwise. - generateData: *const fn(world: *main.game.World, pos: Vec3i, relativePlayerPos: Vec3f, playerDir: Vec3f, relativeDir: Vec3i, currentData: *Block, neighborBlock: Block, blockPlacing: bool) bool = DefaultFunctions.generateData, + generateData: *const fn(world: *main.game.World, pos: Vec3i, relativePlayerPos: Vec3f, playerDir: Vec3f, relativeDir: Vec3i, neighbor: ?Neighbor, currentData: *Block, neighborBlock: Block, blockPlacing: bool) bool = DefaultFunctions.generateData, /// Updates data of a placed block if the RotationMode dependsOnNeighbors. updateData: *const fn(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool = &DefaultFunctions.updateData, @@ -169,14 +169,9 @@ pub const RotationModes = struct { return blocks.meshes.modelIndexStart(block) + @min(block.data, 5); } - pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, relativeDir: Vec3i, currentData: *Block, _: Block, blockPlacing: bool) bool { + pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, neighbor: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool { if(blockPlacing) { - if(relativeDir[0] == 1) currentData.data = Neighbor.dirNegX.toInt(); - if(relativeDir[0] == -1) currentData.data = Neighbor.dirPosX.toInt(); - if(relativeDir[1] == 1) currentData.data = Neighbor.dirNegY.toInt(); - if(relativeDir[1] == -1) currentData.data = Neighbor.dirPosY.toInt(); - if(relativeDir[2] == 1) currentData.data = Neighbor.dirDown.toInt(); - if(relativeDir[2] == -1) currentData.data = Neighbor.dirUp.toInt(); + currentData.data = neighbor.?.reverse().toInt(); return true; } return false; @@ -212,7 +207,7 @@ pub const RotationModes = struct { return blocks.meshes.modelIndexStart(block) + @min(block.data, 3); } - pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, playerDir: Vec3f, _: Vec3i, currentData: *Block, _: Block, blockPlacing: bool) bool { + pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, playerDir: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool { if(blockPlacing) { if(@abs(playerDir[0]) > @abs(playerDir[1])) { if(playerDir[0] < 0) currentData.data = Neighbor.dirNegX.toInt() - 2 @@ -523,7 +518,7 @@ pub const RotationModes = struct { return blocks.meshes.modelIndexStart(block) + (block.data & 255); } - pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, currentData: *Block, _: Block, blockPlacing: bool) bool { + pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, _: Vec3i, _: ?Neighbor, currentData: *Block, _: Block, blockPlacing: bool) bool { if(blockPlacing) { currentData.data = 0; return true; @@ -694,7 +689,11 @@ pub const RotationModes = struct { return blocks.meshes.modelIndexStart(block) + (@as(u5, @truncate(block.data)) -| 1); } - pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, relativeDir: Vec3i, currentData: *Block, _: Block, _: bool) bool { + pub fn generateData(_: *main.game.World, _: Vec3i, _: Vec3f, _: Vec3f, relativeDir: Vec3i, neighbor: ?Neighbor, currentData: *Block, neighborBlock: Block, _: bool) bool { + if(neighbor == null) return false; + const neighborModel = blocks.meshes.model(neighborBlock); + const neighborSupport = neighborBlock.solid() and main.models.models.items[neighborModel].neighborFacingQuads[neighbor.?.reverse().toInt()].len != 0; + if(!neighborSupport) return false; var data: TorchData = @bitCast(@as(u5, @truncate(currentData.data))); if(relativeDir[0] == 1) data.posX = true; if(relativeDir[0] == -1) data.negX = true; @@ -710,25 +709,24 @@ pub const RotationModes = struct { } pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool { - const blockModel = blocks.meshes.modelIndexStart(block.*); const neighborModel = blocks.meshes.model(neighborBlock); - const targetVal = neighborBlock.solid() and (blockModel == neighborModel or main.models.models.items[neighborModel].neighborFacingQuads[neighbor.reverse().toInt()].len != 0); + const neighborSupport = neighborBlock.solid() and main.models.models.items[neighborModel].neighborFacingQuads[neighbor.reverse().toInt()].len != 0; var currentData: TorchData = @bitCast(@as(u5, @truncate(block.data))); switch(neighbor) { .dirNegX => { - currentData.negX = currentData.negX and targetVal; + currentData.negX = currentData.negX and neighborSupport; }, .dirPosX => { - currentData.posX = currentData.posX and targetVal; + currentData.posX = currentData.posX and neighborSupport; }, .dirNegY => { - currentData.negY = currentData.negY and targetVal; + currentData.negY = currentData.negY and neighborSupport; }, .dirPosY => { - currentData.posY = currentData.posY and targetVal; + currentData.posY = currentData.posY and neighborSupport; }, .dirDown => { - currentData.center = currentData.center and targetVal; + currentData.center = currentData.center and neighborSupport; }, else => {}, } @@ -863,7 +861,7 @@ pub const RotationModes = struct { return blocks.meshes.modelIndexStart(block) + (@as(u6, @truncate(block.data)) -| 1); } - pub fn generateData(_: *main.game.World, _: Vec3i, relativePlayerPos: Vec3f, playerDir: Vec3f, relativeDir: Vec3i, currentData: *Block, neighbor: Block, _: bool) bool { + pub fn generateData(_: *main.game.World, _: Vec3i, relativePlayerPos: Vec3f, playerDir: Vec3f, relativeDir: Vec3i, _: ?Neighbor, currentData: *Block, neighbor: Block, _: bool) bool { if(neighbor.mode() == currentData.mode()) parallelPlacing: { const bit = closestRay(.bit, neighbor, null, relativePlayerPos - @as(Vec3f, @floatFromInt(relativeDir)), playerDir); const bitData: CarpetData = @bitCast(@as(u6, @truncate(bit))); @@ -889,38 +887,6 @@ pub const RotationModes = struct { } } - pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool { - const blockModel = blocks.meshes.modelIndexStart(block.*); - const neighborModel = blocks.meshes.model(neighborBlock); - const targetVal = neighborBlock.solid() and (blockModel == neighborModel or main.models.models.items[neighborModel].neighborFacingQuads[neighbor.reverse().toInt()].len != 0); - var currentData: CarpetData = @bitCast(@as(u6, @truncate(block.data))); - switch(neighbor) { - .dirNegX => { - currentData.negX = currentData.negX and targetVal; - }, - .dirPosX => { - currentData.posX = currentData.posX and targetVal; - }, - .dirNegY => { - currentData.negY = currentData.negY and targetVal; - }, - .dirPosY => { - currentData.posY = currentData.posY and targetVal; - }, - .dirDown => { - currentData.negZ = currentData.negZ and targetVal; - }, - .dirUp => { - currentData.posZ = currentData.posZ and targetVal; - }, - } - const result: u16 = @as(u6, @bitCast(currentData)); - if(result == block.data) return false; - if(result == 0) block.* = .{.typ = 0, .data = 0} - else block.data = result; - return true; - } - fn closestRay(comptime typ: enum{bit, intersection}, block: Block, _: ?main.items.Item, relativePlayerPos: Vec3f, playerDir: Vec3f) if(typ == .intersection) ?RayIntersectionResult else u16 { var result: ?RayIntersectionResult = null; var resultBit: u16 = 0;