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 {
|
pub struct BattleSession {
|
||||||
mode: LogicGameMode,
|
mode: LogicGameMode,
|
||||||
tick: i32,
|
tick: i32,
|
||||||
|
queued: Vec<(i32, Vec<LogicGameObjectEntry>)>,
|
||||||
}
|
}
|
||||||
impl BattleSession {
|
impl BattleSession {
|
||||||
pub fn new(mode: LogicGameMode) -> Self {
|
pub fn new(mode: LogicGameMode) -> Self {
|
||||||
Self { mode, tick: 0 }
|
Self {
|
||||||
|
mode,
|
||||||
|
tick: 0,
|
||||||
|
queued: Vec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn mode(&self) -> &LogicGameMode {
|
pub fn mode(&self) -> &LogicGameMode {
|
||||||
&self.mode
|
&self.mode
|
||||||
|
|
@ -21,10 +26,31 @@ impl BattleSession {
|
||||||
pub fn seconds(&self) -> i32 {
|
pub fn seconds(&self) -> i32 {
|
||||||
self.tick / BATTLE_TICKS_PER_SECOND
|
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) {
|
pub fn advance_to(&mut self, tick: i32) {
|
||||||
if tick > self.tick {
|
while self.tick < tick {
|
||||||
self.tick = tick;
|
self.tick += 1;
|
||||||
self.mode.time.tick = tick;
|
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 {
|
pub fn is_finished(&self) -> bool {
|
||||||
|
|
@ -95,6 +121,7 @@ impl BattleRegistry {
|
||||||
executor: LogicLong,
|
executor: LogicLong,
|
||||||
slot: i32,
|
slot: i32,
|
||||||
position: logic::battle::LogicVector2,
|
position: logic::battle::LogicVector2,
|
||||||
|
at_tick: i32,
|
||||||
summon: F,
|
summon: F,
|
||||||
) -> usize
|
) -> usize
|
||||||
where
|
where
|
||||||
|
|
@ -112,9 +139,7 @@ impl BattleRegistry {
|
||||||
};
|
};
|
||||||
let entries = summon(&card, position, owner, session.next_instance());
|
let entries = summon(&card, position, owner, session.next_instance());
|
||||||
let spawned = entries.len();
|
let spawned = entries.len();
|
||||||
for entry in entries {
|
session.queue(at_tick, entries);
|
||||||
session.push(entry);
|
|
||||||
}
|
|
||||||
spawned
|
spawned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,7 @@ impl GameApi for GameService {
|
||||||
played.header.executor_account_id,
|
played.header.executor_account_id,
|
||||||
played.deck_slot,
|
played.deck_slot,
|
||||||
played.position,
|
played.position,
|
||||||
|
played.header.execute_tick,
|
||||||
|card, position, owner, instance| {
|
|card, position, owner, instance| {
|
||||||
self.battles.summon(card, position, owner, 0, instance)
|
self.battles.summon(card, position, owner, 0, instance)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue