using Unity.Entities;
using Unity.NetCode;
namespace ProjectM.Simulation
{
/// Socket count / index constants for the LANTERN 4-socket kit.
public static class SocketId
{
public const int Count = 4;
}
///
/// Per-player ability socket loadout — one replicated row per socket (buffer index = socket 0..3),
/// each holding the (Spark) occupying that socket (0 = empty). The LANTERN
/// 4-socket-kit analog of the single ; modelled on :
/// COLD (mutated only when socketing in the hub, server-sole-writer — NOT predicted). Read by
/// AbilityFireSystem via a BufferLookup, never as a SystemAPI.Query type arg (the 7-arg cap).
///
[InternalBufferCapacity(4)]
[GhostComponent(OwnerSendType = SendToOwnerType.All)]
public struct AbilitySocket : IBufferElementData
{
/// The (Spark) occupying this socket; 0 = empty.
[GhostField] public byte SparkId;
}
///
/// HOT, owner-predicted per-socket ability cooldown for the 4-socket kit — the LANTERN analog of the
/// single scalar (deliberately NOT the cold
/// buffer: a scalar-shaped, index-addressable cooldown whose per-tick rollback restore is proven, unlike
/// a per-tick-mutating [GhostField] buffer). Four raw next-fire ticks, one per socket, each a
/// so the gate survives the frame→tick→rollback boundary and converges without
/// double-firing. 0 = ready. Route stored ticks through and compare
/// by wrapping into a + (raw subtraction
/// is unsafe across wraparound). Explicit SendToOwnerType.All (parity with today's implicit-send-all
/// , so remote clients still drive teammates' ability feel).
///
[GhostComponent(OwnerSendType = SendToOwnerType.All)]
public struct SocketCooldown : IComponentData
{
[GhostField] public uint Next0;
[GhostField] public uint Next1;
[GhostField] public uint Next2;
[GhostField] public uint Next3;
/// Next-fire tick for socket (0..3). Burst-safe (switch, not a field index).
public uint Get(int i)
{
switch (i)
{
case 0: return Next0;
case 1: return Next1;
case 2: return Next2;
default: return Next3;
}
}
/// Set the next-fire tick for socket (0..3).
public void Set(int i, uint v)
{
switch (i)
{
case 0: Next0 = v; break;
case 1: Next1 = v; break;
case 2: Next2 = v; break;
default: Next3 = v; break;
}
}
}
///
/// Replicated per-player frame/class signal (a LANTERN suit-frame IS the class). Baked on the player
/// ghost, written server-side when the frame/class is chosen. Exists because, under the 4-socket kit, no
/// single ability id maps 1:1 to a class the way the old single did — the HUD/
/// feel systems read this instead of ClassTraits.ClassForAbility(AbilityRef.Id). SendToOwner:
/// only the owning client's HUD needs its own frame. (Distinct from the server-only PlayerClass,
/// which is runtime-added and cannot carry a GhostField.)
///
[GhostComponent(OwnerSendType = SendToOwnerType.SendToOwner)]
public struct FrameId : IComponentData
{
/// The frame/class id (see the CharacterId / ClassId convention).
[GhostField] public byte Value;
}
}