feat(headless): hydrate isolated collision worlds
This commit is contained in:
parent
9569dadb57
commit
b6547ff38c
20 changed files with 1960 additions and 101 deletions
|
|
@ -13,6 +13,7 @@ using AcDream.Runtime;
|
|||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.Runtime.Session;
|
||||
using AcDream.Runtime.World;
|
||||
|
||||
namespace AcDream.Headless.Tests;
|
||||
|
||||
|
|
@ -186,6 +187,71 @@ public sealed class HeadlessSessionHostTests
|
|||
Assert.True(host.Runtime.CaptureOwnership().IsConverged);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WorldProjectionHydratesCanonicalMovementAndTeleportState()
|
||||
{
|
||||
var operations = new FixtureSessionOperations();
|
||||
using var credential = new HeadlessCredentialSecret(
|
||||
"fixture",
|
||||
"password");
|
||||
using var host = new HeadlessSessionHost(
|
||||
Descriptor(),
|
||||
credential,
|
||||
new HeadlessDiagnosticWriter(TextWriter.Null),
|
||||
operations);
|
||||
GameRuntime runtime = host.Runtime;
|
||||
const uint player = 0x50000002u;
|
||||
runtime.PlayerIdentity.ServerGuid = player;
|
||||
AddFlatLandblock(runtime.EntityObjects.Physics.Engine);
|
||||
RuntimeEntityRecord record = runtime.EntityObjects
|
||||
.RegisterEntity(Spawn(player))
|
||||
.Canonical!;
|
||||
Assert.True(runtime.EntityObjects.ApplyAcceptedSpawn(
|
||||
record,
|
||||
record.CreateIntegrationVersion,
|
||||
record.Snapshot,
|
||||
replaceGeneration: false));
|
||||
var collision = new FixtureCollisionNeighborhood();
|
||||
var projection = new HeadlessSessionWorldProjection(
|
||||
runtime,
|
||||
collision);
|
||||
|
||||
projection.ProjectSpawn(record, isLocalPlayer: true);
|
||||
PlayerMovementController controller =
|
||||
Assert.IsType<PlayerMovementController>(
|
||||
runtime.MovementOwner.Controller);
|
||||
projection.ProjectPosition(record, isLocalPlayer: true);
|
||||
|
||||
Assert.Same(controller, runtime.MovementOwner.Controller);
|
||||
Assert.Equal(record.LocalEntityId, controller.LocalEntityId);
|
||||
Assert.Equal(
|
||||
0xA9B40000u,
|
||||
controller.CellId & 0xFFFF0000u);
|
||||
Assert.True((controller.CellId & 0xFFFFu) < 0x0100u);
|
||||
projection.BeginTeleport();
|
||||
Assert.Equal(PlayerState.PortalSpace, controller.State);
|
||||
|
||||
RuntimeDestinationReadiness readiness =
|
||||
projection.PrepareDestination(
|
||||
revealGeneration: 7,
|
||||
new RuntimeTeleportDestination(
|
||||
player,
|
||||
InstanceSequence: 1,
|
||||
PositionSequence: 2,
|
||||
TeleportSequence: 1,
|
||||
ForcePositionSequence: 0,
|
||||
new Position(
|
||||
0xA9B40001u,
|
||||
new Vector3(96f, 97f, 50f),
|
||||
Quaternion.Identity)));
|
||||
|
||||
Assert.True(readiness.IsCollisionReady);
|
||||
Assert.False(readiness.IsUnhydratable);
|
||||
Assert.Equal(PlayerState.InWorld, controller.State);
|
||||
Assert.Equal(4, collision.CenterCount);
|
||||
Assert.Equal(0xA9B40001u, collision.LastCell);
|
||||
}
|
||||
|
||||
private static HeadlessSessionDescriptor Descriptor(
|
||||
HeadlessCredentialProviderKind provider =
|
||||
HeadlessCredentialProviderKind.Environment,
|
||||
|
|
@ -217,18 +283,7 @@ public sealed class HeadlessSessionHostTests
|
|||
{
|
||||
const uint player = 0x50000002u;
|
||||
PhysicsEngine engine = runtime.EntityObjects.Physics.Engine;
|
||||
var heights = new byte[81];
|
||||
Array.Fill(heights, (byte)50);
|
||||
var heightTable = new float[256];
|
||||
for (int index = 0; index < heightTable.Length; index++)
|
||||
heightTable[index] = index;
|
||||
engine.AddLandblock(
|
||||
0xA9B4FFFFu,
|
||||
new TerrainSurface(heights, heightTable),
|
||||
[],
|
||||
[],
|
||||
worldOffsetX: 0f,
|
||||
worldOffsetY: 0f);
|
||||
AddFlatLandblock(engine);
|
||||
|
||||
RuntimeEntityRecord record = runtime.EntityObjects
|
||||
.RegisterEntity(Spawn(player))
|
||||
|
|
@ -246,6 +301,22 @@ public sealed class HeadlessSessionHostTests
|
|||
runtime.MovementOwner.Controller = controller;
|
||||
}
|
||||
|
||||
private static void AddFlatLandblock(PhysicsEngine engine)
|
||||
{
|
||||
var heights = new byte[81];
|
||||
Array.Fill(heights, (byte)50);
|
||||
var heightTable = new float[256];
|
||||
for (int index = 0; index < heightTable.Length; index++)
|
||||
heightTable[index] = index;
|
||||
engine.AddLandblock(
|
||||
0xA9B4FFFFu,
|
||||
new TerrainSurface(heights, heightTable),
|
||||
[],
|
||||
[],
|
||||
worldOffsetX: 0f,
|
||||
worldOffsetY: 0f);
|
||||
}
|
||||
|
||||
private static WorldSession.EntitySpawn Spawn(uint guid)
|
||||
{
|
||||
var position = new CreateObject.ServerPosition(
|
||||
|
|
@ -389,4 +460,20 @@ public sealed class HeadlessSessionHostTests
|
|||
}
|
||||
}
|
||||
|
||||
private sealed class FixtureCollisionNeighborhood
|
||||
: IHeadlessCollisionNeighborhood
|
||||
{
|
||||
public int CenterCount { get; private set; }
|
||||
public uint LastCell { get; private set; }
|
||||
|
||||
public void CenterOn(uint fullCellId)
|
||||
{
|
||||
CenterCount++;
|
||||
LastCell = fullCellId;
|
||||
}
|
||||
|
||||
public bool IsReady(uint fullCellId) =>
|
||||
fullCellId == LastCell;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue