rust/hedgewars-server/src/server/demo.rs
changeset 15547 863059f61793
child 15570 d524b7450576
equal deleted inserted replaced
15546:6b9655be1e7f 15547:863059f61793
       
     1 use crate::core::types::{GameCfg, TeamInfo};
       
     2 
       
     3 use std::{
       
     4     fs,
       
     5     io::{self, BufReader, Read, Write},
       
     6     str::FromStr,
       
     7 };
       
     8 
       
     9 struct Demo {
       
    10     teams: Vec<TeamInfo>,
       
    11     config: Vec<GameCfg>,
       
    12     messages: Vec<String>,
       
    13 }
       
    14 
       
    15 impl Demo {
       
    16     fn save(&self, file: String) -> io::Result<()> {
       
    17         Ok(unimplemented!())
       
    18     }
       
    19 
       
    20     fn load(file: String) -> io::Result<Self> {
       
    21         Ok(unimplemented!())
       
    22     }
       
    23 
       
    24     fn load_hwd(file: String) -> io::Result<Self> {
       
    25         let datum = fs::File::open(file)?;
       
    26         let mut reader = io::BufReader::new(datum);
       
    27 
       
    28         #[inline]
       
    29         fn error<T>(cause: &str) -> io::Result<T> {
       
    30             Err(io::Error::new(io::ErrorKind::InvalidData, cause))
       
    31         }
       
    32 
       
    33         fn read_command<'a>(
       
    34             reader: &mut BufReader<fs::File>,
       
    35             buffer: &'a mut [u8],
       
    36         ) -> io::Result<Option<&'a str>> {
       
    37             use io::BufRead;
       
    38 
       
    39             let mut size = [0u8; 1];
       
    40             if reader.read(&mut size)? == 0 {
       
    41                 Ok(None)
       
    42             } else {
       
    43                 let text = &mut buffer[0..size[0] as _];
       
    44 
       
    45                 if reader.read(text)? < text.len() {
       
    46                     Err(io::Error::new(
       
    47                         io::ErrorKind::UnexpectedEof,
       
    48                         "Incomplete command",
       
    49                     ))
       
    50                 } else {
       
    51                     std::str::from_utf8(text).map(Some).map_err(|e| {
       
    52                         io::Error::new(io::ErrorKind::InvalidInput, "The string is not UTF8")
       
    53                     })
       
    54                 }
       
    55             }
       
    56         }
       
    57 
       
    58         fn get_script_name(arg: &str) -> io::Result<String> {
       
    59             const PREFIX: &str = "Scripts/Multiplayer/";
       
    60             const SUFFIX: &str = ".lua";
       
    61             if arg.starts_with(PREFIX) && arg.ends_with(SUFFIX) {
       
    62                 let script = arg[PREFIX.len()..arg.len() - SUFFIX.len()].to_string();
       
    63                 script.replace('_', " ");
       
    64                 Ok(script)
       
    65             } else {
       
    66                 error("Script is not multiplayer")
       
    67             }
       
    68         }
       
    69 
       
    70         fn get_game_flags(arg: &str) -> io::Result<Vec<String>> {
       
    71             const FLAGS: &[u32] = &[
       
    72                 0x0000_1000,
       
    73                 0x0000_0010,
       
    74                 0x0000_0004,
       
    75                 0x0000_0008,
       
    76                 0x0000_0020,
       
    77                 0x0000_0040,
       
    78                 0x0000_0080,
       
    79                 0x0000_0100,
       
    80                 0x0000_0200,
       
    81                 0x0000_0400,
       
    82                 0x0000_0800,
       
    83                 0x0000_2000,
       
    84                 0x0000_4000,
       
    85                 0x0000_8000,
       
    86                 0x0001_0000,
       
    87                 0x0002_0000,
       
    88                 0x0004_0000,
       
    89                 0x0008_0000,
       
    90                 0x0010_0000,
       
    91                 0x0020_0000,
       
    92                 0x0040_0000,
       
    93                 0x0080_0000,
       
    94                 0x0100_0000,
       
    95                 0x0200_0000,
       
    96                 0x0400_0000,
       
    97             ];
       
    98 
       
    99             let flags = u32::from_str(arg).unwrap_or_default();
       
   100             let game_flags = FLAGS
       
   101                 .iter()
       
   102                 .map(|flag| (flag & flags != 0).to_string())
       
   103                 .collect();
       
   104 
       
   105             Ok(game_flags)
       
   106         }
       
   107 
       
   108         let mut config = Vec::new();
       
   109         let mut buffer = [0u8; u8::max_value() as _];
       
   110 
       
   111         let mut game_flags = vec![];
       
   112         let mut scheme_properties: Vec<_> = [
       
   113             "1", "1000", "100", "1", "1", "1000", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1",
       
   114             "1", "",
       
   115         ]
       
   116         .iter()
       
   117         .map(|p| p.to_string())
       
   118         .collect();
       
   119         const SCHEME_PROPERTY_NAMES: &[&str] = &[
       
   120             "$damagepct",
       
   121             "$turntime",
       
   122             "",
       
   123             "$sd_turns",
       
   124             "$casefreq",
       
   125             "$minestime",
       
   126             "$minesnum",
       
   127             "$minedudpct",
       
   128             "$explosives",
       
   129             "$airmines",
       
   130             "$healthprob",
       
   131             "$hcaseamount",
       
   132             "$waterrise",
       
   133             "$healthdec",
       
   134             "$ropepct",
       
   135             "$getawaytime",
       
   136             "$worldedge",
       
   137         ];
       
   138         const AMMO_PROPERTY_NAMES: &[&str] = &["eammloadt", "eammprob", "eammdelay", "eammreinf"];
       
   139         let mut ammo_settings = vec![String::new(); AMMO_PROPERTY_NAMES.len()];
       
   140         let mut teams = vec![];
       
   141         let mut hog_index = 7usize;
       
   142 
       
   143         let mut messages = vec![];
       
   144 
       
   145         while let Some(cmd) = read_command(&mut reader, &mut buffer)? {
       
   146             if let Some(index) = cmd.find(' ') {
       
   147                 match cmd.chars().next().unwrap_or_default() {
       
   148                     'T' => {
       
   149                         if cmd != "TD" {
       
   150                             let () = error("Not a demo file")?;
       
   151                         }
       
   152                     }
       
   153                     'e' => {
       
   154                         if let Some(index) = cmd.find(' ') {
       
   155                             let (name, arg) = cmd.split_at(index);
       
   156                             match name {
       
   157                                 "script" => config.push(GameCfg::Script(get_script_name(arg)?)),
       
   158                                 "map" => config.push(GameCfg::MapType(arg.to_string())),
       
   159                                 "theme" => config.push(GameCfg::Theme(arg.to_string())),
       
   160                                 "seed" => config.push(GameCfg::Seed(arg.to_string())),
       
   161                                 "$gmflags" => game_flags = get_game_flags(arg)?,
       
   162                                 "$scriptparam" => {
       
   163                                     *scheme_properties.last_mut().unwrap() = arg.to_string()
       
   164                                 }
       
   165                                 "$template_filter" => config.push(GameCfg::Template(
       
   166                                     u32::from_str(arg).unwrap_or_default(),
       
   167                                 )),
       
   168                                 "$feature_size" => config.push(GameCfg::FeatureSize(
       
   169                                     u32::from_str(arg).unwrap_or_default(),
       
   170                                 )),
       
   171                                 "$map_gen" => config.push(GameCfg::MapGenerator(
       
   172                                     u32::from_str(arg).unwrap_or_default(),
       
   173                                 )),
       
   174                                 "$maze_size" => config.push(GameCfg::MazeSize(
       
   175                                     u32::from_str(arg).unwrap_or_default(),
       
   176                                 )),
       
   177                                 "addteam" => {
       
   178                                     if let parts = arg.splitn(3, ' ').collect::<Vec<_>>() {
       
   179                                         let color = parts.get(1).unwrap_or(&"1");
       
   180                                         let name = parts.get(2).unwrap_or(&"Unnamed");
       
   181                                         teams.push(TeamInfo {
       
   182                                             color: (u32::from_str(color).unwrap_or(2113696)
       
   183                                                 / 2113696
       
   184                                                 - 1)
       
   185                                                 as u8,
       
   186                                             name: name.to_string(),
       
   187                                             ..TeamInfo::default()
       
   188                                         })
       
   189                                     };
       
   190                                 }
       
   191                                 "fort" => teams
       
   192                                     .last_mut()
       
   193                                     .iter_mut()
       
   194                                     .for_each(|t| t.fort = arg.to_string()),
       
   195                                 "grave" => teams
       
   196                                     .last_mut()
       
   197                                     .iter_mut()
       
   198                                     .for_each(|t| t.grave = arg.to_string()),
       
   199                                 "addhh" => {
       
   200                                     hog_index = (hog_index + 1) % 8;
       
   201                                     if let parts = arg.splitn(3, ' ').collect::<Vec<_>>() {
       
   202                                         let health = parts.get(1).unwrap_or(&"100");
       
   203                                         teams.last_mut().iter_mut().for_each(|t| {
       
   204                                             if let Some(difficulty) = parts.get(0) {
       
   205                                                 t.difficulty =
       
   206                                                     u8::from_str(difficulty).unwrap_or(0);
       
   207                                             }
       
   208                                             if let Some(init_health) = parts.get(1) {
       
   209                                                 scheme_properties[2] = init_health.to_string();
       
   210                                             }
       
   211                                             t.hedgehogs_number = (hog_index + 1) as u8;
       
   212                                             t.hedgehogs[hog_index].name =
       
   213                                                 parts.get(2).unwrap_or(&"Unnamed").to_string()
       
   214                                         });
       
   215                                     }
       
   216                                 }
       
   217                                 "hat" => {
       
   218                                     teams
       
   219                                         .last_mut()
       
   220                                         .iter_mut()
       
   221                                         .for_each(|t| t.hedgehogs[hog_index].hat = arg.to_string());
       
   222                                 }
       
   223                                 name => {
       
   224                                     if let Some(index) =
       
   225                                         SCHEME_PROPERTY_NAMES.iter().position(|n| *n == name)
       
   226                                     {
       
   227                                         scheme_properties[index] = arg.to_string();
       
   228                                     } else if let Some(index) =
       
   229                                         AMMO_PROPERTY_NAMES.iter().position(|n| *n == name)
       
   230                                     {
       
   231                                         ammo_settings[index] = arg.to_string();
       
   232                                     }
       
   233                                 }
       
   234                             }
       
   235                         }
       
   236                     }
       
   237                     '+' => {}
       
   238                     _ => (),
       
   239                 }
       
   240             }
       
   241         }
       
   242 
       
   243         game_flags.append(&mut scheme_properties);
       
   244         config.push(GameCfg::Scheme("ADHOG_SCHEME".to_string(), game_flags));
       
   245         config.push(GameCfg::Ammo(
       
   246             "ADHOG_AMMO".to_string(),
       
   247             Some(ammo_settings.concat()),
       
   248         ));
       
   249 
       
   250         Ok(Demo {
       
   251             teams,
       
   252             config,
       
   253             messages,
       
   254         })
       
   255     }
       
   256 }