88 lines
3.1 KiB
C#
88 lines
3.1 KiB
C#
using NUnit.Framework;
|
|
using ProjectM.Simulation;
|
|
using Unity.Mathematics;
|
|
|
|
namespace ProjectM.Tests
|
|
{
|
|
/// <summary>
|
|
/// Pure-function tests for <see cref="PlayerSpawnMath.SpawnOffset"/> (no ECS world), mirroring
|
|
/// StatMathTests. Pins the M4 co-op deterministic spawn spread: stable, distinct per-NetworkId ring
|
|
/// positions so players never stack on connect.
|
|
/// </summary>
|
|
public class PlayerSpawnRingTests
|
|
{
|
|
const float R = 2.5f;
|
|
const int Slots = 4;
|
|
const float Eps = 1e-4f;
|
|
|
|
[Test]
|
|
public void Deterministic_SameInputs_SameOffset()
|
|
{
|
|
var a = PlayerSpawnMath.SpawnOffset(2, R, Slots);
|
|
var b = PlayerSpawnMath.SpawnOffset(2, R, Slots);
|
|
Assert.AreEqual(a.x, b.x, Eps);
|
|
Assert.AreEqual(a.y, b.y, Eps);
|
|
Assert.AreEqual(a.z, b.z, Eps);
|
|
}
|
|
|
|
[Test]
|
|
public void FirstFour_Land_On_Cardinal_Ring_Slots()
|
|
{
|
|
// NetworkIds start at 1; slots=4 -> 0, 90, 180, 270 degrees on a ring of radius R.
|
|
AssertXz(PlayerSpawnMath.SpawnOffset(1, R, Slots), R, 0f);
|
|
AssertXz(PlayerSpawnMath.SpawnOffset(2, R, Slots), 0f, R);
|
|
AssertXz(PlayerSpawnMath.SpawnOffset(3, R, Slots), -R, 0f);
|
|
AssertXz(PlayerSpawnMath.SpawnOffset(4, R, Slots), 0f, -R);
|
|
}
|
|
|
|
[Test]
|
|
public void Distinct_NetworkIds_Give_Distinct_Positions()
|
|
{
|
|
var seen = new System.Collections.Generic.List<float3>();
|
|
for (int id = 1; id <= 8; id++)
|
|
{
|
|
var p = PlayerSpawnMath.SpawnOffset(id, R, Slots);
|
|
foreach (var q in seen)
|
|
Assert.Greater(math.distance(p, q), 1e-3f, $"id {id} collides with an earlier slot");
|
|
seen.Add(p);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void FifthPlayer_Spills_To_Outer_Ring()
|
|
{
|
|
// idx 4 with slots 4 -> ring 1, slot 0 -> radius doubled, angle 0.
|
|
AssertXz(PlayerSpawnMath.SpawnOffset(5, R, Slots), 2f * R, 0f);
|
|
}
|
|
|
|
[Test]
|
|
public void NonPositiveRadius_Returns_Zero()
|
|
{
|
|
Assert.AreEqual(0f, math.length(PlayerSpawnMath.SpawnOffset(3, 0f, Slots)), Eps);
|
|
Assert.AreEqual(0f, math.length(PlayerSpawnMath.SpawnOffset(3, -1f, Slots)), Eps);
|
|
}
|
|
|
|
[Test]
|
|
public void DegenerateSlots_DoNotThrow_AndStayDistinct()
|
|
{
|
|
// slots < 1 is clamped to 1 (every player on its own concentric ring).
|
|
var a = PlayerSpawnMath.SpawnOffset(1, R, 0);
|
|
var b = PlayerSpawnMath.SpawnOffset(2, R, 0);
|
|
Assert.Greater(math.distance(a, b), 1e-3f);
|
|
}
|
|
|
|
[Test]
|
|
public void Offset_Is_Planar_NoVerticalComponent()
|
|
{
|
|
for (int id = 1; id <= 6; id++)
|
|
Assert.AreEqual(0f, PlayerSpawnMath.SpawnOffset(id, R, Slots).y, Eps);
|
|
}
|
|
|
|
static void AssertXz(float3 p, float x, float z)
|
|
{
|
|
Assert.AreEqual(x, p.x, Eps);
|
|
Assert.AreEqual(z, p.z, Eps);
|
|
}
|
|
}
|
|
}
|