never reuse a global id

the client matches the objects in a snapshot against the ones it already
has by global id, and anything it cannot find it builds from scratch.
our next id was the highest one in play plus one, recomputed at every
spawn - so as soon as a unit died its id came free and the next spawn
took it. at five snapshots a second the client was destroying and
rebuilding models faster than they could appear, which is why units
fought and shot while invisible.

the counter is per battle now and only ever goes up, starting past the
towers.
This commit is contained in:
WiseDev 2026-08-23 14:17:50 +03:00
parent 64a457545d
commit cc92831d06

View file

@ -24,10 +24,20 @@ pub struct BattleSession {
next_snapshot: i32, next_snapshot: i32,
next_bot_play: i32, next_bot_play: i32,
pub pushed_snapshots: u32, pub pushed_snapshots: u32,
next_instance: i32,
pending_bot_play: Option<(LogicDataRef, LogicVector2, i32)>, pending_bot_play: Option<(LogicDataRef, LogicVector2, i32)>,
} }
impl BattleSession { impl BattleSession {
pub fn new(mode: LogicGameMode, taunts: Vec<LogicDataRef>) -> Self { pub fn new(mode: LogicGameMode, taunts: Vec<LogicDataRef>) -> Self {
let first_instance = mode
.battle
.objects
.objects
.iter()
.filter_map(|entry| entry.global_id.0.map(|id| id.instance_id))
.max()
.map(|last| last + 1)
.unwrap_or(0);
let mut random = LogicRandom::new(mode.random_seed); let mut random = LogicRandom::new(mode.random_seed);
let next_bot_emote = Self::roll_emote_tick(&mut random, 0); let next_bot_emote = Self::roll_emote_tick(&mut random, 0);
Self { Self {
@ -42,6 +52,7 @@ impl BattleSession {
next_snapshot: SNAPSHOT_INTERVAL_TICKS, next_snapshot: SNAPSHOT_INTERVAL_TICKS,
next_bot_play: crate::bot::BOT_OPENING_DELAY_SECONDS * BATTLE_TICKS_PER_SECOND, next_bot_play: crate::bot::BOT_OPENING_DELAY_SECONDS * BATTLE_TICKS_PER_SECOND,
pushed_snapshots: 0, pushed_snapshots: 0,
next_instance: first_instance,
pending_bot_play: None, pending_bot_play: None,
} }
} }
@ -258,16 +269,10 @@ impl BattleSession {
.position(|id| *id == account) .position(|id| *id == account)
.map(|index| index as i32) .map(|index| index as i32)
} }
pub fn next_instance(&self) -> i32 { pub fn next_instance(&mut self) -> i32 {
self.mode let instance = self.next_instance;
.battle self.next_instance += 1;
.objects instance
.objects
.iter()
.filter_map(|entry| entry.global_id.0.map(|id| id.instance_id))
.max()
.map(|last| last + 1)
.unwrap_or(0)
} }
pub fn deck_card(&self, owner: i32, slot: i32) -> Option<LogicDataRef> { pub fn deck_card(&self, owner: i32, slot: i32) -> Option<LogicDataRef> {
let deck = self.mode.battle.decks.get(owner.max(0) as usize)?.as_ref()?; let deck = self.mode.battle.decks.get(owner.max(0) as usize)?.as_ref()?;