using ProjectM.Simulation; using Unity.Entities; using Unity.NetCode; namespace ProjectM.Client { /// /// Client-only sender for shared-storage deposit/withdraw RPCs. A /// one-off action (not per-tick predicted input), so it is an RPC: on an interact key edge (E = /// deposit, Q = withdraw a default test item) it creates the request entity targeted at the server /// connection, and the server applies it authoritatively in StorageOpReceiveSystem. Managed /// SystemBase because it reads the managed Input System. Input System types are fully qualified and /// using UnityEngine.InputSystem; is intentionally omitted (that namespace defines a /// PlayerInput type that collides with ). An editor-only /// static hook (Deposit/Withdraw) drives the same path from execute_code for headless validation /// without a focused Game view. /// [WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)] public partial class StorageOpSendSystem : SystemBase { // Default test item used by the keyboard interact and the parameterless debug hooks. const ushort DefaultItemId = 1; const int DefaultCount = 1; #if UNITY_EDITOR struct PendingStorageOp { public byte Op; public ushort ItemId; public int Count; } static readonly System.Collections.Generic.Queue s_Pending = new System.Collections.Generic.Queue(); /// EDITOR / execute_code hook: queue a deposit of of . public static void Deposit(ushort itemId = DefaultItemId, int count = DefaultCount) => s_Pending.Enqueue(new PendingStorageOp { Op = StorageOp.Deposit, ItemId = itemId, Count = count }); /// EDITOR / execute_code hook: queue a withdraw of of . public static void Withdraw(ushort itemId = DefaultItemId, int count = DefaultCount) => s_Pending.Enqueue(new PendingStorageOp { Op = StorageOp.Withdraw, ItemId = itemId, Count = count }); #endif protected override void OnCreate() { RequireForUpdate(); } protected override void OnUpdate() { // Need the server connection to target the RPC; bail (keeping any queued ops) until connected. if (!SystemAPI.TryGetSingletonEntity(out var connection)) return; var keyboard = UnityEngine.InputSystem.Keyboard.current; if (keyboard != null) { if (keyboard.eKey.wasPressedThisFrame) Send(connection, StorageOp.Deposit, DefaultItemId, DefaultCount); if (keyboard.qKey.wasPressedThisFrame) Send(connection, StorageOp.Withdraw, DefaultItemId, DefaultCount); } #if UNITY_EDITOR while (s_Pending.Count > 0) { var op = s_Pending.Dequeue(); Send(connection, op.Op, op.ItemId, op.Count); } #endif } void Send(Entity connection, byte op, ushort itemId, int count) { var request = EntityManager.CreateEntity(); EntityManager.AddComponentData(request, new StorageOpRequest { Op = op, ItemId = itemId, Count = count }); EntityManager.AddComponentData(request, new SendRpcCommandRequest { TargetConnection = connection }); } } }