feat(vfx): port retail hidden and teleport presentation
Preserve canonical live-object ownership across Hidden transitions and remote teleport placement so effects, collision, streaming, and targeting remain synchronized.
This commit is contained in:
parent
a51ebc66e9
commit
1e98d81448
46 changed files with 4883 additions and 127 deletions
|
|
@ -52,6 +52,96 @@ public sealed class ProjectileControllerTests
|
|||
Assert.Same(record.ProjectileRuntime!.Body, record.PhysicsBody);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Hidden_PausesProjectileWithoutClearingActiveOrReplayingClockBacklog()
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
LiveEntityRecord record = fixture.Spawn(instance: 1);
|
||||
WorldEntity entity = record.WorldEntity!;
|
||||
fixture.Engine.ShadowObjects.Register(
|
||||
entity.Id,
|
||||
entity.SourceGfxObjOrSetupId,
|
||||
entity.Position,
|
||||
entity.Rotation,
|
||||
radius: 0.5f,
|
||||
worldOffsetX: 0f,
|
||||
worldOffsetY: 0f,
|
||||
landblockId: 0x01010000u,
|
||||
state: (uint)MissileState,
|
||||
seedCellId: CellA);
|
||||
Assert.True(fixture.Controller.TryBind(record, ProjectileSetup(), 1.0, 1, 1));
|
||||
PhysicsBody body = record.PhysicsBody!;
|
||||
Assert.True(body.IsActive);
|
||||
|
||||
record.FinalPhysicsState = MissileState
|
||||
| PhysicsStateFlags.Hidden
|
||||
| PhysicsStateFlags.IgnoreCollisions;
|
||||
Assert.True(fixture.Controller.ApplyAuthoritativeState(
|
||||
Guid, record.FinalPhysicsState, 1.1, 1, 1));
|
||||
Vector3 hiddenPosition = entity.Position;
|
||||
fixture.Controller.Tick(5.0, 1, 1, playerWorldPosition: null);
|
||||
|
||||
Assert.Equal(hiddenPosition, entity.Position);
|
||||
Assert.True(body.InWorld);
|
||||
Assert.True(body.IsActive);
|
||||
Assert.Equal(5.0, body.LastUpdateTime, 8);
|
||||
Assert.Equal(0, fixture.Engine.ShadowObjects.TotalRegistered);
|
||||
|
||||
record.FinalPhysicsState = MissileState;
|
||||
Assert.True(fixture.Controller.ApplyAuthoritativeState(
|
||||
Guid, record.FinalPhysicsState, 5.0, 1, 1));
|
||||
fixture.Controller.Tick(5.1, 1, 1, playerWorldPosition: null);
|
||||
|
||||
Assert.True(entity.Position.X > hiddenPosition.X);
|
||||
Assert.True(entity.Position.X < hiddenPosition.X + 2f);
|
||||
Assert.Equal(1, fixture.Engine.ShadowObjects.TotalRegistered);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HiddenSharedRemoteProjectile_UsesPositionManagerNarrowTickExactlyOnce()
|
||||
{
|
||||
var fixture = new Fixture();
|
||||
LiveEntityRecord record = fixture.Spawn(instance: 1);
|
||||
WorldEntity entity = record.WorldEntity!;
|
||||
Assert.Null(record.AnimationRuntime);
|
||||
var remote = new GameWindow.RemoteMotion();
|
||||
RemotePhysicsBodyInitializer.Initialize(remote.Body, record);
|
||||
remote.Body.Position = entity.Position;
|
||||
remote.Body.Orientation = entity.Rotation;
|
||||
fixture.Live.SetRemoteMotionRuntime(Guid, remote);
|
||||
Assert.True(fixture.Controller.TryBind(record, ProjectileSetup(), 1.0, 1, 1));
|
||||
Assert.Same(remote.Body, record.ProjectileRuntime!.Body);
|
||||
|
||||
record.FinalPhysicsState = MissileState
|
||||
| PhysicsStateFlags.Hidden
|
||||
| PhysicsStateFlags.IgnoreCollisions;
|
||||
Assert.True(fixture.Controller.ApplyAuthoritativeState(
|
||||
Guid, record.FinalPhysicsState, 1.1, 1, 1));
|
||||
remote.Interp.Enqueue(
|
||||
entity.Position + Vector3.UnitX,
|
||||
heading: 0f,
|
||||
isMovingTo: false,
|
||||
currentBodyPosition: remote.Body.Position);
|
||||
var updater = new RemotePhysicsUpdater(
|
||||
fixture.Engine,
|
||||
(_, _) => (0.48f, 1.835f),
|
||||
(_, _, _, _) => { });
|
||||
|
||||
int publishedRoots = 0;
|
||||
updater.TickHiddenEntities(
|
||||
fixture.Live,
|
||||
localPlayerServerGuid: 0x50000001u,
|
||||
dt: 0.1f,
|
||||
_ => publishedRoots++);
|
||||
Vector3 afterNarrowTick = entity.Position;
|
||||
fixture.Controller.Tick(1.2, 1, 1, playerWorldPosition: null);
|
||||
|
||||
Assert.True(afterNarrowTick.X > 10f);
|
||||
Assert.Equal(afterNarrowTick, entity.Position);
|
||||
Assert.Equal(1, publishedRoots);
|
||||
Assert.True(fixture.Controller.HandlesMovement(Guid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PendingDestinationAndLaterHydration_RetainIdentityAndProjectileOwner()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue