fix: Cleans up AI Pathfinding code to make it more portable for custom requirements. (#2474)
This commit is contained in:
parent
412a71dfe0
commit
30fec7da26
16 changed files with 198 additions and 102 deletions
|
|
@ -1,6 +1,6 @@
|
|||
using Server.Engines.Pathing.Cache;
|
||||
using Server.Mobiles;
|
||||
using Server.PathAlgorithms.BitmapAStar;
|
||||
using Server.PathAlgorithms;
|
||||
using Server.Systems.FeatureFlags;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
|
@ -121,7 +121,7 @@ public class BitmapAStarAlgorithmTests
|
|||
var y = sy;
|
||||
foreach (var dir in result)
|
||||
{
|
||||
Server.Movement.Movement.Offset(dir, ref x, ref y);
|
||||
Movement.Movement.Offset(dir, ref x, ref y);
|
||||
Assert.False(x == blockX && y == blockY,
|
||||
$"path traversed blocker cell ({blockX},{blockY})");
|
||||
}
|
||||
|
|
@ -180,7 +180,7 @@ public class BitmapAStarAlgorithmTests
|
|||
var y = sy;
|
||||
foreach (var dir in result)
|
||||
{
|
||||
Server.Movement.Movement.Offset(dir, ref x, ref y);
|
||||
Movement.Movement.Offset(dir, ref x, ref y);
|
||||
Assert.False(x == blockX && y == blockY,
|
||||
$"path traversed item-blocker cell ({blockX},{blockY})");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,22 +10,11 @@ public class PathfindRecorderTests
|
|||
private static string NewTempPath() =>
|
||||
Path.Combine(Path.GetTempPath(), $"pathfind-recorder-{System.Guid.NewGuid():N}.jsonl");
|
||||
|
||||
/// <summary>
|
||||
/// Reflection-set the static _outputPath without going through Configure (which
|
||||
/// reads from server.cfg) so tests don't poison the project's server.cfg.
|
||||
/// </summary>
|
||||
private static void OverrideOutputPath(string path)
|
||||
{
|
||||
typeof(PathfindRecorder).GetField("_outputPath",
|
||||
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)!
|
||||
.SetValue(null, path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Disabled_RecordIfEnabled_DoesNothing()
|
||||
{
|
||||
var path = NewTempPath();
|
||||
OverrideOutputPath(path);
|
||||
PathfindRecorder.OutputPath = path;
|
||||
PathfindRecorder.SetEnabled(false);
|
||||
|
||||
try
|
||||
|
|
@ -52,7 +41,7 @@ public class PathfindRecorderTests
|
|||
public void Enabled_RecordIfEnabled_WritesValidJsonlLine()
|
||||
{
|
||||
var path = NewTempPath();
|
||||
OverrideOutputPath(path);
|
||||
PathfindRecorder.OutputPath = path;
|
||||
PathfindRecorder.SetEnabled(true);
|
||||
|
||||
try
|
||||
|
|
@ -95,7 +84,7 @@ public class PathfindRecorderTests
|
|||
public void Enabled_RecordsCapabilityFlagsFromBaseCreature()
|
||||
{
|
||||
var path = NewTempPath();
|
||||
OverrideOutputPath(path);
|
||||
PathfindRecorder.OutputPath = path;
|
||||
PathfindRecorder.SetEnabled(true);
|
||||
|
||||
try
|
||||
|
|
@ -130,7 +119,7 @@ public class PathfindRecorderTests
|
|||
public void SetEnabled_TogglingTwice_IsIdempotent()
|
||||
{
|
||||
var path = NewTempPath();
|
||||
OverrideOutputPath(path);
|
||||
PathfindRecorder.OutputPath = path;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -155,9 +144,6 @@ public class PathfindRecorderTests
|
|||
|
||||
private sealed class RecorderStub : Server.Mobiles.BaseCreature
|
||||
{
|
||||
public RecorderStub(Serial serial) : base(serial)
|
||||
{
|
||||
Body = 0xC9;
|
||||
}
|
||||
public RecorderStub(Serial serial) : base(serial) => Body = 0xC9;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public class StepCacheFileTests
|
|||
expected[i] = cache.TryGetMask(map, x, y, standZ[i]);
|
||||
}
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-roundtrip-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-roundtrip-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
var written = cache.SaveToFile(path, map.MapID);
|
||||
|
|
@ -109,7 +109,7 @@ public class StepCacheFileTests
|
|||
var cache = StepCache.Instance;
|
||||
cache.Clear();
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-missing-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-missing-{Guid.NewGuid():N}.swb");
|
||||
Assert.False(cache.TryOpenLazyReader(path, mapId: 1));
|
||||
Assert.Equal(0, cache.OpenLazyReaderCount);
|
||||
}
|
||||
|
|
@ -120,7 +120,7 @@ public class StepCacheFileTests
|
|||
var cache = StepCache.Instance;
|
||||
cache.Clear();
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-badmagic-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-badmagic-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
File.WriteAllBytes(path, new byte[]
|
||||
|
|
@ -150,7 +150,7 @@ public class StepCacheFileTests
|
|||
var map = Map.Maps[1];
|
||||
cache.TryGetMask(map, 1500, 1600, sourceZ: 10);
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-stalehash-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-stalehash-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
cache.SaveToFile(path, map.MapID);
|
||||
|
|
@ -193,7 +193,7 @@ public class StepCacheFileTests
|
|||
Assert.NotNull(map);
|
||||
|
||||
// Populate a handful of chunks.
|
||||
var coords = new (int, int)[]
|
||||
var coords = new[]
|
||||
{
|
||||
(1500, 1600), (1516, 1600), (1500, 1616), (1516, 1616), (1532, 1600)
|
||||
};
|
||||
|
|
@ -202,7 +202,7 @@ public class StepCacheFileTests
|
|||
cache.TryGetMask(map, x, y, sourceZ: 10);
|
||||
}
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-lazy-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-lazy-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
Assert.Equal(coords.Length, cache.SaveToFile(path, map.MapID));
|
||||
|
|
@ -269,7 +269,7 @@ public class StepCacheFileTests
|
|||
chunk.SwimZE_Layer[cellIndex] = -7;
|
||||
chunk.SwimZSE_Layer[cellIndex] = -7;
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-swim-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-swim-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
Assert.Equal(1, cache.SaveToFile(path, map.MapID));
|
||||
|
|
@ -314,7 +314,7 @@ public class StepCacheFileTests
|
|||
var map = Map.Maps[1];
|
||||
Assert.NotNull(map);
|
||||
|
||||
var coords = new (int, int)[]
|
||||
var coords = new[]
|
||||
{
|
||||
(1500, 1600), (1516, 1600), (1500, 1616), (1516, 1616), (1532, 1600)
|
||||
};
|
||||
|
|
@ -323,7 +323,7 @@ public class StepCacheFileTests
|
|||
cache.TryGetMask(map, x, y, sourceZ: 10);
|
||||
}
|
||||
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-preload-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-preload-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
Assert.Equal(coords.Length, cache.SaveToFile(path, map.MapID));
|
||||
|
|
@ -369,7 +369,7 @@ public class StepCacheFileTests
|
|||
|
||||
// Build + save one chunk.
|
||||
cache.TryGetMask(map, 1500, 1600, sourceZ: 10);
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-bypass-{System.Guid.NewGuid():N}.swb");
|
||||
var path = Path.Combine(Path.GetTempPath(), $"step-cache-bypass-{Guid.NewGuid():N}.swb");
|
||||
try
|
||||
{
|
||||
Assert.Equal(1, cache.SaveToFile(path, map.MapID));
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ public class StepCacheFileV6Tests
|
|||
for (var i = 0; i < StepChunk.CellsPerChunk; i++)
|
||||
{
|
||||
c.WalkMask[i] = (byte)(i & 0xFF);
|
||||
c.WetMask[i] = (byte)((~i) & 0xFF);
|
||||
c.SourceZ[i] = (sbyte)(baseZ + (i % 7) - 3); // varies, mostly != 0
|
||||
c.WetMask[i] = (byte)(~i & 0xFF);
|
||||
c.SourceZ[i] = (sbyte)(baseZ + i % 7 - 3); // varies, mostly != 0
|
||||
}
|
||||
SetFlatDirectional(c);
|
||||
return c;
|
||||
|
|
@ -78,9 +78,9 @@ public class StepCacheFileV6Tests
|
|||
{
|
||||
c.WalkMask[i] = (byte)(i & 0xFF);
|
||||
c.WetMask[i] = (byte)((i * 7) & 0xFF);
|
||||
c.SourceZ[i] = (sbyte)((i % 40) - 20);
|
||||
c.WalkZN[i] = (sbyte)(c.SourceZ[i] + (i % 3));
|
||||
c.SwimZS[i] = (sbyte)(c.SourceZ[i] - (i % 2));
|
||||
c.SourceZ[i] = (sbyte)(i % 40 - 20);
|
||||
c.WalkZN[i] = (sbyte)(c.SourceZ[i] + i % 3);
|
||||
c.SwimZS[i] = (sbyte)(c.SourceZ[i] - i % 2);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
|
@ -91,10 +91,10 @@ public class StepCacheFileV6Tests
|
|||
c.AllocateSwimLayer();
|
||||
for (var i = 0; i < StepChunk.CellsPerChunk; i++)
|
||||
{
|
||||
c.SwimSourceZ[i] = (sbyte)((i % 30) - 15);
|
||||
c.SwimSourceZ[i] = (sbyte)(i % 30 - 15);
|
||||
c.SwimMask[i] = (byte)((i * 5) & 0xFF);
|
||||
c.SwimZN_Layer[i] = (sbyte)(i % 7);
|
||||
c.SwimZNW_Layer[i] = (sbyte)(-(i % 4));
|
||||
c.SwimZNW_Layer[i] = (sbyte)-(i % 4);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ public class StepCacheFileV7Tests
|
|||
{
|
||||
c.WalkMask[i] = (byte)(i & 0xFF);
|
||||
c.WetMask[i] = (byte)((i * 7) & 0xFF);
|
||||
c.SourceZ[i] = (sbyte)((i % 40) - 20);
|
||||
c.WalkZN[i] = (sbyte)(c.SourceZ[i] + (i % 3));
|
||||
c.SwimZS[i] = (sbyte)(c.SourceZ[i] - (i % 2));
|
||||
c.SourceZ[i] = (sbyte)(i % 40 - 20);
|
||||
c.WalkZN[i] = (sbyte)(c.SourceZ[i] + i % 3);
|
||||
c.SwimZS[i] = (sbyte)(c.SourceZ[i] - i % 2);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ public class StepCacheFileV8Tests
|
|||
{
|
||||
c.WalkMask[i] = (byte)((i + seed) & 0xFF);
|
||||
c.WetMask[i] = (byte)((i * 7 + seed) & 0xFF);
|
||||
c.SourceZ[i] = (sbyte)(((i + seed) % 40) - 20);
|
||||
c.WalkZN[i] = (sbyte)(c.SourceZ[i] + (i % 3));
|
||||
c.SwimZS[i] = (sbyte)(c.SourceZ[i] - (i % 2));
|
||||
c.SourceZ[i] = (sbyte)((i + seed) % 40 - 20);
|
||||
c.WalkZN[i] = (sbyte)(c.SourceZ[i] + i % 3);
|
||||
c.SwimZS[i] = (sbyte)(c.SourceZ[i] - i % 2);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@ public class StepCacheLifecycleTests
|
|||
// Build 5 distinct chunks by querying different sectors.
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
var x = 1500 + (i * 16);
|
||||
var x = 1500 + i * 16;
|
||||
var y = 1600;
|
||||
cache.TryGetMask(map, x, y, 10);
|
||||
System.Threading.Thread.Sleep(2); // ensure LastTouchedTicks differs
|
||||
|
|
|
|||
|
|
@ -83,10 +83,11 @@ public class StepCacheParityTests
|
|||
wetCells++;
|
||||
}
|
||||
|
||||
if (lookup.WalkZ_N != baker.WalkZ_N || lookup.WalkZ_NE != baker.WalkZ_NE
|
||||
|| lookup.WalkZ_E != baker.WalkZ_E || lookup.WalkZ_SE != baker.WalkZ_SE
|
||||
|| lookup.WalkZ_S != baker.WalkZ_S || lookup.WalkZ_SW != baker.WalkZ_SW
|
||||
|| lookup.WalkZ_W != baker.WalkZ_W || lookup.WalkZ_NW != baker.WalkZ_NW)
|
||||
if (lookup.WalkZ_N != baker.WalkZ_N
|
||||
|| lookup.WalkZ_NE != baker.WalkZ_NE || lookup.WalkZ_E != baker.WalkZ_E
|
||||
|| lookup.WalkZ_SE != baker.WalkZ_SE || lookup.WalkZ_S != baker.WalkZ_S
|
||||
|| lookup.WalkZ_SW != baker.WalkZ_SW || lookup.WalkZ_W != baker.WalkZ_W
|
||||
|| lookup.WalkZ_NW != baker.WalkZ_NW)
|
||||
{
|
||||
disagreements++;
|
||||
_output.WriteLine($"Z DIFF @ ({x},{y}) cache=({lookup.WalkZ_N},{lookup.WalkZ_NE},{lookup.WalkZ_E},{lookup.WalkZ_SE},{lookup.WalkZ_S},{lookup.WalkZ_SW},{lookup.WalkZ_W},{lookup.WalkZ_NW}) baker=({baker.WalkZ_N},{baker.WalkZ_NE},{baker.WalkZ_E},{baker.WalkZ_SE},{baker.WalkZ_S},{baker.WalkZ_SW},{baker.WalkZ_W},{baker.WalkZ_NW})");
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class StaticWalkabilityParityTests
|
|||
// diagonal walkable iff raw-diagonal AND (left-partner OR right-partner).
|
||||
// (Raw masks are correct per spec; baker omits diagonal logic per design.)
|
||||
var newOk = bakerResult.IsWalkable(dir);
|
||||
if (newOk && ((d & 1) == 1))
|
||||
if (newOk && (d & 1) == 1)
|
||||
{
|
||||
var leftPartner = (Direction)((d - 1) & 7);
|
||||
var rightPartner = (Direction)((d + 1) & 7);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue