Fix discrepancy between client-side and server-side torch placement.

fixes #993
This commit is contained in:
IntegratedQuantum 2025-02-02 22:42:47 +01:00
parent 9be4ff1047
commit f8a8d19759
2 changed files with 26 additions and 55 deletions

View File

@ -704,6 +704,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
} }
var posBeforeBlock: Vec3i = undefined; var posBeforeBlock: Vec3i = undefined;
var neighborOfSelection: chunk.Neighbor = undefined;
pub var selectedBlockPos: ?Vec3i = null; pub var selectedBlockPos: ?Vec3i = null;
var lastSelectedBlockPos: Vec3i = undefined; var lastSelectedBlockPos: Vec3i = undefined;
var currentBlockProgress: f32 = 0; var currentBlockProgress: f32 = 0;
@ -752,20 +753,24 @@ pub const MeshSelection = struct { // MARK: MeshSelection
voxelPos[0] +%= step[0]; voxelPos[0] +%= step[0];
total_tMax = tMax[0]; total_tMax = tMax[0];
tMax[0] += tDelta[0]; tMax[0] += tDelta[0];
neighborOfSelection = if(step[0] == 1) .dirPosX else .dirNegX;
} else { } else {
voxelPos[2] +%= step[2]; voxelPos[2] +%= step[2];
total_tMax = tMax[2]; total_tMax = tMax[2];
tMax[2] += tDelta[2]; tMax[2] += tDelta[2];
neighborOfSelection = if(step[2] == 1) .dirUp else .dirDown;
} }
} else { } else {
if(tMax[1] < tMax[2]) { if(tMax[1] < tMax[2]) {
voxelPos[1] +%= step[1]; voxelPos[1] +%= step[1];
total_tMax = tMax[1]; total_tMax = tMax[1];
tMax[1] += tDelta[1]; tMax[1] += tDelta[1];
neighborOfSelection = if(step[1] == 1) .dirPosY else .dirNegY;
} else { } else {
voxelPos[2] +%= step[2]; voxelPos[2] +%= step[2];
total_tMax = tMax[2]; total_tMax = tMax[2];
tMax[2] += tDelta[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: // Check if stuff can be added to the block itself:
if(itemBlock == block.typ) { if(itemBlock == block.typ) {
const relPos: Vec3f = @floatCast(lastPos - @as(Vec3d, @floatFromInt(selectedPos))); 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; if(!canPlaceBlock(selectedPos, block)) return;
updateBlockAndSendUpdate(inventory, slot, selectedPos[0], selectedPos[1], selectedPos[2], oldBlock, block); updateBlockAndSendUpdate(inventory, slot, selectedPos[0], selectedPos[1], selectedPos[2], oldBlock, block);
return; return;
@ -806,7 +811,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
oldBlock = mesh_storage.getBlock(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return; oldBlock = mesh_storage.getBlock(neighborPos[0], neighborPos[1], neighborPos[2]) orelse return;
block = oldBlock; block = oldBlock;
if(block.typ == itemBlock) { 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; if(!canPlaceBlock(neighborPos, block)) return;
updateBlockAndSendUpdate(inventory, slot, neighborPos[0], neighborPos[1], neighborPos[2], oldBlock, block); updateBlockAndSendUpdate(inventory, slot, neighborPos[0], neighborPos[1], neighborPos[2], oldBlock, block);
return; return;
@ -815,7 +820,7 @@ pub const MeshSelection = struct { // MARK: MeshSelection
if(block.solid()) return; if(block.solid()) return;
block.typ = itemBlock; block.typ = itemBlock;
block.data = 0; 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; if(!canPlaceBlock(neighborPos, block)) return;
updateBlockAndSendUpdate(inventory, slot, neighborPos[0], neighborPos[1], neighborPos[2], oldBlock, block); updateBlockAndSendUpdate(inventory, slot, neighborPos[0], neighborPos[1], neighborPos[2], oldBlock, block);
return; return;

View File

@ -26,7 +26,7 @@ pub const RotationMode = struct { // MARK: RotationMode
fn model(block: Block) u16 { fn model(block: Block) u16 {
return blocks.meshes.modelIndexStart(block); 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; return blockPlacing;
} }
fn createBlockModel(modelId: []const u8) u16 { 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. /// 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. /// 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. /// Updates data of a placed block if the RotationMode dependsOnNeighbors.
updateData: *const fn(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool = &DefaultFunctions.updateData, 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); 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(blockPlacing) {
if(relativeDir[0] == 1) currentData.data = Neighbor.dirNegX.toInt(); currentData.data = neighbor.?.reverse().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();
return true; return true;
} }
return false; return false;
@ -212,7 +207,7 @@ pub const RotationModes = struct {
return blocks.meshes.modelIndexStart(block) + @min(block.data, 3); 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(blockPlacing) {
if(@abs(playerDir[0]) > @abs(playerDir[1])) { if(@abs(playerDir[0]) > @abs(playerDir[1])) {
if(playerDir[0] < 0) currentData.data = Neighbor.dirNegX.toInt() - 2 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); 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) { if(blockPlacing) {
currentData.data = 0; currentData.data = 0;
return true; return true;
@ -694,7 +689,11 @@ pub const RotationModes = struct {
return blocks.meshes.modelIndexStart(block) + (@as(u5, @truncate(block.data)) -| 1); 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))); var data: TorchData = @bitCast(@as(u5, @truncate(currentData.data)));
if(relativeDir[0] == 1) data.posX = true; if(relativeDir[0] == 1) data.posX = true;
if(relativeDir[0] == -1) data.negX = 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 { pub fn updateData(block: *Block, neighbor: Neighbor, neighborBlock: Block) bool {
const blockModel = blocks.meshes.modelIndexStart(block.*);
const neighborModel = blocks.meshes.model(neighborBlock); 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))); var currentData: TorchData = @bitCast(@as(u5, @truncate(block.data)));
switch(neighbor) { switch(neighbor) {
.dirNegX => { .dirNegX => {
currentData.negX = currentData.negX and targetVal; currentData.negX = currentData.negX and neighborSupport;
}, },
.dirPosX => { .dirPosX => {
currentData.posX = currentData.posX and targetVal; currentData.posX = currentData.posX and neighborSupport;
}, },
.dirNegY => { .dirNegY => {
currentData.negY = currentData.negY and targetVal; currentData.negY = currentData.negY and neighborSupport;
}, },
.dirPosY => { .dirPosY => {
currentData.posY = currentData.posY and targetVal; currentData.posY = currentData.posY and neighborSupport;
}, },
.dirDown => { .dirDown => {
currentData.center = currentData.center and targetVal; currentData.center = currentData.center and neighborSupport;
}, },
else => {}, else => {},
} }
@ -863,7 +861,7 @@ pub const RotationModes = struct {
return blocks.meshes.modelIndexStart(block) + (@as(u6, @truncate(block.data)) -| 1); 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: { if(neighbor.mode() == currentData.mode()) parallelPlacing: {
const bit = closestRay(.bit, neighbor, null, relativePlayerPos - @as(Vec3f, @floatFromInt(relativeDir)), playerDir); const bit = closestRay(.bit, neighbor, null, relativePlayerPos - @as(Vec3f, @floatFromInt(relativeDir)), playerDir);
const bitData: CarpetData = @bitCast(@as(u6, @truncate(bit))); 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 { 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 result: ?RayIntersectionResult = null;
var resultBit: u16 = 0; var resultBit: u16 = 0;