# HG changeset patch # User alfadur # Date 1590289825 -10800 # Node ID ab095fc0256c8106ca6a9aca92e75deb72836af7 # Parent 98482c4ccf4b25f000735bc148d2e54d57a7e439 convert replay to haskell diff -r 98482c4ccf4b -r ab095fc0256c rust/hedgewars-server/src/server/demo.rs --- a/rust/hedgewars-server/src/server/demo.rs Wed May 20 23:41:25 2020 +0300 +++ b/rust/hedgewars-server/src/server/demo.rs Sun May 24 06:10:25 2020 +0300 @@ -3,21 +3,25 @@ server::haskell::HaskellValue, }; use std::{ + collections::HashMap, fs, io::{self, BufReader, Read, Write}, str::FromStr, }; #[derive(PartialEq, Debug)] -struct Demo { +pub struct Demo { teams: Vec, config: Vec, messages: Vec, } impl Demo { - fn save(&self, file: String) -> io::Result<()> { - Ok(unimplemented!()) + fn save(self, filename: String) -> io::Result<()> { + let text = format!("{}", demo_to_haskell(self)); + let mut file = fs::File::open(filename)?; + file.write(text.as_bytes())?; + Ok(()) } fn load(filename: String) -> io::Result { @@ -269,6 +273,94 @@ } } +fn demo_to_haskell(mut demo: Demo) -> HaskellValue { + use HaskellValue as Hs; + + let mut teams = Vec::with_capacity(demo.teams.len()); + for team in demo.teams { + let mut fields = HashMap::::new(); + + fields.insert("teamowner".to_string(), Hs::String(team.owner)); + fields.insert("teamname".to_string(), Hs::String(team.name)); + fields.insert("teamcolor".to_string(), Hs::Number(team.color)); + fields.insert("teamgrave".to_string(), Hs::String(team.grave)); + fields.insert("teamvoicepack".to_string(), Hs::String(team.voice_pack)); + fields.insert("teamflag".to_string(), Hs::String(team.flag)); + fields.insert("difficulty".to_string(), Hs::Number(team.difficulty)); + fields.insert("hhnum".to_string(), Hs::Number(team.hedgehogs_number)); + + let hogs = team + .hedgehogs + .iter() + .map(|hog| Hs::AnonStruct { + name: "HedgehogInfo".to_string(), + fields: vec![Hs::String(hog.name.clone()), Hs::String(hog.hat.clone())], + }) + .collect(); + + fields.insert("hedgehogs".to_string(), Hs::List(hogs)); + + teams.push(Hs::Struct { + name: "TeamInfo".to_string(), + fields, + }) + } + + let mut map_config = vec![]; + let mut game_config = vec![]; + + let mut save_map_config = |name: &str, value: String| { + map_config.push(Hs::Tuple(vec![ + Hs::String(name.to_string()), + Hs::String(value), + ])); + }; + + for config_item in &demo.config { + match config_item { + GameCfg::FeatureSize(size) => save_map_config("FEATURE_SIZE", size.to_string()), + GameCfg::MapType(map_type) => save_map_config("MAP", map_type.clone()), + GameCfg::MapGenerator(generator) => save_map_config("MAPGEN", generator.to_string()), + GameCfg::MazeSize(size) => save_map_config("MAZE_SIZE", size.to_string()), + GameCfg::Seed(seed) => save_map_config("SEED", seed.clone()), + GameCfg::Template(template) => save_map_config("TEMPLATE", template.to_string()), + GameCfg::DrawnMap(map) => save_map_config("DRAWNMAP", map.clone()), + _ => (), + } + } + + let mut save_game_config = |name: &str, mut value: Vec| { + map_config.push(Hs::Tuple(vec![ + Hs::String(name.to_string()), + Hs::List(value.drain(..).map(Hs::String).collect()), + ])); + }; + + for config_item in &demo.config { + match config_item { + GameCfg::Ammo(name, Some(ammo)) => { + save_game_config("AMMO", vec![name.clone(), ammo.clone()]) + } + GameCfg::Ammo(name, None) => save_game_config("AMMO", vec![name.clone()]), + GameCfg::Scheme(name, scheme) => { + let mut values = vec![name.clone()]; + values.extend_from_slice(&scheme); + save_game_config("SCHEME", values); + } + GameCfg::Script(script) => save_game_config("SCRIPT", vec![script.clone()]), + GameCfg::Theme(theme) => save_game_config("THEME", vec![theme.clone()]), + _ => (), + } + } + + Hs::Tuple(vec![ + Hs::List(teams), + Hs::List(map_config), + Hs::List(game_config), + Hs::List(demo.messages.drain(..).map(Hs::String).collect()), + ]) +} + fn haskell_to_demo(value: HaskellValue) -> Option { use HaskellValue::*; let mut lists = value.into_tuple()?; diff -r 98482c4ccf4b -r ab095fc0256c rust/hedgewars-server/src/server/haskell.rs --- a/rust/hedgewars-server/src/server/haskell.rs Wed May 20 23:41:25 2020 +0300 +++ b/rust/hedgewars-server/src/server/haskell.rs Sun May 24 06:10:25 2020 +0300 @@ -269,7 +269,7 @@ ))(input) } -fn string_content(mut input: &[u8]) -> HaskellResult { +fn string_content(input: &[u8]) -> HaskellResult { map_res( escaped_transform(is_not("\"\\"), '\\', string_escape), |bytes| String::from_utf8(bytes).map_err(|_| ()), @@ -331,7 +331,7 @@ many0(terminated(value, take_while(is_space))), ), ), - |(name, mut fields)| HaskellValue::AnonStruct { + |(name, fields)| HaskellValue::AnonStruct { name: name.clone(), fields, },