# HG changeset patch # User unC0Rr # Date 1542382371 -3600 # Node ID 77b95406631ef20ef226fa0840f0e725b52277c8 # Parent 09dacb61d526f405116aa23718eee09473beebfc Implement more of parsing, start implementation of engine messages rendering diff -r 09dacb61d526 -r 77b95406631e rust/hedgewars-engine-messages/src/messages.rs --- a/rust/hedgewars-engine-messages/src/messages.rs Thu Nov 15 15:39:59 2018 -0500 +++ b/rust/hedgewars-engine-messages/src/messages.rs Fri Nov 16 16:32:51 2018 +0100 @@ -25,26 +25,34 @@ TeamControlGained(String), TeamControlLost(String), TimeWrap, + Taunt(u8), + HogSay(String), + Heartbeat, } #[derive(Debug, PartialEq)] pub enum UnsyncedEngineMessage { + TeamControlGained(String), + TeamControlLost(String), +} + +#[derive(Debug, PartialEq)] +pub enum UnorderedEngineMessage { Ping, Pong, - Say(String), - Taunt(u8), - GameType(u8), + ChatMessage(String), + TeamMessage(String), + Error(String), Warning(String), StopSyncing, GameOver, GameInterrupted, GameSetupChecksum(String), - TeamControlGained(String), - TeamControlLost(String), + PauseToggled, } - #[derive(Debug, PartialEq)] pub enum ConfigEngineMessage { + GameType(u8), ConfigRequest, SetAmmo(String), SetScript(String), @@ -117,19 +125,140 @@ #[derive(Debug, PartialEq)] pub enum EngineMessage { - Synced(SyncedEngineMessage, u32), - Unsynced(UnsyncedEngineMessage), - Config(ConfigEngineMessage), Unknown, Empty, + Synced(SyncedEngineMessage, u32), + Unsynced(UnsyncedEngineMessage), + Unordered(UnorderedEngineMessage), + Config(ConfigEngineMessage), +} + +macro_rules! em { + [$msg: expr] => { + vec![($msg) as u8] + }; +} + +macro_rules! ems { + [$msg: expr, $param: expr] => { + { + let mut v = vec![($msg) as u8]; + v.extend(String::into_bytes($param.to_string()).iter()); + v + } + }; } -impl EngineMessage { - fn from_bytes(buf: &[u8]) -> Self { - unimplemented!() +impl SyncedEngineMessage { + fn to_bytes(&self) -> Vec { + use self::KeystrokeAction::*; + use self::SyncedEngineMessage::*; + match self { + Left(Press) => em!['L'], + Left(Release) => em!['l'], + Right(Press) => em!['R'], + Right(Release) => em!['r'], + Up(Press) => em!['U'], + Up(Release) => em!['u'], + Down(Press) => em!['D'], + Down(Release) => em!['d'], + Precise(Press) => em!['Z'], + Precise(Release) => em!['z'], + Attack(Press) => em!['A'], + Attack(Release) => em!['a'], + NextTurn => em!['N'], + Switch => em!['S'], + Timer(t) => vec!['0' as u8 + t], + Slot(s) => vec!['~' as u8, *s], + SetWeapon(s) => vec!['~' as u8, *s], + Put(x, y) => unimplemented!(), + CursorMove(x, y) => unimplemented!(), + HighJump => em!['J'], + LongJump => em!['j'], + Skip => em![','], + TeamControlGained(str) => ems!['g', str], + TeamControlLost(str) => ems!['f', str], + Taunt(s) => vec!['t' as u8, *s], + HogSay(str) => ems!['h', str], + Heartbeat => em!['+'], + TimeWrap => unreachable!(), + } } +} +impl UnsyncedEngineMessage { + fn to_bytes(&self) -> Vec { + use self::UnsyncedEngineMessage::*; + match self { + TeamControlGained(str) => ems!['G', str], + TeamControlLost(str) => ems!['F', str], + } + } +} + +impl UnorderedEngineMessage { fn to_bytes(&self) -> Vec { unimplemented!() } } + +impl ConfigEngineMessage { + fn to_bytes(&self) -> Vec { + unimplemented!() + } +} + +impl EngineMessage { + pub const MAX_LEN: u16 = 49215; + + fn to_unwrapped(&self) -> Vec { + use self::EngineMessage::*; + match self { + Unknown => unreachable!("you're not supposed to construct such messages"), + Empty => unreachable!("you're not supposed to construct such messages"), + Synced(SyncedEngineMessage::TimeWrap, _) => vec!['#' as u8, 0xff, 0xff], + Synced(msg, timestamp) => { + let mut v = msg.to_bytes(); + v.push((*timestamp / 256) as u8); + v.push(*timestamp as u8); + + v + } + Unsynced(msg) => msg.to_bytes(), + Unordered(msg) => msg.to_bytes(), + Config(msg) => msg.to_bytes(), + } + } + + pub fn to_bytes(&self) -> Vec { + let mut unwrapped = self.to_unwrapped(); + let mut size = unwrapped.len(); + + if size > EngineMessage::MAX_LEN as usize - 2 { + size = EngineMessage::MAX_LEN as usize - 2; + unwrapped.truncate(size); + } + + if size < 64 { + unwrapped.insert(0, size as u8); + } else { + size -= 64; + unwrapped.insert(0, (size / 256 + 64) as u8); + unwrapped.insert(1, size as u8); + } + + unwrapped + } +} + +#[test] +fn message_contruction() { + assert_eq!( + EngineMessage::Synced(SyncedEngineMessage::TimeWrap, 0).to_bytes(), + vec![3, '#' as u8, 255, 255] + ); + assert_eq!( + EngineMessage::Synced(SyncedEngineMessage::NextTurn, 258).to_bytes(), + vec![3, 'N' as u8, 1, 2] + ); +} diff -r 09dacb61d526 -r 77b95406631e rust/hedgewars-engine-messages/src/parser.rs --- a/rust/hedgewars-engine-messages/src/parser.rs Thu Nov 15 15:39:59 2018 -0500 +++ b/rust/hedgewars-engine-messages/src/parser.rs Fri Nov 16 16:32:51 2018 +0100 @@ -1,8 +1,10 @@ -use nom::{*, Err::Error}; +use nom::{Err::Error, *}; use std::str; -use super::messages::{*, EngineMessage::*, UnsyncedEngineMessage::*, SyncedEngineMessage::*, ConfigEngineMessage::*, KeystrokeAction::*}; - +use super::messages::{ + ConfigEngineMessage::*, EngineMessage::*, KeystrokeAction::*, SyncedEngineMessage::*, + UnorderedEngineMessage::*, UnsyncedEngineMessage::*, *, +}; macro_rules! eof_slice ( ($i:expr,) => ( @@ -27,7 +29,7 @@ ); named!(synced_message<&[u8], SyncedEngineMessage>, alt!( - do_parse!(tag!("L") >> (Left(Press))) + do_parse!(tag!("L") >> (Left(Press))) | do_parse!(tag!("l") >> ( Left(Release) )) | do_parse!(tag!("R") >> ( Right(Press) )) | do_parse!(tag!("r") >> ( Right(Release) )) @@ -53,16 +55,26 @@ | do_parse!(tag!("P") >> x: be_i24 >> y: be_i24 >> ( CursorMove(x, y) )) | do_parse!(tag!("f") >> s: string_tail >> ( SyncedEngineMessage::TeamControlLost(s) )) | do_parse!(tag!("g") >> s: string_tail >> ( SyncedEngineMessage::TeamControlGained(s) )) - /* - Slot(u8), - SetWeapon(u8), - */ + | do_parse!(tag!("h") >> s: string_tail >> ( HogSay(s) )) + | do_parse!(tag!("t") >> t: be_u8 >> ( Taunt(t) )) + | do_parse!(tag!("w") >> w: be_u8 >> ( SetWeapon(w) )) + | do_parse!(tag!("~") >> s: be_u8 >> ( Slot(s) )) + | do_parse!(tag!("+") >> ( Heartbeat )) )); named!(unsynced_message<&[u8], UnsyncedEngineMessage>, alt!( - do_parse!(tag!("?") >> (Ping)) - | do_parse!(tag!("!") >> (Ping)) - | do_parse!(tag!("esay ") >> s: string_tail >> (Say(s))) + do_parse!(tag!("F") >> s: string_tail >> ( UnsyncedEngineMessage::TeamControlLost(s) )) + | do_parse!(tag!("G") >> s: string_tail >> ( UnsyncedEngineMessage::TeamControlGained(s) )) +)); + +named!(unordered_message<&[u8], UnorderedEngineMessage>, alt!( + do_parse!(tag!("?") >> ( Ping )) + | do_parse!(tag!("!") >> ( Ping )) + | do_parse!(tag!("s") >> s: string_tail >> ( ChatMessage(s)) ) + | do_parse!(tag!("b") >> s: string_tail >> ( TeamMessage(s)) ) // TODO: wtf is the format + | do_parse!(tag!("M") >> s: string_tail >> ( GameSetupChecksum(s)) ) + | do_parse!(tag!("o") >> ( StopSyncing )) + | do_parse!(tag!("I") >> ( PauseToggled )) )); named!(config_message<&[u8], ConfigEngineMessage>, alt!( @@ -80,13 +92,12 @@ alt!( map!(timestamped_message, |(m, t)| Synced(m, t as u32)) | do_parse!(tag!("#") >> (Synced(TimeWrap, 65535))) + | map!(unordered_message, |m| Unordered(m)) | map!(unsynced_message, |m| Unsynced(m)) | map!(config_message, |m| Config(m)) | unrecognized_message )); - - named!(length_specifier<&[u8], u16>, alt!( verify!(map!(take!(1), |a : &[u8]| a[0] as u16), |l| l < 64) | map!(take!(2), |a| (a[0] as u16 - 64) * 256 + a[1] as u16 + 64) @@ -114,18 +125,27 @@ assert_eq!(length_specifier(b"\x00"), Ok((&b""[..], 0))); assert_eq!(length_specifier(b"\x3f"), Ok((&b""[..], 63))); assert_eq!(length_specifier(b"\x40\x00"), Ok((&b""[..], 64))); - assert_eq!(length_specifier(b"\xff\xff"), Ok((&b""[..], 49215))); + assert_eq!( + length_specifier(b"\xff\xff"), + Ok((&b""[..], EngineMessage::MAX_LEN)) + ); } #[test] fn parse_synced_messages() { - assert_eq!(message(b"\x03L\x01\x02"), Ok((&b""[..], Synced(Left(Press), 258)))); + assert_eq!( + message(b"\x03L\x01\x02"), + Ok((&b""[..], Synced(Left(Press), 258))) + ); assert_eq!(message(b"\x01#"), Ok((&b""[..], Synced(TimeWrap, 65535)))); } #[test] fn parse_unsynced_messages() { - assert_eq!(message(b"\x0aesay hello"), Ok((&b""[..], Unsynced(Say(String::from("hello")))))); + assert_eq!( + message(b"\x06shello"), + Ok((&b""[..], Unordered(ChatMessage(String::from("hello"))))) + ); } #[test] @@ -139,14 +159,9 @@ #[test] fn parse_config_messages() { - assert_eq!( - message(b"\x01C"), - Ok(( - &b""[..], - Config(ConfigRequest) - )) - ); + assert_eq!(message(b"\x01C"), Ok((&b""[..], Config(ConfigRequest)))); } + #[test] fn parse_test_general() { assert_eq!(string_tail(b"abc"), Ok((&b""[..], String::from("abc"))));