steel_protocol/packets/game/
c_add_entity.rs1use glam::DVec3;
4use steel_macros::ClientPacket;
5use steel_registry::packets::play::C_ADD_ENTITY;
6use steel_utils::codec::{LpVec3, VarInt};
7use steel_utils::serial::WriteTo;
8use uuid::Uuid;
9
10#[derive(ClientPacket, Clone, Debug)]
12#[packet_id(Play = C_ADD_ENTITY)]
13pub struct CAddEntity {
14 pub id: i32,
16 pub uuid: Uuid,
18 pub entity_type: i32,
20 pub position: DVec3,
22 pub velocity: DVec3,
24 pub x_rot: i8,
26 pub y_rot: i8,
28 pub head_y_rot: i8,
30 pub data: i32,
32}
33
34impl WriteTo for CAddEntity {
35 fn write(&self, writer: &mut impl std::io::Write) -> std::io::Result<()> {
36 VarInt(self.id).write(writer)?;
37 self.uuid.write(writer)?;
38 VarInt(self.entity_type).write(writer)?;
39 writer.write_all(&self.position.x.to_be_bytes())?;
40 writer.write_all(&self.position.y.to_be_bytes())?;
41 writer.write_all(&self.position.z.to_be_bytes())?;
42
43 write_lp_vec3(writer, self.velocity)?;
45
46 self.x_rot.write(writer)?;
47 self.y_rot.write(writer)?;
48 self.head_y_rot.write(writer)?;
49 VarInt(self.data).write(writer)
50 }
51}
52
53pub fn write_lp_vec3(writer: &mut impl std::io::Write, velocity: DVec3) -> std::io::Result<()> {
60 LpVec3(velocity).write(writer)
61}
62
63impl CAddEntity {
64 #[must_use]
66 pub const fn player(
67 id: i32,
68 uuid: Uuid,
69 entity_type_id: i32,
70 position: DVec3,
71 yaw: f32,
72 pitch: f32,
73 ) -> Self {
74 Self {
75 id,
76 uuid,
77 entity_type: entity_type_id,
78 position,
79 velocity: DVec3::ZERO,
80 x_rot: super::to_angle_byte(pitch),
81 y_rot: super::to_angle_byte(yaw),
82 head_y_rot: super::to_angle_byte(yaw),
83 data: 0,
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_zero_velocity() {
94 let mut buf = Vec::new();
95 write_lp_vec3(&mut buf, DVec3::ZERO).unwrap();
96 assert_eq!(buf, vec![0]);
97 }
98
99 #[test]
100 fn test_tiny_velocity_is_zero() {
101 let mut buf = Vec::new();
102 write_lp_vec3(&mut buf, DVec3::splat(1e-6)).unwrap();
103 assert_eq!(buf, vec![0]);
104 }
105
106 #[test]
107 fn test_non_zero_velocity() {
108 let mut buf = Vec::new();
109 write_lp_vec3(&mut buf, DVec3::ZERO.with_x(1.0)).unwrap();
110 assert_eq!(buf.len(), 6);
112 }
113
114 #[test]
115 fn test_negative_velocity_uses_absolute_scale() {
116 let mut buf = Vec::new();
117 write_lp_vec3(&mut buf, DVec3::ZERO.with_x(-1.0)).unwrap();
118 assert_eq!(buf.len(), 6);
119 }
120
121 #[test]
122 fn test_velocity_with_scale() {
123 let mut buf = Vec::new();
125 write_lp_vec3(&mut buf, DVec3::ZERO.with_x(5.0)).unwrap();
126 assert_eq!(buf[0] & 0x04, 0x04, "Continuation flag should be set");
129 assert!(buf.len() > 6, "Should have continuation VarInt");
131 }
132}