give everything but the summoners a new id once the screen is up

the models came back last run, washed out, and the card art went white
with them: BattleScreen::startResourceLoading walks the battle's objects
to decide what to load, and an opening state holding only two towers
left it nothing to load. art needs the objects in the first state; the
model needs them to arrive after the screen exists. both, not either.

so everything ships up front for the art, and everything except the two
summoners is renumbered once the client speaks, which makes it new to
LogicGameObjectManager::decode and gets it through addGameObject with
its art already in memory. the summoners stay put because the hud holds
them raw at [SpellButton+0x1d0].

mana spending from the last commit is confirmed working in the log.
This commit is contained in:
WiseDev 2026-08-23 14:56:39 +03:00
parent 0c4d0965a6
commit ffabe6e497
2 changed files with 27 additions and 14 deletions

View file

@ -4,7 +4,8 @@ pub const SNAPSHOT_INTERVAL_TICKS: i32 = 4;
pub const MAX_CATCH_UP_TICKS: i32 = 40; pub const MAX_CATCH_UP_TICKS: i32 = 40;
use std::time::Instant; use std::time::Instant;
use logic::battle::{ use logic::battle::{
LogicGameMode, LogicGameObjectEntry, LogicVector2, BATTLE_TICKS_PER_SECOND, BATTLE_TYPE_PVP, LogicGameMode, LogicGameObjectEntry, LogicGameObjectRef, LogicVector2,
BATTLE_TICKS_PER_SECOND, BATTLE_TYPE_PVP, CHARACTER_OBJECT_TYPE,
}; };
use logic::battle::{verify_snapshot, LogicBattleEvent}; use logic::battle::{verify_snapshot, LogicBattleEvent};
use logic::SectorStateMessage; use logic::SectorStateMessage;
@ -58,21 +59,37 @@ impl BattleSession {
pending_bot_play: None, pending_bot_play: None,
} }
} }
fn opening(&self) -> LogicGameMode { fn reannounce(&mut self) {
let mut mode = self.mode.clone(); let leaders = self.mode.battle.leaders;
let leaders = mode.battle.leaders; let mut remap: Vec<(LogicGameObjectRef, LogicGameObjectRef)> = Vec::new();
mode.battle for entry in self.mode.battle.objects.objects.iter_mut() {
if leaders.contains(&entry.global_id) {
continue;
}
let fresh = LogicGameObjectRef::of(CHARACTER_OBJECT_TYPE + 1, self.next_instance);
self.next_instance += 1;
remap.push((entry.global_id, fresh));
entry.global_id = fresh;
}
for towers in self.mode.battle.leader_towers.iter_mut() {
for tower in towers.iter_mut() {
if let Some((_, now)) = remap.iter().find(|(was, _)| was == tower) {
*tower = *now;
}
}
}
self.mode
.battle
.objects .objects
.objects .objects
.retain(|entry| leaders.contains(&entry.global_id)); .sort_by_key(|entry| entry.global_id.0.map(|id| (id.class_id, id.instance_id)));
mode.battle.leader_towers = Default::default();
mode
} }
pub fn announce(&mut self) -> bool { pub fn announce(&mut self) -> bool {
if self.announced { if self.announced {
return false; return false;
} }
self.announced = true; self.announced = true;
self.reannounce();
self.next_snapshot = self.tick; self.next_snapshot = self.tick;
true true
} }
@ -146,11 +163,7 @@ impl BattleSession {
}) })
} }
pub fn snapshot_message(&mut self) -> Option<WireMessage> { pub fn snapshot_message(&mut self) -> Option<WireMessage> {
let snapshot = if self.announced { let snapshot = self.mode.snapshot().ok()?;
self.mode.snapshot().ok()?
} else {
self.opening().snapshot().ok()?
};
let report = verify_snapshot(&snapshot); let report = verify_snapshot(&snapshot);
let unit = self let unit = self
.mode .mode

View file

@ -161,7 +161,7 @@ impl GameService {
opponent = %opponent_name, opponent = %opponent_name,
location = %location, location = %location,
objects, objects,
"sending the opening sector state, objects follow once the client is up" "sending the opening sector state, objects get new ids once the client is up"
); );
Ok(vec![message]) Ok(vec![message])
} }