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 FrameKind / ClassId convention). [GhostField] public byte Value; } }