e1ed08a803
Consolidate the divorced combat + economy halves into one base-local loop. BaseFieldSpawnSystem tops up RegionTag{Base} Ore nodes around the plot; harvest routes Base->shared ledger and Expedition/untagged->personal inventory for BOTH the projectile (ResourceHarvestSystem) and melee (MeleeComboSystem server-only block, writes Remaining back for VFX). Activate the reserved Schedule source in ThreatDirectorSystem so base sieges arm WITHOUT an expedition trip (the loop-closer: previously zero waves ever attacked a base-only player). Region-filter the ExpeditionFieldSystem teardown so it no longer wipes the permanent base field. HudSystem shows phase-aware loop copy. See DR-031.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
2.5 KiB
C#
47 lines
2.5 KiB
C#
using Unity.Entities;
|
|
|
|
namespace ProjectM.Simulation
|
|
{
|
|
/// <summary>
|
|
/// Baked singleton describing the HOME-BASE mining field: a ring of harvestable resource nodes scattered
|
|
/// around the base so the gather -> build -> survive loop lives on ONE screen (no expedition trip required).
|
|
/// DISTINCT from <see cref="ResourceFieldSpawner"/> (the expedition field) so the two never collide on a
|
|
/// GetSingleton. <see cref="ProjectM.Server.BaseFieldSpawnSystem"/> keeps the live RegionTag{Base} node count
|
|
/// topped up to <see cref="TargetCount"/> on a tick cadence; nodes scatter UNIFORMLY-IN-RADIUS in the annulus
|
|
/// [<see cref="InnerRadius"/>, <see cref="OuterRadius"/>] around BaseGridMath.PlotCenter (inner clears the
|
|
/// square build plot + spawn ring, outer stays inside the walkable boundary ring) and are overridden to
|
|
/// RegionTag{Base} + ResourceId.Ore (the sole build currency, kept legible — never the expedition's
|
|
/// Aether/Ore/Biomass round-robin). Place ONE authoring in the gameplay subscene.
|
|
/// </summary>
|
|
public struct BaseFieldSpawner : IComponentData
|
|
{
|
|
/// <summary>Baked resource-node ghost prefab to instantiate (reuses the expedition node prefab).</summary>
|
|
public Entity Prefab;
|
|
|
|
/// <summary>Desired live base-node count; the system refills toward this each respawn pass.</summary>
|
|
public int TargetCount;
|
|
|
|
/// <summary>Inner scatter radius (world units) from the plot center — must clear the build plot + spawn ring.</summary>
|
|
public float InnerRadius;
|
|
|
|
/// <summary>Outer scatter radius (world units) — must stay inside the boundary ring so nodes are reachable.</summary>
|
|
public float OuterRadius;
|
|
|
|
/// <summary>Server ticks between top-up passes (a depleted field refills toward TargetCount on this cadence).</summary>
|
|
public int RespawnIntervalTicks;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Server-only runtime state for <see cref="ProjectM.Server.BaseFieldSpawnSystem"/>, baked beside
|
|
/// <see cref="BaseFieldSpawner"/>. NOT replicated. <see cref="Epoch"/> seeds the per-node scatter RNG
|
|
/// (monotonic, so a top-up never repeats a layout); <see cref="NextSpawnTick"/> gates the cadence (wrap-safe
|
|
/// via TickUtil.NonZero + NetworkTick.IsNewerThan, never raw uint). NextSpawnTick == 0 means "fire now" so the
|
|
/// first pass seeds the field without waiting for a tick that never comes.
|
|
/// </summary>
|
|
public struct BaseFieldRuntime : IComponentData
|
|
{
|
|
public int Epoch;
|
|
public uint NextSpawnTick;
|
|
}
|
|
}
|