refactor(runtime): extract local teleport and player mode
Move local teleport, player-mode, animation, shadow, and sealed-dungeon lifetimes out of GameWindow. Make player-mode entry transactional and isolate approach completions by controller lifetime and approach generation so stale callbacks cannot affect replacements. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
parent
c557038353
commit
eeb0f6b45c
29 changed files with 3311 additions and 1073 deletions
|
|
@ -0,0 +1,93 @@
|
|||
using System.Numerics;
|
||||
using AcDream.App.Input;
|
||||
using AcDream.App.Physics;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Core.Physics.Motion;
|
||||
using DatReaderWriter.Types;
|
||||
using DatEnvCell = DatReaderWriter.DBObjs.EnvCell;
|
||||
|
||||
namespace AcDream.App.Tests.Input;
|
||||
|
||||
public sealed class PlayerMovementPlacementTransactionTests
|
||||
{
|
||||
private const uint PlayerGuid = 0x5000_0001u;
|
||||
private const uint TargetGuid = 0x7000_0001u;
|
||||
private const uint PriorCell = 0x0101_0101u;
|
||||
private const uint DestinationCell = 0x0101_0102u;
|
||||
|
||||
[Fact]
|
||||
public void PreparedPosition_DoesNotPublishRenderRootOrUnstickUntilCommit()
|
||||
{
|
||||
PhysicsEngine physics = PhysicsWithCells(PriorCell, DestinationCell);
|
||||
physics.UpdatePlayerCurrCell(PriorCell);
|
||||
var controller = new PlayerMovementController(physics);
|
||||
var hosts = new Dictionary<uint, IPhysicsObjHost>();
|
||||
IPhysicsObjHost? Resolve(uint id) => hosts.GetValueOrDefault(id);
|
||||
EntityPhysicsHost player = Host(PlayerGuid, Resolve);
|
||||
EntityPhysicsHost target = Host(TargetGuid, Resolve);
|
||||
hosts.Add(PlayerGuid, player);
|
||||
hosts.Add(TargetGuid, target);
|
||||
controller.PositionManager = player.PositionManager;
|
||||
player.PositionManager.StickTo(TargetGuid, 0.5f, 1.8f);
|
||||
|
||||
controller.PreparePositionForCommit(
|
||||
new Vector3(2f, 3f, 4f),
|
||||
DestinationCell,
|
||||
new Vector3(2f, 3f, 4f));
|
||||
|
||||
Assert.Equal(DestinationCell, controller.CellId);
|
||||
Assert.Equal(PriorCell, physics.DataCache!.CellGraph.CurrCell!.Id);
|
||||
Assert.Equal(TargetGuid, player.PositionManager.GetStickyObjectId());
|
||||
|
||||
controller.CommitPreparedPosition();
|
||||
|
||||
Assert.Equal(DestinationCell, physics.DataCache.CellGraph.CurrCell!.Id);
|
||||
Assert.Equal(0u, player.PositionManager.GetStickyObjectId());
|
||||
}
|
||||
|
||||
private static PhysicsEngine PhysicsWithCells(params uint[] cellIds)
|
||||
{
|
||||
var physics = new PhysicsEngine { DataCache = new PhysicsDataCache() };
|
||||
foreach (uint cellId in cellIds)
|
||||
{
|
||||
var cellStruct = new CellStruct
|
||||
{
|
||||
VertexArray = new VertexArray
|
||||
{
|
||||
Vertices = new Dictionary<ushort, SWVertex>(),
|
||||
},
|
||||
Polygons = new Dictionary<ushort, Polygon>(),
|
||||
};
|
||||
var envCell = new DatEnvCell
|
||||
{
|
||||
CellPortals = [],
|
||||
VisibleCells = [],
|
||||
};
|
||||
physics.DataCache.CacheCellStruct(
|
||||
cellId,
|
||||
envCell,
|
||||
cellStruct,
|
||||
Matrix4x4.Identity);
|
||||
}
|
||||
return physics;
|
||||
}
|
||||
|
||||
private static EntityPhysicsHost Host(
|
||||
uint guid,
|
||||
Func<uint, IPhysicsObjHost?> resolve) =>
|
||||
new(
|
||||
guid,
|
||||
getPosition: () => new AcDream.Core.Physics.Position(
|
||||
PriorCell,
|
||||
Vector3.Zero,
|
||||
Quaternion.Identity),
|
||||
getVelocity: () => Vector3.Zero,
|
||||
getRadius: () => 0.5f,
|
||||
inContact: () => true,
|
||||
minterpMaxSpeed: () => 1f,
|
||||
curTime: () => 0d,
|
||||
physicsTimerTime: () => 0d,
|
||||
getObjectA: resolve,
|
||||
handleUpdateTarget: _ => { },
|
||||
interruptCurrentMovement: () => { });
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue