1use std::io::{Read, Write};
2
3use crate::Guid;
4use crate::tbc::{
5 MovementFlags, MovementInfo, TransportInfo, Vector3d,
6};
7
8#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
15pub struct MSG_MOVE_START_FORWARD_Client {
16 pub info: MovementInfo,
17}
18
19impl crate::private::Sealed for MSG_MOVE_START_FORWARD_Client {}
20impl MSG_MOVE_START_FORWARD_Client {
21 fn read_inner(mut r: &mut &[u8], body_size: u32) -> Result<Self, crate::errors::ParseErrorKind> {
22 if !(29..=82).contains(&body_size) {
23 return Err(crate::errors::ParseErrorKind::InvalidSize);
24 }
25
26 let info = MovementInfo::read(&mut r)?;
28
29 Ok(Self {
30 info,
31 })
32 }
33
34}
35
36impl crate::Message for MSG_MOVE_START_FORWARD_Client {
37 const OPCODE: u32 = 0x00b5;
38
39 #[cfg(feature = "print-testcase")]
40 fn message_name(&self) -> &'static str {
41 "MSG_MOVE_START_FORWARD_Client"
42 }
43
44 #[cfg(feature = "print-testcase")]
45 fn to_test_case_string(&self) -> Option<String> {
46 use std::fmt::Write;
47 use crate::traits::Message;
48
49 let mut s = String::new();
50
51 writeln!(s, "test MSG_MOVE_START_FORWARD_Client {{").unwrap();
52 writeln!(s, " info = {{").unwrap();
55 writeln!(s, " flags = {};", MovementFlags::new(self.info.flags.as_int()).as_test_case_value()).unwrap();
57 writeln!(s, " extra_flags = {};", self.info.extra_flags).unwrap();
58 writeln!(s, " timestamp = {};", self.info.timestamp).unwrap();
59 writeln!(s, " position = {{").unwrap();
61 writeln!(s, " x = {};", if self.info.position.x.to_string().contains('.') { self.info.position.x.to_string() } else { format!("{}.0", self.info.position.x) }).unwrap();
63 writeln!(s, " y = {};", if self.info.position.y.to_string().contains('.') { self.info.position.y.to_string() } else { format!("{}.0", self.info.position.y) }).unwrap();
64 writeln!(s, " z = {};", if self.info.position.z.to_string().contains('.') { self.info.position.z.to_string() } else { format!("{}.0", self.info.position.z) }).unwrap();
65
66 writeln!(s, " }};").unwrap();
67 writeln!(s, " orientation = {};", if self.info.orientation.to_string().contains('.') { self.info.orientation.to_string() } else { format!("{}.0", self.info.orientation) }).unwrap();
68 if let Some(if_statement) = &self.info.flags.get_on_transport() {
69 writeln!(s, " transport = {{").unwrap();
71 writeln!(s, " guid = {};", if_statement.transport.guid.guid()).unwrap();
73 writeln!(s, " position = {{").unwrap();
75 writeln!(s, " x = {};", if if_statement.transport.position.x.to_string().contains('.') { if_statement.transport.position.x.to_string() } else { format!("{}.0", if_statement.transport.position.x) }).unwrap();
77 writeln!(s, " y = {};", if if_statement.transport.position.y.to_string().contains('.') { if_statement.transport.position.y.to_string() } else { format!("{}.0", if_statement.transport.position.y) }).unwrap();
78 writeln!(s, " z = {};", if if_statement.transport.position.z.to_string().contains('.') { if_statement.transport.position.z.to_string() } else { format!("{}.0", if_statement.transport.position.z) }).unwrap();
79
80 writeln!(s, " }};").unwrap();
81 writeln!(s, " orientation = {};", if if_statement.transport.orientation.to_string().contains('.') { if_statement.transport.orientation.to_string() } else { format!("{}.0", if_statement.transport.orientation) }).unwrap();
82 writeln!(s, " timestamp = {};", if_statement.transport.timestamp).unwrap();
83
84 writeln!(s, " }};").unwrap();
85 }
86
87 if let Some(if_statement) = &self.info.flags.get_swimming() {
88 match if_statement {
89 crate::tbc::MovementInfo_MovementFlags_Swimming::Swimming {
90 pitch1,
91 } => {
92 writeln!(s, " pitch1 = {};", if pitch1.to_string().contains('.') { pitch1.to_string() } else { format!("{}.0", pitch1) }).unwrap();
93 }
94 crate::tbc::MovementInfo_MovementFlags_Swimming::Ontransport {
95 pitch2,
96 } => {
97 writeln!(s, " pitch2 = {};", if pitch2.to_string().contains('.') { pitch2.to_string() } else { format!("{}.0", pitch2) }).unwrap();
98 }
99 }
100 }
101
102 writeln!(s, " fall_time = {};", if self.info.fall_time.to_string().contains('.') { self.info.fall_time.to_string() } else { format!("{}.0", self.info.fall_time) }).unwrap();
103 if let Some(if_statement) = &self.info.flags.get_jumping() {
104 writeln!(s, " z_speed = {};", if if_statement.z_speed.to_string().contains('.') { if_statement.z_speed.to_string() } else { format!("{}.0", if_statement.z_speed) }).unwrap();
105 writeln!(s, " cos_angle = {};", if if_statement.cos_angle.to_string().contains('.') { if_statement.cos_angle.to_string() } else { format!("{}.0", if_statement.cos_angle) }).unwrap();
106 writeln!(s, " sin_angle = {};", if if_statement.sin_angle.to_string().contains('.') { if_statement.sin_angle.to_string() } else { format!("{}.0", if_statement.sin_angle) }).unwrap();
107 writeln!(s, " xy_speed = {};", if if_statement.xy_speed.to_string().contains('.') { if_statement.xy_speed.to_string() } else { format!("{}.0", if_statement.xy_speed) }).unwrap();
108 }
109
110 if let Some(if_statement) = &self.info.flags.get_spline_elevation() {
111 writeln!(s, " spline_elevation = {};", if if_statement.spline_elevation.to_string().contains('.') { if_statement.spline_elevation.to_string() } else { format!("{}.0", if_statement.spline_elevation) }).unwrap();
112 }
113
114
115 writeln!(s, " }};").unwrap();
116
117 writeln!(s, "}} [").unwrap();
118
119 let [a, b] = (u16::try_from(self.size() + 4).unwrap()).to_be_bytes();
120 writeln!(s, " {a:#04X}, {b:#04X}, /* size */").unwrap();
121 let [a, b, c, d] = 181_u32.to_le_bytes();
122 writeln!(s, " {a:#04X}, {b:#04X}, {c:#04X}, {d:#04X}, /* opcode */").unwrap();
123 let mut bytes: Vec<u8> = Vec::new();
124 self.write_into_vec(&mut bytes).unwrap();
125 let mut bytes = bytes.into_iter();
126
127 writeln!(s, " /* info: MovementInfo start */").unwrap();
128 crate::util::write_bytes(&mut s, &mut bytes, 4, "flags", " ");
129 crate::util::write_bytes(&mut s, &mut bytes, 1, "extra_flags", " ");
130 crate::util::write_bytes(&mut s, &mut bytes, 4, "timestamp", " ");
131 writeln!(s, " /* position: Vector3d start */").unwrap();
132 crate::util::write_bytes(&mut s, &mut bytes, 4, "x", " ");
133 crate::util::write_bytes(&mut s, &mut bytes, 4, "y", " ");
134 crate::util::write_bytes(&mut s, &mut bytes, 4, "z", " ");
135 writeln!(s, " /* position: Vector3d end */").unwrap();
136 crate::util::write_bytes(&mut s, &mut bytes, 4, "orientation", " ");
137 if let Some(if_statement) = &self.info.flags.get_on_transport() {
138 writeln!(s, " /* transport: TransportInfo start */").unwrap();
139 crate::util::write_bytes(&mut s, &mut bytes, crate::util::packed_guid_size(&if_statement.transport.guid), "guid", " ");
140 writeln!(s, " /* position: Vector3d start */").unwrap();
141 crate::util::write_bytes(&mut s, &mut bytes, 4, "x", " ");
142 crate::util::write_bytes(&mut s, &mut bytes, 4, "y", " ");
143 crate::util::write_bytes(&mut s, &mut bytes, 4, "z", " ");
144 writeln!(s, " /* position: Vector3d end */").unwrap();
145 crate::util::write_bytes(&mut s, &mut bytes, 4, "orientation", " ");
146 crate::util::write_bytes(&mut s, &mut bytes, 4, "timestamp", " ");
147 writeln!(s, " /* transport: TransportInfo end */").unwrap();
148 }
149
150 if let Some(if_statement) = &self.info.flags.get_swimming() {
151 match if_statement {
152 crate::tbc::MovementInfo_MovementFlags_Swimming::Swimming {
153 pitch1,
154 } => {
155 crate::util::write_bytes(&mut s, &mut bytes, 4, "pitch1", " ");
156 }
157 crate::tbc::MovementInfo_MovementFlags_Swimming::Ontransport {
158 pitch2,
159 } => {
160 crate::util::write_bytes(&mut s, &mut bytes, 4, "pitch2", " ");
161 }
162 }
163 }
164
165 crate::util::write_bytes(&mut s, &mut bytes, 4, "fall_time", " ");
166 if let Some(if_statement) = &self.info.flags.get_jumping() {
167 crate::util::write_bytes(&mut s, &mut bytes, 4, "z_speed", " ");
168 crate::util::write_bytes(&mut s, &mut bytes, 4, "cos_angle", " ");
169 crate::util::write_bytes(&mut s, &mut bytes, 4, "sin_angle", " ");
170 crate::util::write_bytes(&mut s, &mut bytes, 4, "xy_speed", " ");
171 }
172
173 if let Some(if_statement) = &self.info.flags.get_spline_elevation() {
174 crate::util::write_bytes(&mut s, &mut bytes, 4, "spline_elevation", " ");
175 }
176
177 writeln!(s, " /* info: MovementInfo end */").unwrap();
178
179
180 writeln!(s, "] {{").unwrap();
181 writeln!(s, " versions = \"{}\";", std::env::var("WOWM_TEST_CASE_WORLD_VERSION").unwrap_or("2.4.3".to_string())).unwrap();
182 writeln!(s, "}}\n").unwrap();
183
184 Some(s)
185 }
186
187 fn size_without_header(&self) -> u32 {
188 self.size() as u32
189 }
190
191 fn write_into_vec(&self, mut w: impl Write) -> Result<(), std::io::Error> {
192 self.info.write_into_vec(&mut w)?;
194
195 Ok(())
196 }
197
198 fn read_body<S: crate::private::Sealed>(r: &mut &[u8], body_size: u32) -> Result<Self, crate::errors::ParseError> {
199 Self::read_inner(r, body_size).map_err(|a| crate::errors::ParseError::new(181, "MSG_MOVE_START_FORWARD_Client", body_size, a))
200 }
201
202}
203
204#[cfg(feature = "tbc")]
205impl crate::tbc::ClientMessage for MSG_MOVE_START_FORWARD_Client {}
206
207impl MSG_MOVE_START_FORWARD_Client {
208 pub(crate) const fn size(&self) -> usize {
209 self.info.size() }
211}
212