author | unC0Rr |
Fri, 06 Oct 2023 22:37:44 +0200 | |
changeset 16011 | cf580d9ff7ef |
parent 15831 | c3971b38bbfa |
permissions | -rw-r--r-- |
16011 | 1 |
use std::str; |
2 |
||
3 |
use nom::branch::alt; |
|
4 |
use nom::bytes::streaming::*; |
|
5 |
use nom::combinator::*; |
|
6 |
use nom::error::{ErrorKind, ParseError}; |
|
7 |
use nom::multi::*; |
|
8 |
use nom::number::streaming::*; |
|
9 |
use nom::sequence::{pair, preceded, terminated, tuple}; |
|
10 |
use nom::{Err, IResult, Parser}; |
|
11 |
||
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
12 |
use crate::messages::{ |
14235
77b95406631e
Implement more of parsing, start implementation of engine messages rendering
unC0Rr
parents:
14232
diff
changeset
|
13 |
ConfigEngineMessage::*, EngineMessage::*, KeystrokeAction::*, SyncedEngineMessage::*, |
14281 | 14 |
UnorderedEngineMessage::*, *, |
14235
77b95406631e
Implement more of parsing, start implementation of engine messages rendering
unC0Rr
parents:
14232
diff
changeset
|
15 |
}; |
14231 | 16 |
|
16011 | 17 |
fn eof_slice<I>(i: I) -> IResult<I, I> |
18 |
where |
|
19 |
I: nom::InputLength + Clone, |
|
20 |
{ |
|
21 |
if i.input_len() == 0 { |
|
22 |
Ok((i.clone(), i)) |
|
23 |
} else { |
|
24 |
Err(Err::Error(nom::error::Error::new(i, ErrorKind::Eof))) |
|
14232 | 25 |
} |
16011 | 26 |
} |
27 |
fn unrecognized_message(input: &[u8]) -> IResult<&[u8], EngineMessage> { |
|
28 |
map(rest, |i: &[u8]| Unknown(i.to_owned()))(input) |
|
29 |
} |
|
14230 | 30 |
|
16011 | 31 |
fn string_tail(input: &[u8]) -> IResult<&[u8], String> { |
32 |
map_res(rest, str::from_utf8)(input).map(|(i, s)| (i, s.to_owned())) |
|
33 |
} |
|
14230 | 34 |
|
16011 | 35 |
fn length_without_timestamp(input: &[u8]) -> IResult<&[u8], usize> { |
36 |
map_opt(rest_len, |l| if l > 2 { Some(l - 2) } else { None })(input) |
|
37 |
} |
|
14231 | 38 |
|
16011 | 39 |
fn synced_message(input: &[u8]) -> IResult<&[u8], SyncedEngineMessage> { |
40 |
alt(( |
|
41 |
alt(( |
|
42 |
map(tag(b"L"), |_| Left(Press)), |
|
43 |
map(tag(b"l"), |_| Left(Release)), |
|
44 |
map(tag(b"R"), |_| Right(Press)), |
|
45 |
map(tag(b"r"), |_| Right(Release)), |
|
46 |
map(tag(b"U"), |_| Up(Press)), |
|
47 |
map(tag(b"u"), |_| Up(Release)), |
|
48 |
map(tag(b"D"), |_| Down(Press)), |
|
49 |
map(tag(b"d"), |_| Down(Release)), |
|
50 |
map(tag(b"Z"), |_| Precise(Press)), |
|
51 |
map(tag(b"z"), |_| Precise(Release)), |
|
52 |
map(tag(b"A"), |_| Attack(Press)), |
|
53 |
map(tag(b"a"), |_| Attack(Release)), |
|
54 |
map(tag(b"N"), |_| NextTurn), |
|
55 |
map(tag(b"j"), |_| LongJump), |
|
56 |
map(tag(b"J"), |_| HighJump), |
|
57 |
map(tag(b"S"), |_| Switch), |
|
58 |
)), |
|
59 |
alt(( |
|
60 |
map(tag(b","), |_| Skip), |
|
61 |
map(tag(b"1"), |_| Timer(1)), |
|
62 |
map(tag(b"2"), |_| Timer(2)), |
|
63 |
map(tag(b"3"), |_| Timer(3)), |
|
64 |
map(tag(b"4"), |_| Timer(4)), |
|
65 |
map(tag(b"5"), |_| Timer(5)), |
|
66 |
map(tuple((tag(b"p"), be_i24, be_i24)), |(_, x, y)| Put(x, y)), |
|
67 |
map(tuple((tag(b"P"), be_i24, be_i24)), |(_, x, y)| { |
|
68 |
CursorMove(x, y) |
|
69 |
}), |
|
70 |
map(preceded(tag(b"f"), string_tail), TeamControlLost), |
|
71 |
map(preceded(tag(b"g"), string_tail), TeamControlGained), |
|
72 |
map(preceded(tag(b"t"), be_u8), Taunt), |
|
73 |
map(preceded(tag(b"w"), be_u8), SetWeapon), |
|
74 |
map(preceded(tag(b"~"), be_u8), Slot), |
|
75 |
map(tag(b"+"), |_| Heartbeat), |
|
76 |
)), |
|
77 |
))(input) |
|
78 |
} |
|
14230 | 79 |
|
16011 | 80 |
fn unsynced_message(input: &[u8]) -> IResult<&[u8], UnsyncedEngineMessage> { |
81 |
alt(( |
|
82 |
map( |
|
83 |
preceded(tag(b"F"), string_tail), |
|
84 |
UnsyncedEngineMessage::TeamControlLost, |
|
85 |
), |
|
86 |
map( |
|
87 |
preceded(tag(b"G"), string_tail), |
|
88 |
UnsyncedEngineMessage::TeamControlGained, |
|
89 |
), |
|
90 |
map( |
|
91 |
preceded(tag(b"h"), string_tail), |
|
92 |
UnsyncedEngineMessage::HogSay, |
|
93 |
), |
|
94 |
map( |
|
95 |
preceded(tag(b"s"), string_tail), |
|
96 |
UnsyncedEngineMessage::ChatMessage, |
|
97 |
), |
|
98 |
map( |
|
99 |
preceded(tag(b"b"), string_tail), |
|
100 |
UnsyncedEngineMessage::TeamMessage, |
|
101 |
), |
|
102 |
))(input) |
|
103 |
} |
|
14235
77b95406631e
Implement more of parsing, start implementation of engine messages rendering
unC0Rr
parents:
14232
diff
changeset
|
104 |
|
16011 | 105 |
fn unordered_message(input: &[u8]) -> IResult<&[u8], UnorderedEngineMessage> { |
106 |
alt(( |
|
107 |
map(tag(b"?"), |_| Ping), |
|
108 |
map(tag(b"!"), |_| Pong), |
|
109 |
map(preceded(tag(b"E"), string_tail), Error), |
|
110 |
map(preceded(tag(b"W"), string_tail), Warning), |
|
111 |
map(preceded(tag(b"M"), string_tail), GameSetupChecksum), |
|
112 |
map(tag(b"o"), |_| StopSyncing), |
|
113 |
map(tag(b"I"), |_| PauseToggled), |
|
114 |
))(input) |
|
115 |
} |
|
14232 | 116 |
|
16011 | 117 |
fn config_message(input: &[u8]) -> IResult<&[u8], ConfigEngineMessage> { |
118 |
alt(( |
|
119 |
map(tag(b"C"), |_| ConfigRequest), |
|
120 |
map(preceded(tag(b"eseed "), string_tail), SetSeed), |
|
121 |
map(preceded(tag(b"e$feature_size "), string_tail), |s| { |
|
122 |
SetFeatureSize(s.parse().unwrap_or_default()) |
|
123 |
}), |
|
124 |
))(input) |
|
125 |
} |
|
14231 | 126 |
|
16011 | 127 |
fn timestamped_message(input: &[u8]) -> IResult<&[u8], (SyncedEngineMessage, u16)> { |
128 |
terminated(pair(synced_message, be_u16), eof_slice)(input) |
|
129 |
} |
|
130 |
fn unwrapped_message(input: &[u8]) -> IResult<&[u8], EngineMessage> { |
|
131 |
alt(( |
|
132 |
map(timestamped_message, |(m, t)| { |
|
133 |
EngineMessage::Synced(m, t as u32) |
|
134 |
}), |
|
135 |
map(tag(b"#"), |_| Synced(TimeWrap, 65535u32)), |
|
136 |
map(unordered_message, Unordered), |
|
137 |
map(unsynced_message, Unsynced), |
|
138 |
map(config_message, Config), |
|
139 |
unrecognized_message, |
|
140 |
))(input) |
|
141 |
} |
|
14230 | 142 |
|
16011 | 143 |
fn length_specifier(input: &[u8]) -> IResult<&[u8], u16> { |
144 |
alt(( |
|
145 |
verify(map(take(1usize), |a: &[u8]| a[0] as u16), |&l| l < 64), |
|
146 |
map(take(2usize), |a: &[u8]| { |
|
147 |
(a[0] as u16 - 64) * 256 + a[1] as u16 + 64 |
|
148 |
}), |
|
149 |
))(input) |
|
150 |
} |
|
14230 | 151 |
|
16011 | 152 |
fn empty_message(input: &[u8]) -> IResult<&[u8], EngineMessage> { |
153 |
map(tag(b"\0"), |_| Empty)(input) |
|
154 |
} |
|
155 |
||
156 |
fn non_empty_message(input: &[u8]) -> IResult<&[u8], EngineMessage> { |
|
157 |
map_parser(length_data(length_specifier), unwrapped_message)(input) |
|
158 |
} |
|
14230 | 159 |
|
16011 | 160 |
fn message(input: &[u8]) -> IResult<&[u8], EngineMessage> { |
161 |
alt((empty_message, non_empty_message))(input) |
|
162 |
} |
|
163 |
||
164 |
pub fn extract_messages(input: &[u8]) -> IResult<&[u8], Vec<EngineMessage>> { |
|
165 |
many0(complete(message))(input) |
|
166 |
} |
|
14230 | 167 |
|
14281 | 168 |
pub fn extract_message(buf: &[u8]) -> Option<(usize, EngineMessage)> { |
169 |
let parse_result = message(buf); |
|
170 |
match parse_result { |
|
171 |
Ok((tail, msg)) => { |
|
172 |
let consumed = buf.len() - tail.len(); |
|
173 |
||
174 |
Some((consumed, msg)) |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
175 |
} |
14281 | 176 |
Err(Err::Incomplete(_)) => None, |
177 |
Err(Err::Error(_)) | Err(Err::Failure(_)) => unreachable!(), |
|
178 |
} |
|
179 |
} |
|
180 |
||
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
181 |
#[cfg(test)] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
182 |
mod tests { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
183 |
use crate::messages::UnsyncedEngineMessage::*; |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
184 |
use crate::parser::*; |
14230 | 185 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
186 |
#[test] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
187 |
fn parse_length() { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
188 |
assert_eq!(length_specifier(b"\x01"), Ok((&b""[..], 1))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
189 |
assert_eq!(length_specifier(b"\x00"), Ok((&b""[..], 0))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
190 |
assert_eq!(length_specifier(b"\x3f"), Ok((&b""[..], 63))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
191 |
assert_eq!(length_specifier(b"\x40\x00"), Ok((&b""[..], 64))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
192 |
assert_eq!( |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
193 |
length_specifier(b"\xff\xff"), |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
194 |
Ok((&b""[..], EngineMessage::MAX_LEN)) |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
195 |
); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
196 |
} |
14281 | 197 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
198 |
#[test] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
199 |
fn parse_synced_messages() { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
200 |
assert_eq!( |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
201 |
message(b"\x03L\x01\x02"), |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
202 |
Ok((&b""[..], Synced(Left(Press), 258))) |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
203 |
); |
14275 | 204 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
205 |
assert_eq!(message(b"\x01#"), Ok((&b""[..], Synced(TimeWrap, 65535)))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
206 |
|
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
207 |
assert_eq!( |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
208 |
message(&vec![9, b'p', 255, 133, 151, 1, 0, 2, 0, 0]), |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
209 |
Ok((&b""[..], Synced(Put(-31337, 65538), 0))) |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
210 |
); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
211 |
} |
14230 | 212 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
213 |
#[test] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
214 |
fn parse_unsynced_messages() { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
215 |
assert_eq!( |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
216 |
message(b"\x06shello"), |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
217 |
Ok((&b""[..], Unsynced(ChatMessage(String::from("hello"))))) |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
218 |
); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
219 |
} |
14230 | 220 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
221 |
#[test] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
222 |
fn parse_incorrect_messages() { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
223 |
assert_eq!(message(b"\x00"), Ok((&b""[..], Empty))); |
16011 | 224 |
assert_eq!(message(b"\x01\x00"), Ok((&b""[..], Unknown(vec![0])))); |
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
225 |
|
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
226 |
// garbage after correct message |
16011 | 227 |
assert_eq!( |
228 |
message(b"\x04La\x01\x02"), |
|
229 |
Ok((&b""[..], Unknown(vec![76, 97, 1, 2]))) |
|
230 |
); |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
231 |
} |
14232 | 232 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
233 |
#[test] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
234 |
fn parse_config_messages() { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
235 |
assert_eq!(message(b"\x01C"), Ok((&b""[..], Config(ConfigRequest)))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
236 |
} |
14230 | 237 |
|
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
238 |
#[test] |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
239 |
fn parse_test_general() { |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
240 |
assert_eq!(string_tail(b"abc"), Ok((&b""[..], String::from("abc")))); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
241 |
|
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
242 |
assert_eq!(extract_message(b"\x02#"), None); |
16011 | 243 |
|
244 |
assert_eq!(synced_message(b"L"), Ok((&b""[..], Left(Press)))); |
|
245 |
||
15305
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
246 |
assert_eq!( |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
247 |
extract_message(b"\x01#"), |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
248 |
Some((2, Synced(TimeWrap, 65535))) |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
249 |
); |
ae8e14d14596
Move messages queue to hedgewars-engine-messages lib
unc0rr
parents:
15285
diff
changeset
|
250 |
} |
14230 | 251 |
} |