using ProjectM.Simulation; using Unity.Core; using Unity.Entities; using Unity.Mathematics; using Unity.NetCode; using Unity.Transforms; namespace ProjectM.Tests { /// /// Plain-Entities EditMode harness. Behaviourally identical to the hand-rolled MakeWorld/SetServerTick idioms /// scattered across the suite (a NetworkTime-seeded SimulationSystemGroup world), consolidated so the boilerplate /// has one home. Named NOT to end in "Tests" so the attribute-guard meta-test skips it. /// static class TestWorld { /// World + SimulationSystemGroup, NetworkTime seeded to , TimeData = 1/60. /// sets WorldFlags.GameServer (the IsServer() gate some systems read). public static (World world, SimulationSystemGroup group) Make(string name = "TestWorld", uint tick = 1, bool server = false) { var world = server ? new World(name, WorldFlags.Game | WorldFlags.GameServer) : new World(name); var group = world.GetOrCreateSystemManaged(); world.SetTime(new TimeData(elapsedTime: 0f, deltaTime: 1f / 60f)); SetTick(world, tick); return (world, group); } /// As , plus registers ONE ISystem and sorts. Drop-in for the per-file MakeWorld<T>. public static (World world, SimulationSystemGroup group) Make(string name = "TestWorld", uint tick = 1, bool server = false) where T : unmanaged, ISystem { var (world, group) = Make(name, tick, server); group.AddSystemToUpdateList(world.GetOrCreateSystem()); group.SortSystems(); return (world, group); } /// Register an extra ISystem and re-sort (idempotent — final order is what matters). public static void Add(World world, SimulationSystemGroup group) where T : unmanaged, ISystem { group.AddSystemToUpdateList(world.GetOrCreateSystem()); group.SortSystems(); } /// The reconciled tick API: create NetworkTime if absent, else set it (a strict superset of both /// hand-rolled variants — behaves like GetSingletonEntity() when present, and tolerates absence). public static void SetTick(World world, uint tick) { var em = world.EntityManager; using var q = em.CreateEntityQuery(typeof(NetworkTime)); Entity e = q.IsEmpty ? em.CreateEntity(typeof(NetworkTime)) : q.GetSingletonEntity(); em.SetComponentData(e, new NetworkTime { ServerTick = new NetworkTick(tick) }); } // ---- domain builders (only for shapes that match exactly; per-file builders with extra components stay local) ---- public static Entity Player(EntityManager em, int netId = 1, byte region = RegionId.Base, float3 pos = default) { var e = em.CreateEntity(typeof(PlayerTag), typeof(GhostOwner), typeof(RegionTag), typeof(LocalTransform)); em.SetComponentData(e, new GhostOwner { NetworkId = netId }); em.SetComponentData(e, new RegionTag { Region = region }); em.SetComponentData(e, LocalTransform.FromPosition(pos)); return e; } public static Entity Enemy(EntityManager em, float3 pos, float hp = 50f, byte region = RegionId.Base) { var e = em.CreateEntity(typeof(EnemyTag), typeof(LocalTransform), typeof(RegionTag), typeof(Health)); em.SetComponentData(e, LocalTransform.FromPosition(pos)); em.SetComponentData(e, new RegionTag { Region = region }); em.SetComponentData(e, new Health { Current = hp, Max = hp }); return e; } } }