using Unity.Entities; namespace ProjectM.Simulation { /// /// The ONE in-place frame-swap effect, shared by the editor dev tool (DebugOp.SetClass) and the player-facing /// frame select. Re-seeds the frame's stat band via ; the caller then writes /// FrameId/PlayerClass, re-seeds the socket loadout, and calls (a static can't resolve /// singletons or SystemAPI.SetComponent, so the caller passes the resolved pieces). Server-authoritative + /// prediction-correct (StatRecomputeSystem refolds EffectiveCharacterStats next tick). /// /// HISTORY (2026-08-07 audit purge): this also used to strip and replay a PERMANENT-META band /// (MetaUpgradeCatalog + MetaTierState) so an Aether-bought upgrade followed the frame across a swap. The meta /// shop belonged to the superseded base/expedition direction and was deleted; only the frame band remains. /// public static class ClassSwapUtil { /// Re-seed the frame stat band for on . /// Returns the normalized frame id (the caller writes FrameId/PlayerClass + re-seeds the socket /// loadout). public static void Apply(byte rawClass, DynamicBuffer mods, out byte newClass) { newClass = ClassTraits.Normalize(rawClass); ClassTraits.Reapply(newClass, mods); } /// Heal/down-clamp a LIVING player's Current to the new class's full max (blob base folded with the /// just-reseeded , like StatRecomputeSystem). Doubles as the down-clamp when the new /// class's max is lower (Bathynaut +30 HP vs Harpooner -15%). No-op on a corpse (Current<=0) — respawn refills. public static void HealClamp(ref Health health, float baseMaxHealth, DynamicBuffer mods) { if (health.Current > 0f) health.Current = StatMath.Apply(baseMaxHealth, StatTarget.MaxHealth, mods); } } }