Hygiene B3: single-sourcing & magic-number consolidation

- StructureCatalogAuthoring: WallCostOre -> WallCostBiomass (it bakes a Biomass cost; [FormerlySerializedAs] preserves the scene value).
- Harvester/Fabricator authoring: resource-id byte defaults reference ResourceId.Ore/.Charge instead of magic 2/4.
- RegionMath.RegionBoundaryX (= ExpeditionOffsetX*0.5) single-sources the region-flip X used by HudSystem + OnboardingSystem (was 500f in 3 places).
- CharacterComponent.DefaultGroundedSharpness single-sources the CC sharpness 15f (GetDefault, DashSystem, PlayerDeathStateSystem, PlayerCharacterAuthoring).
- InventorySlot [InternalBufferCapacity] references Tuning.InventoryMaxSlots.
- ConnectionMode enum -> byte-const class (project convention; removes the latent enum-in-Burst trap); field + one Seed() param become byte.
- Tuning.ChargerWindupTicks single-sources the Charger telegraph windup (EnemyBaker + TuningConfig.Defaults; was a bare 30 that could drift).
- (TicksPerSecond deliberately NOT added: no seconds->ticks conversion site exists; the tick-count fields are per-authoring designer tunables, so a const would be unreferenced.)

451/451 EditMode tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 23:29:43 -07:00
parent 589e712db3
commit ba303e5fd0
16 changed files with 37 additions and 21 deletions
@@ -15,10 +15,10 @@ namespace ProjectM.Authoring
public class FabricatorAuthoring : MonoBehaviour
{
[Tooltip("Input resource id consumed per run (1=Aether, 2=Ore, 3=Biomass).")]
public byte InResourceId = 2; // Ore
public byte InResourceId = ResourceId.Ore;
[Min(1)] public int InAmount = 1;
[Tooltip("Output resource id deposited to the global ledger (4 = EB-2 Charge / turret ammo).")]
public byte OutResourceId = 4; // Charge
public byte OutResourceId = ResourceId.Charge;
[Min(1)] public int OutAmount = 3;
[Min(1)] public int PeriodTicks = 30;
[Tooltip("EB-2: 1 = ledger-fed (consume the input from the shared ledger; no conveyor). 0 = M7 MachineInput chain.")]
@@ -13,7 +13,7 @@ namespace ProjectM.Authoring
public class HarvesterAuthoring : MonoBehaviour
{
[Tooltip("Resource id this generator produces (1=Aether, 2=Ore, 3=Biomass).")]
public byte OutputResourceId = 2; // Ore
public byte OutputResourceId = ResourceId.Ore;
[Min(1)] public int Yield = 1;
[Min(1)] public int PeriodTicks = 60;
@@ -1,6 +1,7 @@
using ProjectM.Simulation;
using Unity.Entities;
using UnityEngine;
using UnityEngine.Serialization;
namespace ProjectM.Authoring
{
@@ -23,8 +24,8 @@ namespace ProjectM.Authoring
[Tooltip("Wall structure ghost prefab (StructureAuthoring{Wall} + GhostAuthoring).")]
public GameObject WallPrefab;
[Tooltip("Ore cost to build a wall.")]
[Min(0)] public int WallCostOre = 4;
[Tooltip("Biomass cost to build a wall.")]
[Min(0)] [FormerlySerializedAs("WallCostOre")] public int WallCostBiomass = 4;
[Tooltip("Pylon cosmetic-beacon ghost prefab (StructureAuthoring{Pylon} + GhostAuthoring).")]
public GameObject PylonPrefab;
@@ -69,7 +70,7 @@ namespace ProjectM.Authoring
Type = StructureType.Wall,
Prefab = GetEntity(authoring.WallPrefab, TransformUsageFlags.Dynamic),
CostResourceId = ResourceId.Biomass, // DR-042 C6b: walls cost Biomass (the dead currency's only sink)
CostAmount = authoring.WallCostOre,
CostAmount = authoring.WallCostBiomass,
});
}
@@ -66,7 +66,7 @@ namespace ProjectM.Authoring
// {ChargerAuthoring(LungeState), SpitterAuthoring(SpitterState)} — both would match ZERO AI passes.
if (GetComponent<ChargerAuthoring>() != null && spitter != null)
Debug.LogError($"Enemy '{authoring.name}' has BOTH ChargerAuthoring and SpitterAuthoring; it would match no AI pass and never move. Remove one.", authoring);
if (GetComponent<ChargerAuthoring>() != null) { kind = ZoneEnemyMath.KindCharger; windup = 30; }
if (GetComponent<ChargerAuthoring>() != null) { kind = ZoneEnemyMath.KindCharger; windup = (byte)Tuning.ChargerWindupTicks; }
else if (spitter != null) { kind = ZoneEnemyMath.KindSpitter; windup = (byte)Mathf.Clamp(spitter.WindupTicks, 1, 255); }
else if (GetComponent<SwarmerAuthoring>() != null) { kind = ZoneEnemyMath.KindSwarmer; windup = (byte)Tuning.AttackWindupTicks; /* B4: match the server windup (grunt-path swarmers use GruntWindupTicks); baked 6 was a snap-ramp lie */ }
AddComponent(entity, new EnemyTelegraph { WindupTicks = windup, Kind = kind });
@@ -24,7 +24,7 @@ namespace ProjectM.Authoring
public class PlayerCharacterAuthoring : MonoBehaviour
{
[Tooltip("Sharpness of ground velocity smoothing (higher = snappier).")]
public float GroundedMovementSharpness = 15f;
public float GroundedMovementSharpness = CharacterComponent.DefaultGroundedSharpness;
public AuthoringKinematicCharacterProperties CharacterProperties = AuthoringKinematicCharacterProperties.GetDefault();