Stacking root cause: boxes that persisted from sessions before the
non-persistency change load into the world AFTER MissionServer.OnInit, so the
one-shot init cleanup missed them; they were untracked and never despawned, and
new boxes spawned on top.
- RemoveUntrackedBoxesAt(pos): deletes YALootBoxes_Base near a point that are
NOT in m_ActiveBoxes (skips live boxes via IsTrackedBox), so it is safe to
call any time.
- SpawnOneAtRandomFreeLocation now clears its exact location first, guaranteeing
one box per location and never stacking on a leftover.
- CleanupOrphanedBoxes now runs at startup AND at the start of every
TickLifecycle (self-healing), so ghosts that stream in late are removed within
one check interval. Radius tightened 5m -> 3m.
Despawn timers (per request): split into two main_config keys
- DespawnMinutes: locked/unopened box lifetime (per-type despawnMinutes still
overrides when > 0; default per-type is now 0 = use global).
- OpenedDespawnMinutes: lifetime after a box is opened.
Replaces the single DefaultDespawnMinutes. Lootbox uses GetLockedLifetimeMinutes
/ GetOpenedLifetimeMinutes accordingly. README/configfiles.readme + _comment docs
updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>