using NUnit.Framework; using ProjectM.Server; using ProjectM.Simulation; using Unity.Core; using Unity.Entities; using Unity.Mathematics; using Unity.Transforms; namespace ProjectM.Tests { /// /// Regression test for the teardown region-filter. When the last player /// leaves the expedition the field is cleared — but that teardown must destroy ONLY RegionTag{Expedition} /// nodes, never the permanent RegionTag{Base} home-base mining field. Before the fix the unfiltered teardown /// wiped every ResourceNode on the empty edge (a despawn storm beside base players that broke the core loop). /// public class ExpeditionFieldTeardownTests { [Test] public void Expedition_Empty_Edge_Destroys_Only_Expedition_Nodes_Base_Field_Survives() { var world = new World("ExpeditionTeardown"); using (world) { var group = world.GetOrCreateSystemManaged(); group.AddSystemToUpdateList(world.GetOrCreateSystem()); group.SortSystems(); world.SetTime(new TimeData(elapsedTime: 0f, deltaTime: 1f / 60f)); var em = world.EntityManager; // Cycle director: was occupied last tick, nobody out there now => the occupied->empty edge fires. var cycle = em.CreateEntity(typeof(CycleState), typeof(CycleRuntime)); em.SetComponentData(cycle, new CycleState { Phase = CyclePhase.Calm, CycleNumber = 1 }); em.SetComponentData(cycle, new CycleRuntime { PrevExpeditionOccupied = 1 }); // Spawner singleton (required); null prefab so the spawn branch is inert. var spawnerE = em.CreateEntity(typeof(ResourceFieldSpawner)); em.SetComponentData(spawnerE, new ResourceFieldSpawner { Prefab = Entity.Null, Count = 5, Radius = 10f }); var baseNode = em.CreateEntity(typeof(LocalTransform), typeof(ResourceNode), typeof(RegionTag)); em.SetComponentData(baseNode, LocalTransform.FromPosition(new float3(20, 0, 0))); em.SetComponentData(baseNode, new ResourceNode { ResourceId = ResourceId.Ore, Remaining = 30, HarvestPerHit = 5f }); em.SetComponentData(baseNode, new RegionTag { Region = RegionId.Base }); var expNode = em.CreateEntity(typeof(LocalTransform), typeof(ResourceNode), typeof(RegionTag)); em.SetComponentData(expNode, LocalTransform.FromPosition(new float3(1020, 0, 0))); em.SetComponentData(expNode, new ResourceNode { ResourceId = ResourceId.Aether, Remaining = 30, HarvestPerHit = 5f }); em.SetComponentData(expNode, new RegionTag { Region = RegionId.Expedition }); group.Update(); Assert.IsTrue(em.Exists(baseNode), "The permanent base mining field survives the expedition teardown."); Assert.IsFalse(em.Exists(expNode), "Only the expedition node is cleared when the last player leaves."); } } } }