Skip to content

Commit

Permalink
Parse AI takeover commands.
Browse files Browse the repository at this point in the history
  • Loading branch information
ryantaylor committed Sep 11, 2024
1 parent 89e01d1 commit 324aba0
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 1 deletion.
Binary file added replays/ai_takeover.rec
Binary file not shown.
10 changes: 9 additions & 1 deletion src/command.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Wrapper for Company of Heroes 3 player commands.
use crate::{
command_data::{Pbgid, Sourced, SourcedIndex, SourcedPbgid, Unknown},
command_data::{Empty, Pbgid, Sourced, SourcedIndex, SourcedPbgid, Unknown},
command_type::CommandType,
data::ticks,
};
Expand All @@ -19,6 +19,7 @@ use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "magnus", magnus::wrap(class = "VaultCoh::Command"))]
pub enum Command {
AITakeover(Empty),
BuildGlobalUpgrade(SourcedPbgid),
BuildSquad(SourcedPbgid),
CancelConstruction(Sourced),
Expand All @@ -34,6 +35,13 @@ pub enum Command {
impl Command {
pub(crate) fn from_data_command_at_tick(command: ticks::Command, tick: u32) -> Self {
match command.data {
ticks::CommandData::Empty => match command.action_type {
CommandType::PCMD_AIPlayer => Self::AITakeover(Empty::new(tick)),
_ => panic!(
"an empty command isn't being handled here! command type {:?}",
command.action_type
),
},
ticks::CommandData::Pbgid(pbgid) => match command.action_type {
CommandType::PCMD_Ability => {
Self::UseBattlegroupAbility(Pbgid::new(tick, command.index, pbgid))
Expand Down
24 changes: 24 additions & 0 deletions src/command_data/empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// An empty command format with no additional context.
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Empty {
tick: u32,
}

impl Empty {
pub(crate) fn new(tick: u32) -> Self {
Self { tick }
}

/// This value is the tick at which the command was found while parsing the replay, which
/// represents the time in the replay at which it was executed. Because CoH3's engine runs at 8
/// ticks per second, you can divide this value by 8 to get the number of seconds since the
/// replay began, which will tell you when this command was executed.
pub fn tick(&self) -> u32 {
self.tick
}
}
2 changes: 2 additions & 0 deletions src/command_data/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! Representations of replay command data formats.
mod empty;
mod pbgid;
mod sourced;
mod sourced_index;
mod sourced_pbgid;
mod unknown;

pub use crate::command_data::empty::Empty;
pub use crate::command_data::pbgid::Pbgid;
pub use crate::command_data::sourced::Sourced;
pub use crate::command_data::sourced_index::SourcedIndex;
Expand Down
6 changes: 6 additions & 0 deletions src/data/ticks/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use nom::{

#[derive(Debug, Copy, Clone)]
pub enum CommandData {
Empty,
Pbgid(u32),
SourcedPbgid(u32, u16),
Sourced(u16),
Expand All @@ -20,6 +21,10 @@ pub enum CommandData {
}

impl CommandData {
pub fn parse_empty(input: Span) -> ParserResult<CommandData> {
map(rest, |_| CommandData::Empty)(input)
}

pub fn parse_pbgid(input: Span) -> ParserResult<CommandData> {
map(tuple((take(27u32), le_u32)), |(_, pbgid)| {
CommandData::Pbgid(pbgid)
Expand Down Expand Up @@ -56,6 +61,7 @@ impl CommandData {
command_type: CommandType,
) -> impl FnMut(Span) -> ParserResult<CommandData> {
match command_type {
CommandType::PCMD_AIPlayer => Self::parse_empty,
CommandType::PCMD_Ability
| CommandType::PCMD_InstantUpgrade
| CommandType::PCMD_TentativeUpgrade => Self::parse_pbgid,
Expand Down
7 changes: 7 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ fn parse_new_map_chunk() {
assert_eq!(replay.map_localized_description_id(), "$11233955");
}

#[test]
fn parse_ai_takeover() {
let data = include_bytes!("../replays/ai_takeover.rec");
let replay = Replay::from_bytes(data);
assert!(replay.is_ok());
}

#[test]
#[cfg_attr(not(feature = "regression"), ignore)]
fn regression() {
Expand Down

0 comments on commit 324aba0

Please sign in to comment.