play spawns on the tick the command names
commands carry tick_when_given and execute_tick, so a spawn no longer lands the moment its turn message arrives. it is queued and released on its own tick while advance_to steps the battle one tick at a time, which is what makes the simulation reproducible from the command stream rather than from when packets happened to arrive. the per-tick object update goes in this loop next.
This commit is contained in:
parent
83a1dd2bd3
commit
d6cfc81c71
2 changed files with 33 additions and 7 deletions
|
|
@ -7,10 +7,15 @@ use tokio::sync::Mutex;
|
|||
pub struct BattleSession {
|
||||
mode: LogicGameMode,
|
||||
tick: i32,
|
||||
queued: Vec<(i32, Vec<LogicGameObjectEntry>)>,
|
||||
}
|
||||
impl BattleSession {
|
||||
pub fn new(mode: LogicGameMode) -> Self {
|
||||
Self { mode, tick: 0 }
|
||||
Self {
|
||||
mode,
|
||||
tick: 0,
|
||||
queued: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn mode(&self) -> &LogicGameMode {
|
||||
&self.mode
|
||||
|
|
@ -21,10 +26,31 @@ impl BattleSession {
|
|||
pub fn seconds(&self) -> i32 {
|
||||
self.tick / BATTLE_TICKS_PER_SECOND
|
||||
}
|
||||
pub fn queue(&mut self, at_tick: i32, entries: Vec<LogicGameObjectEntry>) {
|
||||
if entries.is_empty() {
|
||||
return;
|
||||
}
|
||||
self.queued.push((at_tick.max(self.tick + 1), entries));
|
||||
}
|
||||
pub fn advance_to(&mut self, tick: i32) {
|
||||
if tick > self.tick {
|
||||
self.tick = tick;
|
||||
self.mode.time.tick = tick;
|
||||
while self.tick < tick {
|
||||
self.tick += 1;
|
||||
self.release_queued(self.tick);
|
||||
}
|
||||
self.mode.time.tick = self.tick;
|
||||
}
|
||||
fn release_queued(&mut self, tick: i32) {
|
||||
let mut due = Vec::new();
|
||||
self.queued.retain(|(at, entries)| {
|
||||
if *at <= tick {
|
||||
due.extend(entries.iter().cloned());
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
for entry in due {
|
||||
self.mode.battle.objects.push(entry);
|
||||
}
|
||||
}
|
||||
pub fn is_finished(&self) -> bool {
|
||||
|
|
@ -95,6 +121,7 @@ impl BattleRegistry {
|
|||
executor: LogicLong,
|
||||
slot: i32,
|
||||
position: logic::battle::LogicVector2,
|
||||
at_tick: i32,
|
||||
summon: F,
|
||||
) -> usize
|
||||
where
|
||||
|
|
@ -112,9 +139,7 @@ impl BattleRegistry {
|
|||
};
|
||||
let entries = summon(&card, position, owner, session.next_instance());
|
||||
let spawned = entries.len();
|
||||
for entry in entries {
|
||||
session.push(entry);
|
||||
}
|
||||
session.queue(at_tick, entries);
|
||||
spawned
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ impl GameApi for GameService {
|
|||
played.header.executor_account_id,
|
||||
played.deck_slot,
|
||||
played.position,
|
||||
played.header.execute_tick,
|
||||
|card, position, owner, instance| {
|
||||
self.battles.summon(card, position, owner, 0, instance)
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue