--- 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<TeamInfo>,
config: Vec<GameCfg>,
messages: Vec<String>,
}
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<Self> {
@@ -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::<String, HaskellValue>::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<String>| {
+ 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<Demo> {
use HaskellValue::*;
let mut lists = value.into_tuple()?;
--- 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<String> {
+fn string_content(input: &[u8]) -> HaskellResult<String> {
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,
},