rust/hedgewars-engine-messages/src/lib.rs
author unC0Rr
Tue, 13 Nov 2018 16:54:40 +0100
changeset 14227 257b296169a8
parent 14226 a8fe9cd51154
child 14230 ab1ef7074e07
permissions -rw-r--r--
Start working on engine messages parser

use nom::*;
use std::str;

#[derive(Debug, PartialEq)]
pub enum KeystrokeAction {
    Press,
    Release,
}

#[derive(Debug, PartialEq)]
pub enum SyncedEngineMessage {
    Left(KeystrokeAction),
    Right(KeystrokeAction),
    Up(KeystrokeAction),
    Down(KeystrokeAction),
    Precise(KeystrokeAction),
    Attack(KeystrokeAction),
    NextTurn,
    Switch,
    Timer(u8),
    Slot(u8),
    SetWeapon(u8),
    Put(i32, i32),
    HighJump,
    LowJump,
    Skip,
    TeamControlGained(String),
    TeamControlLost(String),
}

#[derive(Debug, PartialEq)]
pub enum UnsyncedEngineMessage {
    Ping,
    Pong,
    Say(String),
    Taunt(u8),
    GameType(u8),
    Warning(String),
    StopSyncing,
    GameOver,
    GameInterrupted,
    GameSetupChecksum(String),
}

#[derive(Debug, PartialEq)]
pub enum ConfigEngineMessage {
    ConfigRequest,
    SetAmmo(String),
    SetScript(String),
    SetScriptParam(String),
    Spectate,
    TeamLocality(bool),
    SetMap(String),
    SetTheme(String),
    SetSeed(String),
    SetTemplateFilter(String),
    SetMapGenerator(String),
    SetFeatureSize(u8),
    SetDelay(u32),
    SetReadyDelay(u32),
    SetCratesFrequency(u8),
    SetHealthCrateProbability(u8),
    SetHealthCratesNumber(u8),
    SetRoundsTilSuddenDeath(u8),
    SetSuddenDeathWaterRiseSpeed(u8),
    SetSuddenDeathHealthDecreaseRate(u8),
    SetDamageMultiplier(u32),
    SetRopeLength(u32),
    SetGetawayTime(u32),
    SetDudMinesPercent(u8),
    SetMinesNumber(u32),
    SetAirMinesNumber(u32),
    SetBarrelsNumber(u32),
    SetTurnTime(u32),
    SetMinesTime(u32),
    SetWorldEdge(u8),
    Draw,
    // TODO
    SetVoicePack(String),
    AddHedgehog(String, u8, u32),
    AddTeam(String, u8),
    SetHedgehogCoordinates(i32, i32),
    SetFort(String),
    SetGrave(String),
    SetHat(String),
    SetFlag(String),
    SetOwner(String),
    SetOneClanMode(bool),
    SetMultishootMode(bool),
    SetSolidLand(bool),
    SetBorders(bool),
    SetDivideTeams(bool),
    SetLowGravity(bool),
    SetLaserSight(bool),
    SetInvulnerability(bool),
    SetHealthReset(bool),
    SetVampiric(bool),
    SetKarma(bool),
    SetArtilleryMode(bool),
    SetHedgehogSwitch(bool),
    SetRandomOrder(bool),
    SetKingMode(bool),
    SetPlaceHedgehog(bool),
    SetSharedAmmo(bool),
    SetGirdersEnabled(bool),
    SetLandObjectsEnabled(bool),
    SetAISurvivalMode(bool),
    SetInfiniteAttack(bool),
    SetResetWeapons(bool),
    SetAmmoPerHedgehog(bool),
    SetWindMode(u8),
    SetTagTeam(bool),
    SetBottomBorder(bool),
    SetShoppaBorder(bool),
}

#[derive(Debug, PartialEq)]
pub enum EngineMessage {
    Synced(SyncedEngineMessage, u32),
    Unsynced(UnsyncedEngineMessage),
    Config(ConfigEngineMessage),
    Unknown,
    Empty,
}

impl EngineMessage {
    fn from_bytes(buf: &[u8]) -> Self {
        unimplemented!()
    }

    fn to_bytes(&self) -> Vec<u8> {
        unimplemented!()
    }
}

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)
    )
);

named!(unrecognized_message<&[u8], EngineMessage>,
    do_parse!(rest >> (EngineMessage::Unknown))
);

named!(string_tail<&[u8], String>, map!(map_res!(rest, str::from_utf8), String::from));

named!(synced_message<&[u8], SyncedEngineMessage>, alt!(
      do_parse!(tag!("+l") >> (SyncedEngineMessage::Left(KeystrokeAction::Press)))
));

named!(unsynced_message<&[u8], UnsyncedEngineMessage>, alt!(
      do_parse!(tag!("?") >> (UnsyncedEngineMessage::Ping))
    | do_parse!(tag!("!") >> (UnsyncedEngineMessage::Ping))
    | do_parse!(tag!("esay ") >> s: string_tail  >> (UnsyncedEngineMessage::Say(s)))
));

named!(config_message<&[u8], ConfigEngineMessage>, alt!(
    do_parse!(tag!("C") >> (ConfigEngineMessage::ConfigRequest))
));

named!(empty_message<&[u8], EngineMessage>,
    do_parse!(tag!("\0") >> (EngineMessage::Empty))
);

named!(non_empty_message<&[u8], EngineMessage>, length_value!(length_specifier,
    alt!(
          map!(synced_message, |m| EngineMessage::Synced(m, 0))
        | map!(unsynced_message, |m| EngineMessage::Unsynced(m))
        | map!(config_message, |m| EngineMessage::Config(m))
        | unrecognized_message
    )
));

named!(message<&[u8], EngineMessage>, alt!(
      empty_message
    | non_empty_message
    )
);

named!(pub extract_messages<&[u8], Vec<EngineMessage> >, many0!(complete!(message)));

#[test]
fn parse_length() {
    assert_eq!(length_specifier(b"\x01"), Ok((&b""[..], 1)));
    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)));
}

#[test]
fn parse_synced_messages() {
    assert_eq!(message(b"\x02+l"), Ok((&b""[..], EngineMessage::Synced(SyncedEngineMessage::Left(KeystrokeAction::Press), 0))));
}

#[test]
fn parse_unsynced_messages() {
    assert_eq!(message(b"\x0aesay hello"), Ok((&b""[..], EngineMessage::Unsynced(UnsyncedEngineMessage::Say(String::from("hello"))))));
}

#[test]
fn parse_incorrect_messages() {
    assert_eq!(message(b"\x00"), Ok((&b""[..], EngineMessage::Empty)));
    assert_eq!(message(b"\x01\x00"), Ok((&b""[..], EngineMessage::Unknown)));
}

#[test]
fn parse_config_messages() {
    assert_eq!(
        message(b"\x01C"),
        Ok((
            &b""[..],
            EngineMessage::Config(ConfigEngineMessage::ConfigRequest)
        ))
    );
}
#[test]
fn parse_test_general() {
    assert_eq!(string_tail(b"abc"), Ok((&b""[..], String::from("abc"))));
}