1 use nom::*; |
1 pub mod messages; |
2 use std::str; |
2 pub mod parser; |
3 |
3 |
4 #[derive(Debug, PartialEq)] |
|
5 pub enum KeystrokeAction { |
|
6 Press, |
|
7 Release, |
|
8 } |
|
9 |
|
10 #[derive(Debug, PartialEq)] |
|
11 pub enum SyncedEngineMessage { |
|
12 Left(KeystrokeAction), |
|
13 Right(KeystrokeAction), |
|
14 Up(KeystrokeAction), |
|
15 Down(KeystrokeAction), |
|
16 Precise(KeystrokeAction), |
|
17 Attack(KeystrokeAction), |
|
18 NextTurn, |
|
19 Switch, |
|
20 Timer(u8), |
|
21 Slot(u8), |
|
22 SetWeapon(u8), |
|
23 Put(i32, i32), |
|
24 HighJump, |
|
25 LowJump, |
|
26 Skip, |
|
27 TeamControlGained(String), |
|
28 TeamControlLost(String), |
|
29 } |
|
30 |
|
31 #[derive(Debug, PartialEq)] |
|
32 pub enum UnsyncedEngineMessage { |
|
33 Ping, |
|
34 Pong, |
|
35 Say(String), |
|
36 Taunt(u8), |
|
37 GameType(u8), |
|
38 Warning(String), |
|
39 StopSyncing, |
|
40 GameOver, |
|
41 GameInterrupted, |
|
42 GameSetupChecksum(String), |
|
43 } |
|
44 |
|
45 #[derive(Debug, PartialEq)] |
|
46 pub enum ConfigEngineMessage { |
|
47 ConfigRequest, |
|
48 SetAmmo(String), |
|
49 SetScript(String), |
|
50 SetScriptParam(String), |
|
51 Spectate, |
|
52 TeamLocality(bool), |
|
53 SetMap(String), |
|
54 SetTheme(String), |
|
55 SetSeed(String), |
|
56 SetTemplateFilter(String), |
|
57 SetMapGenerator(String), |
|
58 SetFeatureSize(u8), |
|
59 SetDelay(u32), |
|
60 SetReadyDelay(u32), |
|
61 SetCratesFrequency(u8), |
|
62 SetHealthCrateProbability(u8), |
|
63 SetHealthCratesNumber(u8), |
|
64 SetRoundsTilSuddenDeath(u8), |
|
65 SetSuddenDeathWaterRiseSpeed(u8), |
|
66 SetSuddenDeathHealthDecreaseRate(u8), |
|
67 SetDamageMultiplier(u32), |
|
68 SetRopeLength(u32), |
|
69 SetGetawayTime(u32), |
|
70 SetDudMinesPercent(u8), |
|
71 SetMinesNumber(u32), |
|
72 SetAirMinesNumber(u32), |
|
73 SetBarrelsNumber(u32), |
|
74 SetTurnTime(u32), |
|
75 SetMinesTime(u32), |
|
76 SetWorldEdge(u8), |
|
77 Draw, |
|
78 // TODO |
|
79 SetVoicePack(String), |
|
80 AddHedgehog(String, u8, u32), |
|
81 AddTeam(String, u8), |
|
82 SetHedgehogCoordinates(i32, i32), |
|
83 SetFort(String), |
|
84 SetGrave(String), |
|
85 SetHat(String), |
|
86 SetFlag(String), |
|
87 SetOwner(String), |
|
88 SetOneClanMode(bool), |
|
89 SetMultishootMode(bool), |
|
90 SetSolidLand(bool), |
|
91 SetBorders(bool), |
|
92 SetDivideTeams(bool), |
|
93 SetLowGravity(bool), |
|
94 SetLaserSight(bool), |
|
95 SetInvulnerability(bool), |
|
96 SetHealthReset(bool), |
|
97 SetVampiric(bool), |
|
98 SetKarma(bool), |
|
99 SetArtilleryMode(bool), |
|
100 SetHedgehogSwitch(bool), |
|
101 SetRandomOrder(bool), |
|
102 SetKingMode(bool), |
|
103 SetPlaceHedgehog(bool), |
|
104 SetSharedAmmo(bool), |
|
105 SetGirdersEnabled(bool), |
|
106 SetLandObjectsEnabled(bool), |
|
107 SetAISurvivalMode(bool), |
|
108 SetInfiniteAttack(bool), |
|
109 SetResetWeapons(bool), |
|
110 SetAmmoPerHedgehog(bool), |
|
111 SetWindMode(u8), |
|
112 SetTagTeam(bool), |
|
113 SetBottomBorder(bool), |
|
114 SetShoppaBorder(bool), |
|
115 } |
|
116 |
|
117 #[derive(Debug, PartialEq)] |
|
118 pub enum EngineMessage { |
|
119 Synced(SyncedEngineMessage, u32), |
|
120 Unsynced(UnsyncedEngineMessage), |
|
121 Config(ConfigEngineMessage), |
|
122 Unknown, |
|
123 Empty, |
|
124 } |
|
125 |
|
126 impl EngineMessage { |
|
127 fn from_bytes(buf: &[u8]) -> Self { |
|
128 unimplemented!() |
|
129 } |
|
130 |
|
131 fn to_bytes(&self) -> Vec<u8> { |
|
132 unimplemented!() |
|
133 } |
|
134 } |
|
135 |
|
136 named!(length_specifier<&[u8], u16>, alt!( |
|
137 verify!(map!(take!(1), |a : &[u8]| a[0] as u16), |l| l < 64) |
|
138 | map!(take!(2), |a| (a[0] as u16 - 64) * 256 + a[1] as u16 + 64) |
|
139 ) |
|
140 ); |
|
141 |
|
142 named!(unrecognized_message<&[u8], EngineMessage>, |
|
143 do_parse!(rest >> (EngineMessage::Unknown)) |
|
144 ); |
|
145 |
|
146 named!(string_tail<&[u8], String>, map!(map_res!(rest, str::from_utf8), String::from)); |
|
147 |
|
148 named!(synced_message<&[u8], SyncedEngineMessage>, alt!( |
|
149 do_parse!(tag!("+l") >> (SyncedEngineMessage::Left(KeystrokeAction::Press))) |
|
150 )); |
|
151 |
|
152 named!(unsynced_message<&[u8], UnsyncedEngineMessage>, alt!( |
|
153 do_parse!(tag!("?") >> (UnsyncedEngineMessage::Ping)) |
|
154 | do_parse!(tag!("!") >> (UnsyncedEngineMessage::Ping)) |
|
155 | do_parse!(tag!("esay ") >> s: string_tail >> (UnsyncedEngineMessage::Say(s))) |
|
156 )); |
|
157 |
|
158 named!(config_message<&[u8], ConfigEngineMessage>, alt!( |
|
159 do_parse!(tag!("C") >> (ConfigEngineMessage::ConfigRequest)) |
|
160 )); |
|
161 |
|
162 named!(empty_message<&[u8], EngineMessage>, |
|
163 do_parse!(tag!("\0") >> (EngineMessage::Empty)) |
|
164 ); |
|
165 |
|
166 named!(non_empty_message<&[u8], EngineMessage>, length_value!(length_specifier, |
|
167 alt!( |
|
168 map!(synced_message, |m| EngineMessage::Synced(m, 0)) |
|
169 | map!(unsynced_message, |m| EngineMessage::Unsynced(m)) |
|
170 | map!(config_message, |m| EngineMessage::Config(m)) |
|
171 | unrecognized_message |
|
172 ) |
|
173 )); |
|
174 |
|
175 named!(message<&[u8], EngineMessage>, alt!( |
|
176 empty_message |
|
177 | non_empty_message |
|
178 ) |
|
179 ); |
|
180 |
|
181 named!(pub extract_messages<&[u8], Vec<EngineMessage> >, many0!(complete!(message))); |
|
182 |
|
183 #[test] |
|
184 fn parse_length() { |
|
185 assert_eq!(length_specifier(b"\x01"), Ok((&b""[..], 1))); |
|
186 assert_eq!(length_specifier(b"\x00"), Ok((&b""[..], 0))); |
|
187 assert_eq!(length_specifier(b"\x3f"), Ok((&b""[..], 63))); |
|
188 assert_eq!(length_specifier(b"\x40\x00"), Ok((&b""[..], 64))); |
|
189 assert_eq!(length_specifier(b"\xff\xff"), Ok((&b""[..], 49215))); |
|
190 } |
|
191 |
|
192 #[test] |
|
193 fn parse_synced_messages() { |
|
194 assert_eq!(message(b"\x02+l"), Ok((&b""[..], EngineMessage::Synced(SyncedEngineMessage::Left(KeystrokeAction::Press), 0)))); |
|
195 } |
|
196 |
|
197 #[test] |
|
198 fn parse_unsynced_messages() { |
|
199 assert_eq!(message(b"\x0aesay hello"), Ok((&b""[..], EngineMessage::Unsynced(UnsyncedEngineMessage::Say(String::from("hello")))))); |
|
200 } |
|
201 |
|
202 #[test] |
|
203 fn parse_incorrect_messages() { |
|
204 assert_eq!(message(b"\x00"), Ok((&b""[..], EngineMessage::Empty))); |
|
205 assert_eq!(message(b"\x01\x00"), Ok((&b""[..], EngineMessage::Unknown))); |
|
206 } |
|
207 |
|
208 #[test] |
|
209 fn parse_config_messages() { |
|
210 assert_eq!( |
|
211 message(b"\x01C"), |
|
212 Ok(( |
|
213 &b""[..], |
|
214 EngineMessage::Config(ConfigEngineMessage::ConfigRequest) |
|
215 )) |
|
216 ); |
|
217 } |
|
218 #[test] |
|
219 fn parse_test_general() { |
|
220 assert_eq!(string_tail(b"abc"), Ok((&b""[..], String::from("abc")))); |
|
221 } |
|