b34945c2d2
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>
83 lines
3.3 KiB
C#
83 lines
3.3 KiB
C#
using Unity.Entities;using Unity.Mathematics;
|
|
|
|
|
|
namespace ProjectM.Simulation
|
|
{
|
|
/// <summary>
|
|
/// Pure, deterministic merge logic for a shared storage container's <see cref="StorageEntry"/> buffer.
|
|
/// No RNG / wall-clock, so server and (future) prediction agree. Deposit merges into an existing row
|
|
/// for the same item or appends a new row; Withdraw decrements and drops a row that hits zero, clamping
|
|
/// to available. DynamicBuffer is a handle, so mutations apply to the underlying entity buffer.
|
|
/// Unit-tested in EditMode via a plain Entities world.
|
|
/// </summary>
|
|
public static class StorageMath
|
|
{
|
|
/// <summary>Add <paramref name="count"/> of <paramref name="itemId"/>, merging into an existing row if present. No-op for count <= 0 or itemId 0.</summary>
|
|
public static void Deposit(DynamicBuffer<StorageEntry> buffer, ushort itemId, int count)
|
|
{
|
|
if (count <= 0 || itemId == 0)
|
|
return;
|
|
|
|
for (int i = 0; i < buffer.Length; i++)
|
|
{
|
|
if (buffer[i].ItemId == itemId)
|
|
{
|
|
var entry = buffer[i];
|
|
entry.Count += count;
|
|
buffer[i] = entry;
|
|
return;
|
|
}
|
|
}
|
|
|
|
buffer.Add(new StorageEntry { ItemId = itemId, Count = count });
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove up to <paramref name="count"/> of <paramref name="itemId"/>, clamped to what is available.
|
|
/// Drops the row when it reaches zero. Returns the amount actually withdrawn (0 if none). No-op for
|
|
/// count <= 0 or itemId 0.
|
|
/// </summary>
|
|
public static int Withdraw(DynamicBuffer<StorageEntry> buffer, ushort itemId, int count)
|
|
{
|
|
if (count <= 0 || itemId == 0)
|
|
return 0;
|
|
|
|
for (int i = 0; i < buffer.Length; i++)
|
|
{
|
|
if (buffer[i].ItemId == itemId)
|
|
{
|
|
var entry = buffer[i];
|
|
int taken = entry.Count < count ? entry.Count : count;
|
|
entry.Count -= taken;
|
|
if (entry.Count <= 0)
|
|
buffer.RemoveAt(i);
|
|
else
|
|
buffer[i] = entry;
|
|
return taken;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>Total count of <paramref name="itemId"/> across the buffer (0 if absent / itemId 0). EB-2 ledger
|
|
/// affordability read; mirrors MachineSlotMath.TotalOf. Pure, non-generic, Burst-safe.</summary>
|
|
public static int TotalOf(DynamicBuffer<StorageEntry> buffer, ushort itemId)
|
|
{
|
|
if (itemId == 0)
|
|
return 0;
|
|
int total = 0;
|
|
for (int i = 0; i < buffer.Length; i++)
|
|
if (buffer[i].ItemId == itemId)
|
|
total += buffer[i].Count;
|
|
return total;
|
|
}
|
|
|
|
/// <summary>END-1 soft-loss penalty: remove a FRACTION (0..1) of EVERY row, floored per row, dropping any
|
|
/// row that hits zero. Pure/deterministic (no RNG, no wall-clock), Burst-safe; iterates back-to-front so a
|
|
/// dropped row never skips its successor. No-op for fraction <= 0.</summary>
|
|
|
|
|
|
}
|
|
}
|