using NUnit.Framework; using ProjectM.Server; using ProjectM.Simulation; using Unity.Core; using Unity.Entities; using Unity.NetCode; namespace ProjectM.Tests { /// /// Plain-Entities EditMode tests for the server-only — the RPC handler /// that applies deposit/withdraw ops to the shared storage container's replicated StorageEntry buffer. /// A bare world with a SharedStorageContainer singleton (carrying the buffer) plus synthetic /// StorageOpRequest + ReceiveRpcCommandRequest entities exercises the handler. The system plays /// its ECB back immediately (Temp allocator), so the handled request entity is destroyed within the single /// group update. Mirrors HealthApplyDamageSystemTests. Locks the deposit/withdraw/drop-row behaviour before /// the Stage-C const refactor and any later storage-model changes. /// public class StorageOpReceiveSystemTests { static (World world, SimulationSystemGroup group) MakeWorld(string name) { var world = new World(name); var group = world.GetOrCreateSystemManaged(); group.AddSystemToUpdateList(world.GetOrCreateSystem()); group.SortSystems(); world.SetTime(new TimeData(elapsedTime: 0f, deltaTime: 1f / 60f)); return (world, group); } static Entity MakeContainer(EntityManager em, ushort itemId, int count) { var e = em.CreateEntity(typeof(SharedStorageContainer)); var buf = em.AddBuffer(e); if (itemId != 0) buf.Add(new StorageEntry { ItemId = itemId, Count = count }); return e; } static void MakeRequest(EntityManager em, byte op, ushort itemId, int count) { var e = em.CreateEntity(); em.AddComponentData(e, new StorageOpRequest { Op = op, ItemId = itemId, Count = count }); em.AddComponentData(e, default(ReceiveRpcCommandRequest)); } [Test] public void Withdraw_Decrements_Existing_Row_And_Destroys_Request() { var (world, group) = MakeWorld("StorageWithdrawWorld"); using (world) { var em = world.EntityManager; var container = MakeContainer(em, itemId: 1, count: 100); MakeRequest(em, StorageOp.Withdraw, itemId: 1, count: 30); group.Update(); var buf = em.GetBuffer(container); Assert.AreEqual(1, buf.Length, "A partial withdraw keeps the row."); Assert.AreEqual(70, buf[0].Count, "100 - 30 = 70 must remain."); using var reqQuery = em.CreateEntityQuery(typeof(StorageOpRequest)); Assert.AreEqual(0, reqQuery.CalculateEntityCount(), "The handled request entity must be destroyed by the system's ECB."); } } [Test] public void Deposit_Of_New_Item_Appends_A_Row() { var (world, group) = MakeWorld("StorageDepositWorld"); using (world) { var em = world.EntityManager; var container = MakeContainer(em, itemId: 1, count: 100); MakeRequest(em, StorageOp.Deposit, itemId: 2, count: 20); group.Update(); var buf = em.GetBuffer(container); Assert.AreEqual(2, buf.Length, "Depositing a previously-absent item appends a second row."); int item2 = -1; for (int i = 0; i < buf.Length; i++) if (buf[i].ItemId == 2) item2 = buf[i].Count; Assert.AreEqual(20, item2, "The appended row carries the deposited count."); } } [Test] public void Withdraw_Of_Full_Stack_Drops_The_Row() { var (world, group) = MakeWorld("StorageWithdrawZeroWorld"); using (world) { var em = world.EntityManager; var container = MakeContainer(em, itemId: 1, count: 30); MakeRequest(em, StorageOp.Withdraw, itemId: 1, count: 30); group.Update(); var buf = em.GetBuffer(container); Assert.AreEqual(0, buf.Length, "Withdrawing the whole stack drops the row entirely."); } } } }