Free the last match's body animations before the next map loads

Every PersistentRemoteTree holds an Arc<SoldierBodyAnimation> (since
25c008b), which owns the match's player XAnimCatalog and BodyMeshCatalog.
reset_anim_for_match clears the other per-match animation state on
MatchInstalled and MatchTornDown, but not RemoteBodyTrees, and the trees'
only pruning (retain_live in pose_remote_bodies) runs once the next match
poses remote bodies. When a different map loads, load_prepared_match drops
the resident copy of the last match before walking the new one, and from
then until the first remote pose the trees alone keep the old match's
catalogs alive, through the peak of the next load.

Reset RemoteBodyTrees with the rest of the per-match state. The trees are
rebuilt when remote bodies are posed in the new match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
JohnM
2026-10-10 00:08:48 +08:00
parent 91217cd0ac
commit 3953364247
@@ -3,6 +3,7 @@ use frame::{MatchInstalled, MatchTornDown, SessionSwapApplied};
use net::ClientSet;
use crate::anim::fpv_prepared::PreparedFpv;
use crate::anim::remote_body::RemoteBodyTrees;
use crate::anim::scene_submission::AnimDObjSceneSkels;
use crate::occupancy::dyn_ent::{DynEntPhysClip, DynEntPhysWorld};
use crate::occupancy::fpv_present::{
@@ -24,6 +25,7 @@ pub(crate) fn reset_anim_for_match(
mut settled: ResMut<FpvHeldSettled>,
mut held_life: ResMut<FpvHeldLife>,
mut scene_skels: ResMut<AnimDObjSceneSkels>,
mut remote_trees: ResMut<RemoteBodyTrees>,
existing: Query<Entity, With<FpvPlacementRoot>>,
) {
let installs = installed.read().count();
@@ -42,6 +44,7 @@ pub(crate) fn reset_anim_for_match(
settled.0 = None;
held_life.0 = None;
*scene_skels = AnimDObjSceneSkels::default();
*remote_trees = RemoteBodyTrees::default();
for entity in &existing {
commands.entity(entity).try_despawn();