304ee8c2a7
Portal-gated rooms: new RunLifecycle.RoomExplore loot window; room+nodes persist past the last kill; PortalInteractRequest -> server-only PortalCommand advances (client derives the portal pos). RunDirectorSystem moves teardown off the InRoom edge, relocates the boss-branch/route-gate into the RoomExplore exit, and advances an empty expedition immediately (incl. a boss clear). Class-at-base via a shared ClassSwapUtil (meta-band strip + per-class MetaTierState replay, so the base RPC and the dev SetClass can't drift); ClassSelectRequest Staging-gated. Per-run PREP buffs (PrepPurchaseRequest, PrepCatalog): once-per-run == the row's prep StatModifier band is present, TotalOf-before-Withdraw atomic, stripped on Returning beside the boon band. Health.Max promoted to [GhostField] (the one ghost-hash re-bake) so the boss + floating enemy HP bars read it directly. Feel: melee cone connect-thunk (C3), hit-stop throttle so a horde wipe can't stutter (C4), Spitter cornered-hold. 456/456 EditMode; two adversarial reviews (pre-code 13-confirmed folded; post-impl clean bar the RoomExplore boss-clear dead-time, fixed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
37 lines
1.5 KiB
C#
37 lines
1.5 KiB
C#
using System.Collections.Generic;
|
|
using ProjectM.Simulation;
|
|
using Unity.Entities;
|
|
using Unity.NetCode;
|
|
using UnityEngine;
|
|
|
|
namespace ProjectM.Client
|
|
{
|
|
/// <summary>
|
|
/// Client-side class-pick sender: a static enqueue (the Staging class-select HUD buttons) drained into
|
|
/// <see cref="ClassSelectRequest"/> RPCs (the MetaSpendSendSystem idiom). Carries only the class id; the server
|
|
/// re-validates the phase + applies the full swap. Statics reset on play-enter (the stale-bridge hazard).
|
|
/// </summary>
|
|
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
|
|
public partial class ClassSelectSendSystem : SystemBase
|
|
{
|
|
static readonly Queue<byte> s_Queue = new();
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
|
static void ResetStatics() => s_Queue.Clear();
|
|
|
|
/// <summary>Queue a class pick (0=Warrior, 1=Ranger). The Staging class buttons drive this.</summary>
|
|
public static void RequestClass(byte classId) => s_Queue.Enqueue(classId);
|
|
|
|
protected override void OnCreate() => RequireForUpdate<NetworkId>();
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
while (s_Queue.Count > 0)
|
|
{
|
|
var req = EntityManager.CreateEntity(typeof(ClassSelectRequest), typeof(SendRpcCommandRequest));
|
|
EntityManager.SetComponentData(req, new ClassSelectRequest { ClassId = s_Queue.Dequeue() });
|
|
}
|
|
}
|
|
}
|
|
}
|