steel_protocol/packets/game/
c_section_blocks_update.rs1use 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 self.section_pos.write(writer)?;
28
29 VarInt(self.changes.len() as i32).write(writer)?;
31
32 for change in &self.changes {
34 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}