1 use crate::{ |
1 use crate::{ |
2 core::types::{GameCfg, HedgehogInfo, TeamInfo}, |
2 core::types::{GameCfg, HedgehogInfo, TeamInfo}, |
3 server::haskell::HaskellValue, |
3 server::haskell::HaskellValue, |
4 }; |
4 }; |
5 use std::{ |
5 use std::{ |
|
6 collections::HashMap, |
6 fs, |
7 fs, |
7 io::{self, BufReader, Read, Write}, |
8 io::{self, BufReader, Read, Write}, |
8 str::FromStr, |
9 str::FromStr, |
9 }; |
10 }; |
10 |
11 |
11 #[derive(PartialEq, Debug)] |
12 #[derive(PartialEq, Debug)] |
12 struct Demo { |
13 pub struct Demo { |
13 teams: Vec<TeamInfo>, |
14 teams: Vec<TeamInfo>, |
14 config: Vec<GameCfg>, |
15 config: Vec<GameCfg>, |
15 messages: Vec<String>, |
16 messages: Vec<String>, |
16 } |
17 } |
17 |
18 |
18 impl Demo { |
19 impl Demo { |
19 fn save(&self, file: String) -> io::Result<()> { |
20 fn save(self, filename: String) -> io::Result<()> { |
20 Ok(unimplemented!()) |
21 let text = format!("{}", demo_to_haskell(self)); |
|
22 let mut file = fs::File::open(filename)?; |
|
23 file.write(text.as_bytes())?; |
|
24 Ok(()) |
21 } |
25 } |
22 |
26 |
23 fn load(filename: String) -> io::Result<Self> { |
27 fn load(filename: String) -> io::Result<Self> { |
24 let mut file = fs::File::open(filename)?; |
28 let mut file = fs::File::open(filename)?; |
25 let mut bytes = vec![]; |
29 let mut bytes = vec![]; |
267 messages, |
271 messages, |
268 }) |
272 }) |
269 } |
273 } |
270 } |
274 } |
271 |
275 |
|
276 fn demo_to_haskell(mut demo: Demo) -> HaskellValue { |
|
277 use HaskellValue as Hs; |
|
278 |
|
279 let mut teams = Vec::with_capacity(demo.teams.len()); |
|
280 for team in demo.teams { |
|
281 let mut fields = HashMap::<String, HaskellValue>::new(); |
|
282 |
|
283 fields.insert("teamowner".to_string(), Hs::String(team.owner)); |
|
284 fields.insert("teamname".to_string(), Hs::String(team.name)); |
|
285 fields.insert("teamcolor".to_string(), Hs::Number(team.color)); |
|
286 fields.insert("teamgrave".to_string(), Hs::String(team.grave)); |
|
287 fields.insert("teamvoicepack".to_string(), Hs::String(team.voice_pack)); |
|
288 fields.insert("teamflag".to_string(), Hs::String(team.flag)); |
|
289 fields.insert("difficulty".to_string(), Hs::Number(team.difficulty)); |
|
290 fields.insert("hhnum".to_string(), Hs::Number(team.hedgehogs_number)); |
|
291 |
|
292 let hogs = team |
|
293 .hedgehogs |
|
294 .iter() |
|
295 .map(|hog| Hs::AnonStruct { |
|
296 name: "HedgehogInfo".to_string(), |
|
297 fields: vec![Hs::String(hog.name.clone()), Hs::String(hog.hat.clone())], |
|
298 }) |
|
299 .collect(); |
|
300 |
|
301 fields.insert("hedgehogs".to_string(), Hs::List(hogs)); |
|
302 |
|
303 teams.push(Hs::Struct { |
|
304 name: "TeamInfo".to_string(), |
|
305 fields, |
|
306 }) |
|
307 } |
|
308 |
|
309 let mut map_config = vec![]; |
|
310 let mut game_config = vec![]; |
|
311 |
|
312 let mut save_map_config = |name: &str, value: String| { |
|
313 map_config.push(Hs::Tuple(vec![ |
|
314 Hs::String(name.to_string()), |
|
315 Hs::String(value), |
|
316 ])); |
|
317 }; |
|
318 |
|
319 for config_item in &demo.config { |
|
320 match config_item { |
|
321 GameCfg::FeatureSize(size) => save_map_config("FEATURE_SIZE", size.to_string()), |
|
322 GameCfg::MapType(map_type) => save_map_config("MAP", map_type.clone()), |
|
323 GameCfg::MapGenerator(generator) => save_map_config("MAPGEN", generator.to_string()), |
|
324 GameCfg::MazeSize(size) => save_map_config("MAZE_SIZE", size.to_string()), |
|
325 GameCfg::Seed(seed) => save_map_config("SEED", seed.clone()), |
|
326 GameCfg::Template(template) => save_map_config("TEMPLATE", template.to_string()), |
|
327 GameCfg::DrawnMap(map) => save_map_config("DRAWNMAP", map.clone()), |
|
328 _ => (), |
|
329 } |
|
330 } |
|
331 |
|
332 let mut save_game_config = |name: &str, mut value: Vec<String>| { |
|
333 map_config.push(Hs::Tuple(vec![ |
|
334 Hs::String(name.to_string()), |
|
335 Hs::List(value.drain(..).map(Hs::String).collect()), |
|
336 ])); |
|
337 }; |
|
338 |
|
339 for config_item in &demo.config { |
|
340 match config_item { |
|
341 GameCfg::Ammo(name, Some(ammo)) => { |
|
342 save_game_config("AMMO", vec![name.clone(), ammo.clone()]) |
|
343 } |
|
344 GameCfg::Ammo(name, None) => save_game_config("AMMO", vec![name.clone()]), |
|
345 GameCfg::Scheme(name, scheme) => { |
|
346 let mut values = vec![name.clone()]; |
|
347 values.extend_from_slice(&scheme); |
|
348 save_game_config("SCHEME", values); |
|
349 } |
|
350 GameCfg::Script(script) => save_game_config("SCRIPT", vec![script.clone()]), |
|
351 GameCfg::Theme(theme) => save_game_config("THEME", vec![theme.clone()]), |
|
352 _ => (), |
|
353 } |
|
354 } |
|
355 |
|
356 Hs::Tuple(vec![ |
|
357 Hs::List(teams), |
|
358 Hs::List(map_config), |
|
359 Hs::List(game_config), |
|
360 Hs::List(demo.messages.drain(..).map(Hs::String).collect()), |
|
361 ]) |
|
362 } |
|
363 |
272 fn haskell_to_demo(value: HaskellValue) -> Option<Demo> { |
364 fn haskell_to_demo(value: HaskellValue) -> Option<Demo> { |
273 use HaskellValue::*; |
365 use HaskellValue::*; |
274 let mut lists = value.into_tuple()?; |
366 let mut lists = value.into_tuple()?; |
275 let mut lists_iter = lists.drain(..); |
367 let mut lists_iter = lists.drain(..); |
276 |
368 |