LANTERN purge B3+B5: delete the cycle/core/win-lose spine + onboarding; save epoch v7

Deletes CyclePhaseSystem, GoalReachedSystem, CoreDamage/CoreRestore, ThreatDirector,
CoreIntegrity/GoalProgress/RunPhase/RunOutcome/ThreatState components,
CoreVisualFeedbackSystem, and the whole Client/Onboarding slice (+6 test files).

Keepers reworked: RunDirectorSystem (UpdateBefore attr + launch guard + goal/threat
bank removed; sole SaveRequest raiser now), CycleDirectorSpawnSystem (ledger/meta
host only), WaveSystem UNGATED (waves run wherever a WaveDirector is baked),
EnemyAISystem core-fallback stripped, AmbientAudioSystem reworked (bed + run cues;
no CycleState gate), MusicSystem RunInfo-only, HudSystem big trim (goal meter, core
bar, siege banner, terminal banner, outcome flash, onboarding hook all gone),
MetaShop/ClassPrep/AimReticle siege gates dropped, DebugOverlay/ops re-meant
(SpawnWave=force next wave, EndSiege=quiet arena; SetCalm/AdvanceGoal/SetHeat
retired, bytes reserved), TuningConfig Core knobs retired (ids 20-23 reserved),
StorageMath.DrainFraction deleted, HowToPlay copy rewritten.

Save epoch v7 (fresh epoch, operator-approved): SaveData drops goal/core/outcome +
conveyor/machine-IO fields; MinLoadableVersion=7; PendingSave/PendingStructure
trimmed; RollTerminalCampaignForward deleted; SaveStructureScan signature slimmed.

390 tests green; Play world-creation clean (player + waves live, no exceptions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 15:27:12 -07:00
parent 835dace213
commit b34945c2d2
74 changed files with 233 additions and 3955 deletions
@@ -129,17 +129,11 @@ namespace ProjectM.Client
static void StagePendingSave(World server)
{
var data = SaveService.Load();
// A terminal (won/lost) save Continues as a FRESH campaign — base+meta kept, outcome/meter/core reset
// (else the dead outcome banner re-latches from the first snapshot).
SaveService.RollTerminalCampaignForward(data);
if (data == null) return;
var em = server.EntityManager;
var e = em.CreateEntity();
// v5->v6 migration (operator-approved): an old save's Charge counted boss-cleared runs (DR-042), so a
// missing RunsCompleted floors to it — the HUD never shows "Charge 3/4" beside "Runs completed: 0".
int runsCompleted = data.RunsCompleted > data.GoalCharge ? data.RunsCompleted : data.GoalCharge;
em.AddComponentData(e, new PendingSave { GoalCharge = data.GoalCharge, GoalTarget = data.GoalTarget, CoreCurrent = data.CoreCurrent, RunOutcome = (byte)data.RunOutcome, RunsCompleted = runsCompleted, MaxDepthReached = data.MaxDepthReached, HasData = 1 });
em.AddComponentData(e, new PendingSave { RunsCompleted = data.RunsCompleted, MaxDepthReached = data.MaxDepthReached, HasData = 1 });
// v6: stage the meta tiers UNCONDITIONALLY (empty OK — the Bursted spawn system GetBuffers it in the
// HasData block; a conditional buffer would throw on any v<=5 Continue). Rows verbatim, no clamping.
var mbuf = em.AddBuffer<PendingMetaRow>(e);
@@ -159,10 +153,6 @@ namespace ProjectM.Client
var sbuf = em.AddBuffer<PendingStructure>(se);
foreach (var s in data.Structures)
sbuf.Add(SaveApply.ToPending(s)); // EB-1: pure mapping (unit-tested, incl. the wounded HP)
var iobuf = em.AddBuffer<PendingStructureIo>(se);
if (data.StructureIo != null)
foreach (var io in data.StructureIo)
iobuf.Add(new PendingStructureIo { StructureIndex = io.StructureIndex, Slot = io.Slot, ResourceId = io.ResourceId, Count = io.Count });
}
}
@@ -175,9 +165,6 @@ namespace ProjectM.Client
using var q = em.CreateEntityQuery(ComponentType.ReadOnly<ResourceLedger>());
if (q.IsEmptyIgnoreFilter) return;
var dir = q.GetSingletonEntity();
var goal = em.HasComponent<GoalProgress>(dir) ? em.GetComponentData<GoalProgress>(dir) : default;
var core = em.HasComponent<CoreIntegrity>(dir) ? em.GetComponentData<CoreIntegrity>(dir) : default; // END-1
var outcome = em.HasComponent<RunOutcome>(dir) ? em.GetComponentData<RunOutcome>(dir) : default; // END-2
var buffer = em.GetBuffer<StorageEntry>(dir, true);
var rows = new LedgerRow[buffer.Length];
@@ -195,21 +182,16 @@ namespace ProjectM.Client
// v6: the permanent-meta slice via the ONE shared collector — omitting it HERE (the most common
// exit path) would silently WIPE all meta progression on quit (the meta review's top blocker).
MetaSaveScan.Collect(em, dir, out var metaRows, out var runsCompleted, out var maxDepth);
SaveStructureScan.Collect(em, nowTick, out var structures, out var structureIo);
SaveStructureScan.Collect(em, nowTick, out var structures);
SaveService.Save(new SaveData
{
GoalCharge = goal.Charge,
GoalTarget = goal.Target,
CoreCurrent = core.Current,
RunsCompleted = runsCompleted,
MaxDepthReached = maxDepth,
MetaUpgrades = metaRows,
RunOutcome = outcome.Value,
Ledger = rows,
Structures = structures,
StructureIo = structureIo,
SavedAtMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
});
}