Skip to main content

steel_protocol/packets/game/
s_sign_update.rs

1use std::io::Cursor;
2
3use steel_macros::ServerPacket;
4use steel_utils::BlockPos;
5use steel_utils::serial::{PrefixedRead, ReadFrom};
6use steel_utils::types::SignTextSlot;
7
8/// Maximum characters per sign line.
9pub const MAX_SIGN_LINE_LENGTH: usize = 384;
10
11/// Serverbound packet sent when a player finishes editing a sign.
12#[derive(ServerPacket, Clone, Debug)]
13pub struct SSignUpdate {
14    /// The position of the sign block.
15    pub pos: BlockPos,
16    /// The four lines of text. Each line is max 384 characters.
17    pub lines: [String; 4],
18    /// Which side of the sign was edited.
19    pub slot: SignTextSlot,
20}
21
22impl ReadFrom for SSignUpdate {
23    fn read(data: &mut Cursor<&[u8]>) -> std::io::Result<Self> {
24        use steel_utils::codec::VarInt;
25
26        let pos = BlockPos::read(data)?;
27        // Vanilla writes the lines as a fixed-size list, so there is no length prefix.
28        let lines = [
29            String::read_prefixed_bound::<VarInt>(data, MAX_SIGN_LINE_LENGTH)?,
30            String::read_prefixed_bound::<VarInt>(data, MAX_SIGN_LINE_LENGTH)?,
31            String::read_prefixed_bound::<VarInt>(data, MAX_SIGN_LINE_LENGTH)?,
32            String::read_prefixed_bound::<VarInt>(data, MAX_SIGN_LINE_LENGTH)?,
33        ];
34        let slot = SignTextSlot::read(data)?;
35
36        Ok(Self { pos, lines, slot })
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn sign_update_reads_lines_before_slot() {
46        // BlockPos(0, 64, 0) packed, then four length-prefixed lines, then the slot.
47        let mut bytes = 0x0000_0000_0000_0040u64.to_be_bytes().to_vec();
48        for line in ["a", "b", "c", "d"] {
49            bytes.push(1);
50            bytes.extend_from_slice(line.as_bytes());
51        }
52        bytes.push(1); // SignTextSlot::Front
53
54        let packet = SSignUpdate::read(&mut Cursor::new(&bytes[..])).expect("should decode");
55
56        assert_eq!(packet.pos, BlockPos::new(0, 64, 0));
57        assert_eq!(packet.lines, ["a", "b", "c", "d"].map(String::from));
58        assert_eq!(packet.slot, SignTextSlot::Front);
59    }
60}