103 lines
2.7 KiB
Rust
103 lines
2.7 KiB
Rust
//! Rollback-simulated state for an active match.
|
|
|
|
use bevy::prelude::*;
|
|
use bevy_ggrs::prelude::*;
|
|
|
|
use crate::match_loading::{MatchConfig, MatchRules};
|
|
|
|
#[derive(Resource, Clone, Debug, Hash, PartialEq, Eq)]
|
|
pub struct MatchState {
|
|
pub elapsed_frames: u32,
|
|
/// Indexed by the player's session handle.
|
|
pub players: Vec<PlayerMatchState>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
|
pub struct PlayerMatchState {
|
|
pub stocks_remaining: Option<u8>,
|
|
pub score: i32,
|
|
pub deaths: u32,
|
|
}
|
|
|
|
impl MatchState {
|
|
pub fn from_config(config: &MatchConfig) -> Self {
|
|
let stocks_remaining = match &config.rules {
|
|
MatchRules::Stock {
|
|
starting_stocks, ..
|
|
} => Some(*starting_stocks),
|
|
MatchRules::Timed { .. } => None,
|
|
};
|
|
|
|
Self {
|
|
elapsed_frames: 0,
|
|
players: (0..config.players.len())
|
|
.map(|_| PlayerMatchState {
|
|
stocks_remaining,
|
|
score: 0,
|
|
deaths: 0,
|
|
})
|
|
.collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct MatchRuntimePlugin;
|
|
|
|
impl Plugin for MatchRuntimePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.rollback_resource_with_clone::<MatchState>()
|
|
.checksum_resource_with_hash::<MatchState>();
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::{fighter::FighterId, match_loading::MatchPlayer, stage::manifest::StageId};
|
|
|
|
fn config(rules: MatchRules) -> MatchConfig {
|
|
MatchConfig {
|
|
stage: StageId::TestStage,
|
|
players: vec![
|
|
MatchPlayer {
|
|
handle: 1,
|
|
fighter: FighterId::TestFighter,
|
|
},
|
|
MatchPlayer {
|
|
handle: 0,
|
|
fighter: FighterId::TestFighter,
|
|
},
|
|
],
|
|
rules,
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn stock_state_starts_with_configured_stocks() {
|
|
let state = MatchState::from_config(&config(MatchRules::Stock {
|
|
starting_stocks: 4,
|
|
time_limit_frames: Some(60),
|
|
}));
|
|
|
|
assert_eq!(state.elapsed_frames, 0);
|
|
assert_eq!(state.players.len(), 2);
|
|
assert!(state.players.iter().all(|player| {
|
|
player.stocks_remaining == Some(4) && player.score == 0 && player.deaths == 0
|
|
}));
|
|
}
|
|
|
|
#[test]
|
|
fn timed_state_has_no_stock_counter() {
|
|
let state = MatchState::from_config(&config(MatchRules::Timed {
|
|
time_limit_frames: 60,
|
|
}));
|
|
|
|
assert!(
|
|
state
|
|
.players
|
|
.iter()
|
|
.all(|player| player.stocks_remaining.is_none())
|
|
);
|
|
}
|
|
}
|