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;
}
}
}