Files
Workspace/Assets/Demos/Demo2/Tests/EditMode/Demo2EcsTests.cs
T
2026-08-18 02:03:34 +08:00

131 lines
5.6 KiB
C#

#nullable enable
using System.Diagnostics;
using Demo2.Domain;
using Demo2.ECS;
using Demo2.Runtime;
using NUnit.Framework;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
namespace Demo2.Tests
{
public sealed class Demo2EcsTests
{
[Test]
public void SameSeedAndCommands_RemainIdenticalForTenThousandTicks()
{
using var left = new Demo2EcsWorld(20260817, Demo2BuiltInContent.BuildRules());
using var right = new Demo2EcsWorld(20260817, Demo2BuiltInContent.BuildRules());
left.SetPhase(Demo2Phase.Production);
right.SetPhase(Demo2Phase.Production);
for (var tick = 0; tick < 10_000; tick++)
{
left.Tick();
right.Tick();
}
var leftState = left.EntityManager.GetComponentData<Demo2SimulationState>(left.Singleton);
var rightState = right.EntityManager.GetComponentData<Demo2SimulationState>(right.Singleton);
Assert.That(leftState.Tick, Is.EqualTo(10_000));
Assert.That(leftState.StateHash, Is.EqualTo(rightState.StateHash));
}
[Test]
public void SnapshotRestore_ContinuesWithTheSameHash()
{
using var source = new Demo2EcsWorld(42, Demo2BuiltInContent.BuildRules());
source.SetPhase(Demo2Phase.Production);
for (var tick = 0; tick < 500; tick++) source.Tick();
var snapshot = source.CaptureSnapshot(new[] { "production.dense-ammo" });
using var restored = new Demo2EcsWorld(999, Demo2BuiltInContent.BuildRules());
restored.RestoreSnapshot(snapshot);
for (var tick = 0; tick < 200; tick++)
{
source.Tick();
restored.Tick();
}
var sourceState = source.EntityManager.GetComponentData<Demo2SimulationState>(source.Singleton);
var restoredState = restored.EntityManager.GetComponentData<Demo2SimulationState>(restored.Singleton);
Assert.That(restoredState.StateHash, Is.EqualTo(sourceState.StateHash));
}
[Test]
public void BuildCommands_AreIdempotentAndRemovalRefundsBeforeEntityDestruction()
{
using var service = new Demo2GameService();
service.StartNewGame(17);
var command = new Demo2BuildCommand
{
Sequence = 1,
IdempotencyToken = "test-place",
PlayerId = "test",
Kind = Demo2MachineKind.Conveyor,
X = 1,
Y = 1
};
var accepted = service.SubmitBuild(command);
var duplicate = service.SubmitBuild(command);
var removed = service.BuildLocal(Demo2MachineKind.Conveyor, 1, 1, remove: true);
Assert.That(accepted.Accepted, Is.True);
Assert.That(duplicate.Accepted && duplicate.Duplicate, Is.True);
Assert.That(removed.Accepted, Is.True);
Assert.That(removed.Refund, Is.EqualTo(5));
}
[Test]
public void MultipleTurrets_LoadWithoutSingletonExceptions()
{
using var world = new Demo2EcsWorld(31);
var manager = world.EntityManager;
var state = manager.GetComponentData<Demo2SimulationState>(world.Singleton);
var turret = Demo2EcsFactory.CreateMachine(manager, ++state.NextStableId, Demo2MachineKind.Turret, 22, 10, 0, 0);
manager.AddComponentData(turret, new Demo2TurretAmmo());
Demo2EcsFactory.CreateMaterial(manager, ++state.NextStableId, Demo2MaterialKind.Ammo, 0, 19, 0, 9);
manager.SetComponentData(world.Singleton, state);
world.SetPhase(Demo2Phase.Production);
world.Tick();
var query = manager.CreateEntityQuery(typeof(Demo2TurretAmmo));
using var ammo = query.ToComponentDataArray<Demo2TurretAmmo>(Allocator.Temp);
long total = 0;
for (var i = 0; i < ammo.Length; i++) total += ammo[i].Value;
Assert.That(total, Is.EqualTo(9));
}
[Test]
[Category("Demo2Performance")]
public void StressTick_HandlesTenThousandItemsAndOneThousandMachines()
{
using var world = new Demo2EcsWorld(77);
var manager = world.EntityManager;
var state = manager.GetComponentData<Demo2SimulationState>(world.Singleton);
for (var i = 0; i < 1_000; i++)
Demo2EcsFactory.CreateMachine(manager, ++state.NextStableId, Demo2MachineKind.Conveyor, i % Demo2Protocol.GridWidth, (i / Demo2Protocol.GridWidth) % 10, 0, 0);
for (var i = 0; i < 10_000; i++)
Demo2EcsFactory.CreateMaterial(manager, ++state.NextStableId, Demo2MaterialKind.IronOre, i % Demo2Protocol.GridWidth, 19, 0, 1);
manager.SetComponentData(world.Singleton, state);
world.SetPhase(Demo2Phase.Production);
var before = System.GC.GetAllocatedBytesForCurrentThread();
var stopwatch = Stopwatch.StartNew();
world.Tick();
stopwatch.Stop();
var allocated = System.GC.GetAllocatedBytesForCurrentThread() - before;
using var entities = manager.GetAllEntities(Allocator.Temp);
UnityEngine.Debug.Log($"[Demo2 Benchmark] entities={entities.Length} tickMs={stopwatch.Elapsed.TotalMilliseconds:0.00} managedBytes={allocated}");
Assert.That(entities.Length, Is.GreaterThanOrEqualTo(11_000));
Assert.That(stopwatch.ElapsedMilliseconds, Is.LessThan(10_000));
Assert.That(allocated, Is.LessThanOrEqualTo(4096));
}
}
}