23 LongJump, |
23 LongJump, |
24 Skip, |
24 Skip, |
25 TeamControlGained(String), |
25 TeamControlGained(String), |
26 TeamControlLost(String), |
26 TeamControlLost(String), |
27 TimeWrap, |
27 TimeWrap, |
|
28 Taunt(u8), |
|
29 HogSay(String), |
|
30 Heartbeat, |
28 } |
31 } |
29 |
32 |
30 #[derive(Debug, PartialEq)] |
33 #[derive(Debug, PartialEq)] |
31 pub enum UnsyncedEngineMessage { |
34 pub enum UnsyncedEngineMessage { |
|
35 TeamControlGained(String), |
|
36 TeamControlLost(String), |
|
37 } |
|
38 |
|
39 #[derive(Debug, PartialEq)] |
|
40 pub enum UnorderedEngineMessage { |
32 Ping, |
41 Ping, |
33 Pong, |
42 Pong, |
34 Say(String), |
43 ChatMessage(String), |
35 Taunt(u8), |
44 TeamMessage(String), |
36 GameType(u8), |
45 Error(String), |
37 Warning(String), |
46 Warning(String), |
38 StopSyncing, |
47 StopSyncing, |
39 GameOver, |
48 GameOver, |
40 GameInterrupted, |
49 GameInterrupted, |
41 GameSetupChecksum(String), |
50 GameSetupChecksum(String), |
42 TeamControlGained(String), |
51 PauseToggled, |
43 TeamControlLost(String), |
52 } |
44 } |
|
45 |
|
46 #[derive(Debug, PartialEq)] |
53 #[derive(Debug, PartialEq)] |
47 pub enum ConfigEngineMessage { |
54 pub enum ConfigEngineMessage { |
|
55 GameType(u8), |
48 ConfigRequest, |
56 ConfigRequest, |
49 SetAmmo(String), |
57 SetAmmo(String), |
50 SetScript(String), |
58 SetScript(String), |
51 SetScriptParam(String), |
59 SetScriptParam(String), |
52 Spectate, |
60 Spectate, |
115 SetShoppaBorder(bool), |
123 SetShoppaBorder(bool), |
116 } |
124 } |
117 |
125 |
118 #[derive(Debug, PartialEq)] |
126 #[derive(Debug, PartialEq)] |
119 pub enum EngineMessage { |
127 pub enum EngineMessage { |
|
128 Unknown, |
|
129 Empty, |
120 Synced(SyncedEngineMessage, u32), |
130 Synced(SyncedEngineMessage, u32), |
121 Unsynced(UnsyncedEngineMessage), |
131 Unsynced(UnsyncedEngineMessage), |
|
132 Unordered(UnorderedEngineMessage), |
122 Config(ConfigEngineMessage), |
133 Config(ConfigEngineMessage), |
123 Unknown, |
134 } |
124 Empty, |
135 |
|
136 macro_rules! em { |
|
137 [$msg: expr] => { |
|
138 vec![($msg) as u8] |
|
139 }; |
|
140 } |
|
141 |
|
142 macro_rules! ems { |
|
143 [$msg: expr, $param: expr] => { |
|
144 { |
|
145 let mut v = vec![($msg) as u8]; |
|
146 v.extend(String::into_bytes($param.to_string()).iter()); |
|
147 v |
|
148 } |
|
149 }; |
|
150 } |
|
151 |
|
152 impl SyncedEngineMessage { |
|
153 fn to_bytes(&self) -> Vec<u8> { |
|
154 use self::KeystrokeAction::*; |
|
155 use self::SyncedEngineMessage::*; |
|
156 match self { |
|
157 Left(Press) => em!['L'], |
|
158 Left(Release) => em!['l'], |
|
159 Right(Press) => em!['R'], |
|
160 Right(Release) => em!['r'], |
|
161 Up(Press) => em!['U'], |
|
162 Up(Release) => em!['u'], |
|
163 Down(Press) => em!['D'], |
|
164 Down(Release) => em!['d'], |
|
165 Precise(Press) => em!['Z'], |
|
166 Precise(Release) => em!['z'], |
|
167 Attack(Press) => em!['A'], |
|
168 Attack(Release) => em!['a'], |
|
169 NextTurn => em!['N'], |
|
170 Switch => em!['S'], |
|
171 Timer(t) => vec!['0' as u8 + t], |
|
172 Slot(s) => vec!['~' as u8, *s], |
|
173 SetWeapon(s) => vec!['~' as u8, *s], |
|
174 Put(x, y) => unimplemented!(), |
|
175 CursorMove(x, y) => unimplemented!(), |
|
176 HighJump => em!['J'], |
|
177 LongJump => em!['j'], |
|
178 Skip => em![','], |
|
179 TeamControlGained(str) => ems!['g', str], |
|
180 TeamControlLost(str) => ems!['f', str], |
|
181 Taunt(s) => vec!['t' as u8, *s], |
|
182 HogSay(str) => ems!['h', str], |
|
183 Heartbeat => em!['+'], |
|
184 TimeWrap => unreachable!(), |
|
185 } |
|
186 } |
|
187 } |
|
188 |
|
189 impl UnsyncedEngineMessage { |
|
190 fn to_bytes(&self) -> Vec<u8> { |
|
191 use self::UnsyncedEngineMessage::*; |
|
192 match self { |
|
193 TeamControlGained(str) => ems!['G', str], |
|
194 TeamControlLost(str) => ems!['F', str], |
|
195 } |
|
196 } |
|
197 } |
|
198 |
|
199 impl UnorderedEngineMessage { |
|
200 fn to_bytes(&self) -> Vec<u8> { |
|
201 unimplemented!() |
|
202 } |
|
203 } |
|
204 |
|
205 impl ConfigEngineMessage { |
|
206 fn to_bytes(&self) -> Vec<u8> { |
|
207 unimplemented!() |
|
208 } |
125 } |
209 } |
126 |
210 |
127 impl EngineMessage { |
211 impl EngineMessage { |
128 fn from_bytes(buf: &[u8]) -> Self { |
212 pub const MAX_LEN: u16 = 49215; |
129 unimplemented!() |
213 |
130 } |
214 fn to_unwrapped(&self) -> Vec<u8> { |
131 |
215 use self::EngineMessage::*; |
132 fn to_bytes(&self) -> Vec<u8> { |
216 match self { |
133 unimplemented!() |
217 Unknown => unreachable!("you're not supposed to construct such messages"), |
134 } |
218 Empty => unreachable!("you're not supposed to construct such messages"), |
135 } |
219 Synced(SyncedEngineMessage::TimeWrap, _) => vec!['#' as u8, 0xff, 0xff], |
|
220 Synced(msg, timestamp) => { |
|
221 let mut v = msg.to_bytes(); |
|
222 v.push((*timestamp / 256) as u8); |
|
223 v.push(*timestamp as u8); |
|
224 |
|
225 v |
|
226 } |
|
227 Unsynced(msg) => msg.to_bytes(), |
|
228 Unordered(msg) => msg.to_bytes(), |
|
229 Config(msg) => msg.to_bytes(), |
|
230 } |
|
231 } |
|
232 |
|
233 pub fn to_bytes(&self) -> Vec<u8> { |
|
234 let mut unwrapped = self.to_unwrapped(); |
|
235 let mut size = unwrapped.len(); |
|
236 |
|
237 if size > EngineMessage::MAX_LEN as usize - 2 { |
|
238 size = EngineMessage::MAX_LEN as usize - 2; |
|
239 unwrapped.truncate(size); |
|
240 } |
|
241 |
|
242 if size < 64 { |
|
243 unwrapped.insert(0, size as u8); |
|
244 } else { |
|
245 size -= 64; |
|
246 unwrapped.insert(0, (size / 256 + 64) as u8); |
|
247 unwrapped.insert(1, size as u8); |
|
248 } |
|
249 |
|
250 unwrapped |
|
251 } |
|
252 } |
|
253 |
|
254 #[test] |
|
255 fn message_contruction() { |
|
256 assert_eq!( |
|
257 EngineMessage::Synced(SyncedEngineMessage::TimeWrap, 0).to_bytes(), |
|
258 vec![3, '#' as u8, 255, 255] |
|
259 ); |
|
260 assert_eq!( |
|
261 EngineMessage::Synced(SyncedEngineMessage::NextTurn, 258).to_bytes(), |
|
262 vec![3, 'N' as u8, 1, 2] |
|
263 ); |
|
264 } |