Skip to main content

steel_protocol/packets/game/
c_section_blocks_update.rs

1use std::io::{Result, Write};
2
3use steel_macros::ClientPacket;
4use steel_registry::packets::play::C_SECTION_BLOCKS_UPDATE;
5use steel_utils::{
6    BlockStateId, PackedSectionBlockPos, SectionPos,
7    codec::{VarInt, VarLong},
8    serial::WriteTo,
9};
10
11#[derive(ClientPacket, Clone, Debug)]
12#[packet_id(Play = C_SECTION_BLOCKS_UPDATE)]
13pub struct CSectionBlocksUpdate {
14    pub section_pos: SectionPos,
15    pub changes: Vec<BlockChange>,
16}
17
18#[derive(Clone, Debug)]
19pub struct BlockChange {
20    pub pos: PackedSectionBlockPos,
21    pub block_state: BlockStateId,
22}
23
24impl WriteTo for CSectionBlocksUpdate {
25    fn write(&self, writer: &mut impl Write) -> Result<()> {
26        // Write section position
27        self.section_pos.write(writer)?;
28
29        // Write number of changes
30        VarInt(self.changes.len() as i32).write(writer)?;
31
32        // Write each change as a packed VarLong
33        for change in &self.changes {
34            // Pack as: (block_state_id << 12) | packed_pos
35            let block_id = i32::from(change.block_state.0);
36            let packed = i64::from(block_id) << 12 | i64::from(change.pos.as_u16());
37
38            VarLong(packed).write(writer)?;
39        }
40
41        Ok(())
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use std::io::Cursor;
48
49    use steel_utils::{
50        BlockStateId, PackedSectionBlockPos, SectionPos,
51        codec::{VarInt, VarLong},
52        serial::ReadFrom,
53    };
54
55    use super::{BlockChange, CSectionBlocksUpdate};
56    use steel_utils::serial::WriteTo;
57
58    #[test]
59    fn writes_changes_with_section_relative_positions() {
60        let packet = CSectionBlocksUpdate {
61            section_pos: SectionPos::new(1, -2, 3),
62            changes: vec![BlockChange {
63                pos: PackedSectionBlockPos::from_local_xyz(1, 15, 2).unwrap(),
64                block_state: BlockStateId(42),
65            }],
66        };
67
68        let mut data = Vec::new();
69        packet.write(&mut data).unwrap();
70
71        let mut cursor = Cursor::new(data.as_slice());
72        assert_eq!(SectionPos::read(&mut cursor).unwrap(), packet.section_pos);
73        assert_eq!(VarInt::read(&mut cursor).unwrap().0, 1);
74        assert_eq!(
75            VarLong::read(&mut cursor).unwrap().0,
76            (42_i64 << 12) | 0x12f
77        );
78    }
79}