86 lines
4.6 KiB
C#
86 lines
4.6 KiB
C#
using Unity.Entities;
|
|
|
|
namespace ProjectM.Simulation
|
|
{
|
|
/// <summary>
|
|
/// Baked, server-only tuning for the composite ThreatDirector (the data-driven base-attack scheduler). Lives
|
|
/// on the global CycleDirector entity but is NOT a [GhostField] — the server alone decides when a siege
|
|
/// fires; clients learn about it only through the replicated <see cref="CycleState.Phase"/> flip to Siege.
|
|
/// Flat scalar fields (never an enum/array — dodges the MCP authoring-drop gotcha + stays Burst-trivial). This
|
|
/// slice wires only the POST-EXPEDITION source; the Heat/Schedule fields are baked-but-inert so those sources
|
|
/// drop in later additively with NO re-bake (server-only layout, not a ghost serializer change).
|
|
/// </summary>
|
|
public struct ThreatConfig : IComponentData
|
|
{
|
|
// ---- Post-expedition retaliation (the only source wired this slice) ----
|
|
|
|
/// <summary>1 = a completed expedition (a player returning to base) can draw a retaliation siege.</summary>
|
|
public byte PostExpeditionEnabled;
|
|
|
|
/// <summary>Telegraph/arming delay (server ticks) between the trigger and the siege actually spawning.</summary>
|
|
public uint PostExpeditionDelayTicks;
|
|
|
|
/// <summary>Siege size floor (Husk count) for a post-expedition retaliation.</summary>
|
|
public int SizeBase;
|
|
|
|
/// <summary>Extra Husks per unit of resources hauled back this run (0 = a flat <see cref="SizeBase"/> siege).</summary>
|
|
public int SizePerExpeditionResource;
|
|
|
|
/// <summary>How a pending siege starts (see <see cref="ThreatStartCondition"/>).</summary>
|
|
public byte StartCondition;
|
|
|
|
/// <summary>Max server ticks a Siege may run before it auto-collapses (remaining Husks culled) so an unattended/empty-base siege can never soft-lock. 0 = no cap.</summary>
|
|
public uint SiegeTimeoutTicks;
|
|
|
|
// ---- Reserved, present-but-inert this slice (additive later, no re-bake) ----
|
|
|
|
public byte HeatEnabled;
|
|
public float HeatPerTickAtBase;
|
|
public float HeatPerHarvest;
|
|
public float HeatThreshold;
|
|
public byte ScheduleEnabled;
|
|
public uint ScheduleIntervalTicks;
|
|
}
|
|
|
|
/// <summary>Start-condition constants for <see cref="ThreatConfig.StartCondition"/> (bytes — never an enum, never in an RPC).</summary>
|
|
public static class ThreatStartCondition
|
|
{
|
|
/// <summary>DEFAULT: arm via the telegraph countdown (<see cref="ThreatState.ArmTick"/>) then fire — even at an empty base.</summary>
|
|
public const byte Immediate = 0;
|
|
|
|
/// <summary>Hold the pending siege until ≥1 player is in the base region OR the arm tick + a grace window elapses (bounded — never a soft-lock).</summary>
|
|
public const byte RequirePlayerAtBase = 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Server-only runtime state of the ThreatDirector, on the global CycleDirector entity beside
|
|
/// <see cref="CycleRuntime"/>. NOT replicated. <see cref="PendingSiegeSize"/> is the single documented entry
|
|
/// point: any source (post-expedition, dev tools, later Heat/Schedule) sets it; <c>CyclePhaseSystem</c>
|
|
/// consumes it on the Calm→Siege edge and zeroes it. All stored ticks are wrap-safe (TickUtil.NonZero +
|
|
/// NetworkTick compares), never raw uint.
|
|
/// </summary>
|
|
public struct ThreatState : IComponentData
|
|
{
|
|
/// <summary>Husk count of the armed siege; 0 = none pending. Consumed (zeroed) by CyclePhaseSystem at Siege entry.</summary>
|
|
public int PendingSiegeSize;
|
|
|
|
/// <summary>Server tick the pending siege fires (telegraph). 0 = fire as soon as seen. Routed through TickUtil.NonZero.</summary>
|
|
public uint ArmTick;
|
|
|
|
/// <summary>Server tick the current Siege began (0 = not under siege). The bounded-resolution timeout measures from here (TickUtil.NonZero) so an unattended/empty-base siege can never soft-lock.</summary>
|
|
public uint SiegeStartTick;
|
|
|
|
/// <summary>Count of expeditions completed (a player returned to base). Drives the post-expedition source + stats.</summary>
|
|
public int ExpeditionsCompleted;
|
|
|
|
/// <summary>Return events the gate has signalled but the director has not yet consumed (the gate teleports the player out of its radius, so one increment per return — natural de-dup).</summary>
|
|
public int PendingReturns;
|
|
|
|
/// <summary>Accumulated heat (inert this slice; the Heat source reads/writes it later).</summary>
|
|
public float Heat;
|
|
|
|
/// <summary>Next scheduled-siege tick (inert this slice; the Schedule source uses it later). TickUtil.NonZero when used.</summary>
|
|
public uint NextScheduledTick;
|
|
}
|
|
}
|