From 94974a984049b1c593763704dfea6f8912e373fa Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 3 Jun 2026 01:31:06 -0500 Subject: [PATCH 1/4] Add additional rules for slab can_be_replaced --- src/blocks/crates/data/src/lib.rs | 1 + src/blocks/src/building/slab.rs | 22 ++++++++++++++++++++-- src/core/src/block_face.rs | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/blocks/crates/data/src/lib.rs b/src/blocks/crates/data/src/lib.rs index 46fa501a..f3b499c6 100644 --- a/src/blocks/crates/data/src/lib.rs +++ b/src/blocks/crates/data/src/lib.rs @@ -16,6 +16,7 @@ pub struct PlacementContext<'a> { pub level: &'a World, pub dimension: Dimension, pub player_rotation: &'a Rotation, + pub default_placement_state: BlockStateId, } /// Result of the get_placement_state function diff --git a/src/blocks/src/building/slab.rs b/src/blocks/src/building/slab.rs index 81f7d369..9bc56651 100644 --- a/src/blocks/src/building/slab.rs +++ b/src/blocks/src/building/slab.rs @@ -41,7 +41,25 @@ impl BlockBehavior for SlabBlock { PlacedBlocks::default() } - fn can_be_replaced(&self, _context: PlacementContext) -> bool { - true + fn can_be_replaced(&self, context: PlacementContext) -> bool { + if matches!(self.ty, SlabType::Double) { + return false; + } + + if !matches!(context.face, BlockFace::Top | BlockFace::Bottom) { + return false; + } + + let expected_face = match self.ty { + SlabType::Top => BlockFace::Bottom, + SlabType::Bottom => BlockFace::Top, + SlabType::Double => unreachable!(), + }; + + if context.face != expected_face { + return false; + } + + context.default_placement_state.try_cast::().is_some_and(|slab| slab.block_type == self.block_type) } } diff --git a/src/core/src/block_face.rs b/src/core/src/block_face.rs index 632b4073..b14ab874 100644 --- a/src/core/src/block_face.rs +++ b/src/core/src/block_face.rs @@ -4,7 +4,7 @@ use temper_codec::decode::errors::NetDecodeError; use temper_codec::decode::{NetDecode, NetDecodeOpts}; use temper_codec::net_types::var_int::VarInt; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum BlockFace { Top, Bottom, From af3b575b9c20eaef47e6ad849d563a9888f81c1d Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 3 Jun 2026 01:41:35 -0500 Subject: [PATCH 2/4] Change block placing logic to try the offset block and adjacent block --- .../src/packets/src/place_block.rs | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 383fe20e..984b9ac1 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -118,7 +118,7 @@ pub fn handle( continue 'ev_loop; } - let offset_pos = block_pos + let mut offset_pos = block_pos + IVec3::new( (event.cursor_x * 2.0 - 1.0) as i32, (event.cursor_y * 2.0 - 1.0) as i32, @@ -159,8 +159,15 @@ pub fn handle( continue 'ev_loop; } - let placement_context = temper_blocks::PlacementContext { - face: event.face, + let mut block_state = ITEM_TO_BLOCK_MAPPING + .get() + .unwrap() + .get(&(item_id.as_u32() as i32)) + .copied() + .unwrap(); + + let mut placement_context = temper_blocks::PlacementContext { + face: event.face.clone(), cursor: DVec3::new( f64::from(event.cursor_x), f64::from(event.cursor_y), @@ -171,36 +178,44 @@ pub fn handle( level: &state.0.world, dimension: Dimension::Overworld, player_rotation: rot, + default_placement_state: block_state, }; + // Try to replace the block from the offset calculated if !curr_state.can_be_replaced(placement_context.clone()) { - if let Err(err) = conn.send_packet_ref(&ack_packet) { - error!("Failed to send block change ack packet: {:?}", err); + // If the block cannot be replaced, try to replace the block adjacent to the face clicked + offset_pos = block_pos + event.face.get_normal().into(); + + let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) + else { + error!("Can't get block at {}", offset_pos); continue 'ev_loop; - } + }; + + if !curr_state.can_be_replaced(placement_context.clone()) { + if let Err(err) = conn.send_packet_ref(&ack_packet) { + error!("Failed to send block change ack packet: {:?}", err); + continue 'ev_loop; + } + + if let Err(err) = conn.send_packet(BlockUpdate { + location: NetworkPosition { + x: offset_pos.pos.x, + y: offset_pos.pos.y as i16, + z: offset_pos.pos.z, + }, + block_state_id: curr_state.to_varint(), + }) { + error!("Failed to send block update packet to player: {err}"); + continue 'ev_loop; + } - if let Err(err) = conn.send_packet(BlockUpdate { - location: NetworkPosition { - x: offset_pos.pos.x, - y: offset_pos.pos.y as i16, - z: offset_pos.pos.z, - }, - block_state_id: curr_state.to_varint(), - }) { - error!("Failed to send block update packet to player: {err}"); continue 'ev_loop; } - continue 'ev_loop; + placement_context.block_pos = offset_pos; } - let mut block_state = ITEM_TO_BLOCK_MAPPING - .get() - .unwrap() - .get(&(item_id.as_u32() as i32)) - .copied() - .unwrap(); - let mut placed_blocks = block_state.get_placement_state(placement_context); if placed_blocks.place_original { From 20016eeaafefac9286d15cb465e76f3bf2244874 Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 3 Jun 2026 01:47:26 -0500 Subject: [PATCH 3/4] Formatting fix --- src/blocks/src/building/slab.rs | 5 ++++- src/game_systems/src/packets/src/place_block.rs | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/blocks/src/building/slab.rs b/src/blocks/src/building/slab.rs index 9bc56651..20491b62 100644 --- a/src/blocks/src/building/slab.rs +++ b/src/blocks/src/building/slab.rs @@ -60,6 +60,9 @@ impl BlockBehavior for SlabBlock { return false; } - context.default_placement_state.try_cast::().is_some_and(|slab| slab.block_type == self.block_type) + context + .default_placement_state + .try_cast::() + .is_some_and(|slab| slab.block_type == self.block_type) } } diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 984b9ac1..53787f89 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -186,7 +186,8 @@ pub fn handle( // If the block cannot be replaced, try to replace the block adjacent to the face clicked offset_pos = block_pos + event.face.get_normal().into(); - let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) + let Ok(curr_state) = + state.0.world.get_block(offset_pos, Dimension::Overworld) else { error!("Can't get block at {}", offset_pos); continue 'ev_loop; From b2724413772013dce1e21409aa89dca78e0f9bed Mon Sep 17 00:00:00 2001 From: MSKatKing Date: Wed, 3 Jun 2026 10:30:28 -0500 Subject: [PATCH 4/4] Fix compilation error --- src/blocks/src/decorative/fence_pane.rs | 4 ++-- src/core/src/pos.rs | 10 ++++++++++ src/game_systems/src/packets/src/place_block.rs | 5 ++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/blocks/src/decorative/fence_pane.rs b/src/blocks/src/decorative/fence_pane.rs index c145211b..1723eabd 100644 --- a/src/blocks/src/decorative/fence_pane.rs +++ b/src/blocks/src/decorative/fence_pane.rs @@ -29,7 +29,7 @@ impl BlockBehavior for FenceAndPaneBlock { &mut self.south, &mut self.west, ]) { - let pos = context.block_pos + IVec3::new(*dx, 0, *dz).into(); + let pos = context.block_pos + IVec3::new(*dx, 0, *dz); let block = context .level .get_block(pos, context.dimension) @@ -61,7 +61,7 @@ impl BlockBehavior for FenceAndPaneBlock { &mut self.south, &mut self.west, ]) { - let pos = pos + IVec3::new(*dx, 0, *dz).into(); + let pos = pos + IVec3::new(*dx, 0, *dz); let block = world .get_block(pos, Dimension::Overworld) .unwrap_or_default(); diff --git a/src/core/src/pos.rs b/src/core/src/pos.rs index f22ca563..91719527 100644 --- a/src/core/src/pos.rs +++ b/src/core/src/pos.rs @@ -104,6 +104,16 @@ impl Add<(i32, i32, i32)> for BlockPos { } } +impl Add for BlockPos { + type Output = BlockPos; + + fn add(self, rhs: IVec3) -> Self::Output { + Self { + pos: self.pos + rhs, + } + } +} + #[derive(Clone, Copy, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct ChunkHeight { pub min_y: i16, diff --git a/src/game_systems/src/packets/src/place_block.rs b/src/game_systems/src/packets/src/place_block.rs index 53787f89..f38e4b91 100644 --- a/src/game_systems/src/packets/src/place_block.rs +++ b/src/game_systems/src/packets/src/place_block.rs @@ -123,8 +123,7 @@ pub fn handle( (event.cursor_x * 2.0 - 1.0) as i32, (event.cursor_y * 2.0 - 1.0) as i32, (event.cursor_z * 2.0 - 1.0) as i32, - ) - .into(); + ); let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld) else { @@ -184,7 +183,7 @@ pub fn handle( // Try to replace the block from the offset calculated if !curr_state.can_be_replaced(placement_context.clone()) { // If the block cannot be replaced, try to replace the block adjacent to the face clicked - offset_pos = block_pos + event.face.get_normal().into(); + offset_pos = block_pos + event.face.get_normal(); let Ok(curr_state) = state.0.world.get_block(offset_pos, Dimension::Overworld)