95 lines
4.2 KiB
C#
95 lines
4.2 KiB
C#
using NUnit.Framework;
|
|
using ProjectM.Server;
|
|
using ProjectM.Simulation;
|
|
using Unity.Core;
|
|
using Unity.Entities;
|
|
using Unity.Mathematics;
|
|
using Unity.NetCode;
|
|
using Unity.Transforms;
|
|
|
|
namespace ProjectM.Tests
|
|
{
|
|
/// <summary>
|
|
/// Plain-Entities tests for <see cref="DashTrailDamageSystem"/> (Phase 1.7 Blade Dash). A dashing player with the
|
|
/// boon damages a nearby enemy ONCE per dash (StartTick-keyed dedup survives a re-tick); a fresh dash hits again;
|
|
/// no boon → no damage.
|
|
/// </summary>
|
|
public class DashTrailDamageSystemTests
|
|
{
|
|
static (World world, SimulationSystemGroup group, EntityManager em) MakeWorld(uint tick)
|
|
{
|
|
var world = new World("DashTrailTest");
|
|
var group = world.GetOrCreateSystemManaged<SimulationSystemGroup>();
|
|
group.AddSystemToUpdateList(world.GetOrCreateSystem<DashTrailDamageSystem>());
|
|
group.SortSystems();
|
|
world.SetTime(new TimeData(elapsedTime: 0f, deltaTime: 1f / 60f));
|
|
var em = world.EntityManager;
|
|
em.SetComponentData(em.CreateEntity(typeof(NetworkTime)), new NetworkTime { ServerTick = new NetworkTick(tick) });
|
|
return (world, group, em);
|
|
}
|
|
|
|
static void SetTick(EntityManager em, uint tick)
|
|
{
|
|
using var q = em.CreateEntityQuery(typeof(NetworkTime));
|
|
em.SetComponentData(q.GetSingletonEntity(), new NetworkTime { ServerTick = new NetworkTick(tick) });
|
|
}
|
|
|
|
static Entity MakeDasher(EntityManager em, byte flags, uint startTick, uint iframeUntil)
|
|
{
|
|
var e = em.CreateEntity(typeof(PlayerTag), typeof(GhostOwner), typeof(BoonEffects), typeof(DashTrailState));
|
|
em.AddComponentData(e, LocalTransform.FromPosition(new float3(0f, 0f, 0f)));
|
|
em.AddComponentData(e, new DashState { Dir = new float2(1f, 0f), StartTick = startTick, IFrameUntilTick = iframeUntil, RecoverUntilTick = iframeUntil + 9 });
|
|
em.AddComponent<Simulate>(e); // enabled by default
|
|
em.SetComponentData(e, new GhostOwner { NetworkId = 1 });
|
|
em.SetComponentData(e, new BoonEffects { Flags = flags });
|
|
return e;
|
|
}
|
|
|
|
static Entity MakeEnemy(EntityManager em, float3 pos)
|
|
{
|
|
var e = em.CreateEntity(typeof(EnemyTag));
|
|
em.AddComponentData(e, LocalTransform.FromPosition(pos));
|
|
em.AddComponentData(e, new HitRadius { Value = 0.5f });
|
|
em.AddComponentData(e, new Health { Current = 60f, Max = 60f });
|
|
em.AddBuffer<DamageEvent>(e);
|
|
return e;
|
|
}
|
|
|
|
[Test]
|
|
public void BladeDash_DamagesNearbyEnemy_OncePerDash_ReHitsOnNextDash()
|
|
{
|
|
var (world, group, em) = MakeWorld(100);
|
|
using (world)
|
|
{
|
|
var player = MakeDasher(em, BoonFlag.DashTrail, startTick: 100, iframeUntil: 112);
|
|
var enemy = MakeEnemy(em, new float3(1f, 0f, 0f)); // within 1.6 + 0.5
|
|
|
|
group.Update(); // tick 100, dashing
|
|
Assert.AreEqual(1, em.GetBuffer<DamageEvent>(enemy).Length, "enemy in the dash path takes one hit");
|
|
|
|
group.Update(); // same tick + same StartTick -> dedup, no second hit
|
|
Assert.AreEqual(1, em.GetBuffer<DamageEvent>(enemy).Length, "no re-hit within the same dash");
|
|
|
|
// A fresh dash (new StartTick) resets the dedup set -> the enemy can be hit again.
|
|
SetTick(em, 130);
|
|
em.SetComponentData(player, new DashState { Dir = new float2(1f, 0f), StartTick = 130, IFrameUntilTick = 142, RecoverUntilTick = 151 });
|
|
group.Update();
|
|
Assert.AreEqual(2, em.GetBuffer<DamageEvent>(enemy).Length, "a fresh dash hits the enemy again");
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void NoBoon_NoDamage()
|
|
{
|
|
var (world, group, em) = MakeWorld(100);
|
|
using (world)
|
|
{
|
|
MakeDasher(em, flags: 0, startTick: 100, iframeUntil: 112); // no DashTrail flag
|
|
var enemy = MakeEnemy(em, new float3(1f, 0f, 0f));
|
|
group.Update();
|
|
Assert.AreEqual(0, em.GetBuffer<DamageEvent>(enemy).Length, "no Blade Dash boon -> no trail damage");
|
|
}
|
|
}
|
|
}
|
|
}
|