LANTERN purge: delete the superseded base/expedition shell (audit H1/H3/M5)
The 2026-08-06 audit found the shipping scene was still the abandoned co-op-Hades game with LANTERN combat bolted on, and that a third of the codebase was live code for a direction abandoned on 2026-07-13. Operator chose deletion over freezing: "everything is saved in source control if needed. I want the project to be clean." DELETED (~140 source files, Scripts 335->231, Tests 77->43): - Enemy variants + boss (H3). ChargerAuthoring / SpitterAuthoring / SwarmerAuthoring were attached to ZERO prefabs, so LungeState / SpitterState / SwarmerTag were never baked: ~272 lines of Bursted AI passes, BossAISystem (261 lines) and the whole MixBands escalation curve could not match a single chunk at runtime, while 734 lines of green tests certified them. Both shipping enemy prefabs were already byte-identical in stats. - Run/room lifecycle: RunDirector FSM, RunInfo/RunMap/RoomPlan/RoomTag, route select, portal interact, ready-check, room field/teardown. - Meta shop, prep loadout, boons (incl. KillRewardSystem and DashTrailDamageSystem, which existed only to serve boon flags). - Build palette + structures, shared storage, inventory/equipment (already recorded PAUSED in CLAUDE.md). - The HUD panels driving all of the above (HudSystem 1168 -> 610). KEPT deliberately: BaseGridMath + BaseAnchor (8 systems use PlotCenter for spawn rings, respawn and dynamic light), the resource ledger + StorageMath, the save system, region/relevancy. Three of these were in the delete set until I checked their consumers — worth remembering that the file-level manifest was wrong about them. Also folds in audit finding M5: PlayerClass was a second, server-only copy of the byte FrameId already replicates. It existed for the meta shop; with that gone, FrameId is the single frame identity. Harvest is now single-sink (ledger). HarvestMath keeps its shape so LANTERN's carried-vs-banked cargo split lands in one place, not two. 295/295 EditMode green, zero compile errors. Subscene re-bake and Play validation follow in the next commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,8 +21,6 @@ namespace ProjectM.Simulation
|
||||
public uint Stamp;
|
||||
public uint KnockUntil;
|
||||
public bool IsFinisher; // Phase 1.7: this swing is the combo finisher
|
||||
public bool Detonate; // Phase 1.7: attacker has the FinisherDetonate boon
|
||||
public bool Pull; // Phase 1.7: attacker has the KnockToPull boon
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -52,12 +50,8 @@ namespace ProjectM.Simulation
|
||||
public partial struct MeleeComboSystem : ISystem
|
||||
{
|
||||
ComponentLookup<KnockbackState> m_KnockbackLookup;
|
||||
ComponentLookup<BossState> m_BossLookup; // A4: the boss is knockback-immune (no melee stunlock out of its slams)
|
||||
|
||||
ComponentLookup<RegionTag> m_RegionLookup;
|
||||
BufferLookup<InventorySlot> m_InvLookup;
|
||||
BufferLookup<StatModifier> m_StatModLookup;
|
||||
ComponentLookup<BoonEffects> m_BoonEffectsLookup; // Phase 1.7 (player query is at the 7-type cap -> lookup)
|
||||
ComponentLookup<MeleeCleavePending> m_PendingLookup; // 07-20 G2.1 scheduled cleave (query at cap -> lookup)
|
||||
|
||||
/// <summary>Phase 1.7 Detonating Finisher blast radius (planar, tunable).</summary>
|
||||
@@ -69,7 +63,7 @@ namespace ProjectM.Simulation
|
||||
/// (G2.2); damage/knockback keep the classic finisher mult.</summary>
|
||||
static PendingCleave BuildCleave(byte step, byte comboLen, float baseDamage, float baseRange, float knockSpeed,
|
||||
float finisherMult, float finisherRangeMult, uint stamp, uint knockUntil, float3 from, float2 aim,
|
||||
float2 facingDir, int ownerId, byte bflags, bool hasMods, DynamicBuffer<StatModifier> mods)
|
||||
float2 facingDir, int ownerId, bool hasMods, DynamicBuffer<StatModifier> mods)
|
||||
{
|
||||
bool fin = step >= comboLen;
|
||||
float d = math.max(0f, hasMods ? StatMath.Apply(baseDamage, StatTarget.MeleeDamage, mods) : baseDamage);
|
||||
@@ -85,8 +79,7 @@ namespace ProjectM.Simulation
|
||||
Stamp = stamp,
|
||||
KnockUntil = knockUntil,
|
||||
IsFinisher = fin,
|
||||
Detonate = (bflags & BoonFlag.FinisherDetonate) != 0,
|
||||
Pull = (bflags & BoonFlag.KnockToPull) != 0,
|
||||
// Detonate/Pull came from boon flags (deleted 2026-08-07 audit purge).
|
||||
};
|
||||
}
|
||||
|
||||
@@ -94,12 +87,8 @@ namespace ProjectM.Simulation
|
||||
public void OnCreate(ref SystemState state)
|
||||
{
|
||||
m_KnockbackLookup = state.GetComponentLookup<KnockbackState>(isReadOnly: false);
|
||||
m_BossLookup = state.GetComponentLookup<BossState>(isReadOnly: true);
|
||||
|
||||
m_RegionLookup = state.GetComponentLookup<RegionTag>(isReadOnly: true);
|
||||
m_InvLookup = state.GetBufferLookup<InventorySlot>(isReadOnly: false);
|
||||
m_StatModLookup = state.GetBufferLookup<StatModifier>(isReadOnly: true);
|
||||
m_BoonEffectsLookup = state.GetComponentLookup<BoonEffects>(isReadOnly: true);
|
||||
m_PendingLookup = state.GetComponentLookup<MeleeCleavePending>(isReadOnly: false);
|
||||
state.RequireForUpdate<NetworkTime>();
|
||||
}
|
||||
@@ -134,7 +123,6 @@ namespace ProjectM.Simulation
|
||||
// when at least one swing actually started — no per-tick enemy gather on idle/client ticks).
|
||||
var cleaves = isServer ? new NativeList<PendingCleave>(Allocator.Temp) : default;
|
||||
m_StatModLookup.Update(ref state);
|
||||
m_BoonEffectsLookup.Update(ref state); // Phase 1.7: per-player boon flags (read inside the player loop)
|
||||
m_PendingLookup.Update(ref state); // 07-20 G2.1: scheduled cleave slots (server-only writes)
|
||||
|
||||
foreach (var (mc, control, input, facing, xform, owner, ds, entity) in
|
||||
@@ -164,7 +152,6 @@ namespace ProjectM.Simulation
|
||||
cleaves.Add(BuildCleave(pend.Step, comboLen, baseDamage, baseRange, knockSpeed,
|
||||
finisherMult, finisherRangeMult, stamp, knockUntil, xform.ValueRO.Position,
|
||||
input.ValueRO.Aim, facing.ValueRO.Direction, owner.ValueRO.NetworkId,
|
||||
m_BoonEffectsLookup.HasComponent(entity) ? m_BoonEffectsLookup[entity].Flags : (byte)0,
|
||||
m_StatModLookup.HasBuffer(entity), m_StatModLookup.HasBuffer(entity) ? m_StatModLookup[entity] : default));
|
||||
m_PendingLookup[entity] = default;
|
||||
}
|
||||
@@ -237,7 +224,6 @@ namespace ProjectM.Simulation
|
||||
cleaves.Add(BuildCleave(pend.Step, comboLen, baseDamage, baseRange, knockSpeed,
|
||||
finisherMult, finisherRangeMult, stamp, knockUntil, xform.ValueRO.Position,
|
||||
input.ValueRO.Aim, facing.ValueRO.Direction, owner.ValueRO.NetworkId,
|
||||
m_BoonEffectsLookup.HasComponent(entity) ? m_BoonEffectsLookup[entity].Flags : (byte)0,
|
||||
m_StatModLookup.HasBuffer(entity), m_StatModLookup.HasBuffer(entity) ? m_StatModLookup[entity] : default));
|
||||
m_PendingLookup[entity] = new MeleeCleavePending { ResolveTick = TickUtil.NonZero(now + ct), Step = swingStep };
|
||||
}
|
||||
@@ -246,7 +232,6 @@ namespace ProjectM.Simulation
|
||||
cleaves.Add(BuildCleave(swingStep, comboLen, baseDamage, baseRange, knockSpeed,
|
||||
finisherMult, finisherRangeMult, stamp, knockUntil, xform.ValueRO.Position,
|
||||
input.ValueRO.Aim, facing.ValueRO.Direction, owner.ValueRO.NetworkId,
|
||||
m_BoonEffectsLookup.HasComponent(entity) ? m_BoonEffectsLookup[entity].Flags : (byte)0,
|
||||
m_StatModLookup.HasBuffer(entity), m_StatModLookup.HasBuffer(entity) ? m_StatModLookup[entity] : default));
|
||||
}
|
||||
}
|
||||
@@ -273,14 +258,8 @@ namespace ProjectM.Simulation
|
||||
// pool) just like a base projectile hit. SERVER-ONLY (this whole block) — interpolated node ghosts
|
||||
// are never rolled back, so the deposit + destroy fire exactly once per swing.
|
||||
bool haveLedger = SystemAPI.TryGetSingletonEntity<ResourceLedger>(out var ledgerEntity);
|
||||
bool haveDb = SystemAPI.TryGetSingleton<ItemDatabase>(out var itemDb);
|
||||
DynamicBuffer<StorageEntry> ledger = default;
|
||||
if (haveLedger) ledger = SystemAPI.GetBuffer<StorageEntry>(ledgerEntity);
|
||||
m_RegionLookup.Update(ref state);
|
||||
m_InvLookup.Update(ref state);
|
||||
var meleePlayerByConn = new NativeHashMap<int, Entity>(8, Allocator.Temp);
|
||||
foreach (var (po, pe) in SystemAPI.Query<RefRO<GhostOwner>>().WithAll<PlayerTag, InventorySlot>().WithEntityAccess())
|
||||
meleePlayerByConn[po.ValueRO.NetworkId] = pe;
|
||||
var harvEntity = new NativeList<Entity>(Allocator.Temp);
|
||||
var harvPos = new NativeList<float3>(Allocator.Temp);
|
||||
var harvRemaining = new NativeList<int>(Allocator.Temp);
|
||||
@@ -288,7 +267,6 @@ namespace ProjectM.Simulation
|
||||
var harvPerHit = new NativeList<float>(Allocator.Temp);
|
||||
var harvIsClutter = new NativeList<bool>(Allocator.Temp);
|
||||
var harvVariant = new NativeList<byte>(Allocator.Temp);
|
||||
var harvToLedger = new NativeList<bool>(Allocator.Temp);
|
||||
foreach (var (hx, node, he) in
|
||||
SystemAPI.Query<RefRO<LocalTransform>, RefRO<ResourceNode>>().WithEntityAccess())
|
||||
{
|
||||
@@ -301,7 +279,6 @@ namespace ProjectM.Simulation
|
||||
harvPerHit.Add(node.ValueRO.HarvestPerHit);
|
||||
harvIsClutter.Add(false);
|
||||
harvVariant.Add(0);
|
||||
harvToLedger.Add(m_RegionLookup.HasComponent(he) && m_RegionLookup[he].Region == RegionId.Base);
|
||||
}
|
||||
foreach (var (hx, clutter, he) in
|
||||
SystemAPI.Query<RefRO<LocalTransform>, RefRO<BlightClutter>>().WithEntityAccess())
|
||||
@@ -315,13 +292,11 @@ namespace ProjectM.Simulation
|
||||
harvPerHit.Add(clutter.ValueRO.ScrapPerHit);
|
||||
harvIsClutter.Add(true);
|
||||
harvVariant.Add(clutter.ValueRO.Variant);
|
||||
harvToLedger.Add(m_RegionLookup.HasComponent(he) && m_RegionLookup[he].Region == RegionId.Base);
|
||||
}
|
||||
var harvDestroyed = new NativeArray<bool>(harvEntity.Length, Allocator.Temp);
|
||||
|
||||
|
||||
m_KnockbackLookup.Update(ref state);
|
||||
m_BossLookup.Update(ref state);
|
||||
|
||||
var ecb = new EntityCommandBuffer(Allocator.Temp);
|
||||
for (int s = 0; s < cleaves.Length; s++)
|
||||
@@ -339,29 +314,8 @@ namespace ProjectM.Simulation
|
||||
SourceTick = c.Stamp,
|
||||
});
|
||||
if (c.KnockSpeed > 0f)
|
||||
KnockbackUtil.Stamp(ref m_KnockbackLookup, m_BossLookup, target,
|
||||
c.From, enemyPositions[i], c.Face, c.KnockSpeed, c.KnockUntil, c.Pull);
|
||||
}
|
||||
}
|
||||
// Phase 1.7 Detonating Finisher: a finisher swing with the boon blasts a planar AoE around its
|
||||
// origin (mirrors HazardExplosionSystem). Cone+blast overlap is the normal DamageEvent-summation.
|
||||
for (int s = 0; s < cleaves.Length; s++)
|
||||
{
|
||||
var dc = cleaves[s];
|
||||
if (!dc.IsFinisher || !dc.Detonate)
|
||||
continue;
|
||||
float detRadSq = k_DetonateRadius * k_DetonateRadius;
|
||||
for (int i = 0; i < enemyEntities.Length; i++)
|
||||
{
|
||||
float2 dd = new float2(enemyPositions[i].x - dc.From.x, enemyPositions[i].z - dc.From.z);
|
||||
if (math.lengthsq(dd) > detRadSq)
|
||||
continue;
|
||||
ecb.AppendToBuffer(enemyEntities[i], new DamageEvent
|
||||
{
|
||||
Amount = dc.Damage,
|
||||
SourceNetworkId = dc.OwnerId,
|
||||
SourceTick = dc.Stamp,
|
||||
});
|
||||
KnockbackUtil.Stamp(ref m_KnockbackLookup, target,
|
||||
c.From, enemyPositions[i], c.Face, c.KnockSpeed, c.KnockUntil);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,17 +337,12 @@ namespace ProjectM.Simulation
|
||||
// zero means ZERO (cover); any POSITIVE yield still credits >= 1 (the fractional-yield guard).
|
||||
int deposit = harvPerHit[i] > 0f ? amount : 0;
|
||||
byte yieldId = harvYieldId[i];
|
||||
// Route by region: Base nodes credit the shared ledger DIRECTLY (the build pool); an
|
||||
// expedition / un-tagged target goes to the swinging player's PERSONAL inventory (spill to
|
||||
// ledger), mirroring ResourceHarvestSystem. Only deplete if the yield landed somewhere —
|
||||
// never consume a node for zero credit (e.g. no ledger singleton present).
|
||||
Entity meleeHarvester = Entity.Null;
|
||||
if (meleePlayerByConn.TryGetValue(hc.OwnerId, out var meleePlayer))
|
||||
meleeHarvester = meleePlayer;
|
||||
// All yield credits the shared ledger — the PERSONAL inventory sink was deleted with the
|
||||
// superseded shell (2026-08-07 audit). Only deplete if the yield landed somewhere; never
|
||||
// consume a node for zero credit (e.g. no ledger singleton present).
|
||||
if (deposit > 0)
|
||||
{
|
||||
bool deposited = HarvestMath.DepositYield(yieldId, deposit, harvToLedger[i], meleeHarvester,
|
||||
m_InvLookup, ledger, haveLedger, haveDb, itemDb);
|
||||
bool deposited = HarvestMath.DepositYield(yieldId, deposit, ledger, haveLedger);
|
||||
if (!deposited)
|
||||
continue; // never consume a YIELDING target for zero credit
|
||||
}
|
||||
@@ -455,8 +404,6 @@ namespace ProjectM.Simulation
|
||||
harvIsClutter.Dispose();
|
||||
harvVariant.Dispose();
|
||||
harvDestroyed.Dispose();
|
||||
harvToLedger.Dispose();
|
||||
meleePlayerByConn.Dispose();
|
||||
}
|
||||
|
||||
if (cleaves.IsCreated)
|
||||
|
||||
Reference in New Issue
Block a user