131 lines
5.6 KiB
C#
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));
|
|
}
|
|
}
|
|
}
|