LANTERN P1 step 2: AbilityFireSystem socket restructure + SpawnId repack

The netcode core of the 4-socket kit (Phase1_Combat_Gym_Build_Spec §1,§2,§5; review NP-1/
RS-1/DB-1/DB-3):
- PlayerInput: +4 Socket0..3 InputEvents + Burst-safe GetSocket(i); legacy Fire kept vestigial.
- PlayerInputGatherSystem: gather sockets from keyboard 1..4 (+gamepad RT/LB/RB); socket 0 also
  fires on the legacy primary (right-click / pad LT) as a bridge.
- AbilityFireSystem: query dropped to 4 type args (PlayerInput/PlayerFacing/LocalTransform/
  GhostOwner) + BufferLookup<AbilitySocket>/ComponentLookup<SocketCooldown>/BufferLookup<
  EffectiveSocketStats> (the 7-arg-cap fix); loops 4 sockets; per-socket cooldown + per-socket
  effective stats; Cone + Projectile dispatch per socket (predict-spawn Projectile-only).
- ProjectileSpawnId.Pack: pure Burst-safe key owner14|socket2|fireCount12|fork4 so same-tick
  multi-socket projectiles never collide; AbilityFireSystem uses it.
L1 clean; L2 494/494 (+5 ProjectileSpawnId tests: distinct-per-socket, fork, owner, bit-ranges,
count-wrap). L3 two-player + rollback is the group-A gate (after step 2.5). Note: the client
feel layer (muzzle/anim) still reads the legacy cooldown until step 2.5; sockets bake empty
until content (step 4), so nothing fires in-game yet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-14 10:59:45 -07:00
parent b143eb6bb5
commit 12f86c86de
7 changed files with 290 additions and 181 deletions
@@ -29,11 +29,31 @@ namespace ProjectM.Simulation
/// one swing attempt across the frame->tick->rollback boundary; read by the predicted MeleeComboSystem.</summary>
[GhostField] public InputEvent Attack;
/// <summary>LANTERN 4-socket kit: one fire event per ability socket (0..3). A press sets that socket's
/// event for the tick; AbilityFireSystem fires the Spark in that socket. InputEvent survives the
/// frame->tick->rollback boundary so one press fires once. Read per-socket via <see cref="GetSocket"/>.</summary>
[GhostField] public InputEvent Socket0;
[GhostField] public InputEvent Socket1;
[GhostField] public InputEvent Socket2;
[GhostField] public InputEvent Socket3;
/// <summary>Active input scheme this tick (<see cref="InputSchemeId"/>: 0 = mouse/keyboard, 1 = gamepad).
/// The server reads it so the auto-target assist applies only to gamepad shots; precise mouse aim is left
/// exact. A byte (not an enum): it is compared inside the Burst-compiled <c>AbilityFireSystem</c>.</summary>
[GhostField] public byte Scheme;
/// <summary>The fire event for ability socket <paramref name="i"/> (0..3). Burst-safe (switch, not a field index).</summary>
public InputEvent GetSocket(int i)
{
switch (i)
{
case 0: return Socket0;
case 1: return Socket1;
case 2: return Socket2;
default: return Socket3;
}
}
public FixedString512Bytes ToFixedString()
{
var s = new FixedString512Bytes();