refactor(runtime): own canonical entity and object lifetime
Introduce one presentation-free RuntimeEntityObjectLifetime for the exact entity directory and ClientObjectTable. Make GameWindow, graphical projections, retained UI, interaction, session routing, create/delete integration, and reset borrow that owner while preserving synchronous retail ordering, dormant retention, and retry semantics. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
d9bf4c4960
commit
5ef8b5371d
40 changed files with 712 additions and 170 deletions
|
|
@ -25,6 +25,7 @@ using AcDream.Core.Rendering;
|
|||
using AcDream.Core.Selection;
|
||||
using AcDream.Core.Vfx;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Runtime.Entities;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using Silk.NET.OpenGL;
|
||||
|
|
@ -44,7 +45,7 @@ internal sealed record LivePresentationDependencies(
|
|||
WorldGameState WorldGameState,
|
||||
WorldEvents WorldEvents,
|
||||
SelectionState Selection,
|
||||
ClientObjectTable Objects,
|
||||
RuntimeEntityObjectLifetime EntityObjects,
|
||||
LiveEntityRuntimeSlot RuntimeSlot,
|
||||
DeferredLiveEntityMotionRuntimeBindings MotionBindings,
|
||||
DeferredEntityEffectAdvanceSource EffectAdvance,
|
||||
|
|
@ -377,7 +378,8 @@ internal sealed class LivePresentationCompositionPhase
|
|||
worldState,
|
||||
new CompositeLiveEntityResourceLifecycle(
|
||||
[.. resourceOwners]),
|
||||
componentLifecycle);
|
||||
componentLifecycle,
|
||||
d.EntityObjects);
|
||||
var liveRuntimeLease = scope.Own(
|
||||
"canonical live-entity runtime",
|
||||
liveEntities,
|
||||
|
|
@ -487,7 +489,7 @@ internal sealed class LivePresentationCompositionPhase
|
|||
() => new EquippedChildRenderController(
|
||||
content.Dats,
|
||||
d.DatLock,
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
liveEntities,
|
||||
d.EffectPoses,
|
||||
parentAcceptance.TryAccept,
|
||||
|
|
@ -675,7 +677,7 @@ internal sealed class LivePresentationCompositionPhase
|
|||
static value => value.Dispose());
|
||||
var selectionQuery = new WorldSelectionQuery(
|
||||
liveEntities,
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
selectionScene,
|
||||
() => d.PlayerIdentity.ServerGuid,
|
||||
interaction.LateBindings.SelectionCamera.Snapshot,
|
||||
|
|
@ -699,7 +701,7 @@ internal sealed class LivePresentationCompositionPhase
|
|||
}
|
||||
});
|
||||
var radarSnapshotProvider = new RadarSnapshotProvider(
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
liveEntities,
|
||||
() => liveEntities.Snapshots,
|
||||
playerGuid: () => d.PlayerIdentity.ServerGuid,
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ using AcDream.Core.Player;
|
|||
using AcDream.Core.Social;
|
||||
using AcDream.Core.Spells;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Session;
|
||||
using Silk.NET.Windowing;
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ internal sealed record SessionPlayerDependencies(
|
|||
WorldGameState WorldGameState,
|
||||
WorldEvents WorldEvents,
|
||||
SelectionState Selection,
|
||||
ClientObjectTable Objects,
|
||||
RuntimeEntityObjectLifetime EntityObjects,
|
||||
EntityClassificationCache ClassificationCache,
|
||||
LiveEntityRuntimeSlot RuntimeSlot,
|
||||
LiveEntityAnimationRuntimeView<LiveEntityAnimationState> AnimatedEntities,
|
||||
|
|
@ -475,14 +476,14 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
var dormantLiveEntities = new DormantLiveEntityStore();
|
||||
var deletion = new LiveEntityDeletionController(
|
||||
live.LiveEntities,
|
||||
d.Objects,
|
||||
d.EntityObjects,
|
||||
teardown,
|
||||
d.PlayerIdentity,
|
||||
dormantLiveEntities,
|
||||
d.Options.DumpLiveSpawns ? d.Log : null);
|
||||
var hydration = new LiveEntityHydrationController(
|
||||
live.LiveEntities,
|
||||
d.Objects,
|
||||
d.EntityObjects,
|
||||
d.DatLock,
|
||||
projectionMaterializer,
|
||||
new LiveEntityRelationshipProjection(live.EquippedChildren),
|
||||
|
|
@ -505,7 +506,7 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
|
||||
var networkUpdates = new LiveEntityNetworkUpdateController(
|
||||
live.LiveEntities,
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
hydration,
|
||||
live.EntityEffects,
|
||||
live.Presentation,
|
||||
|
|
@ -574,7 +575,7 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
new CombatAttackTargetSource(
|
||||
d.Selection,
|
||||
live.LiveEntities,
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
d.PlayerIdentity),
|
||||
d.Settings,
|
||||
d.PlayerController,
|
||||
|
|
@ -809,7 +810,7 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
d.Shortcuts,
|
||||
d.DesiredComponents),
|
||||
new LiveSessionDomainRuntime(
|
||||
d.Objects,
|
||||
d.EntityObjects,
|
||||
d.LocalPlayer,
|
||||
d.Spellbook,
|
||||
d.Combat,
|
||||
|
|
@ -873,7 +874,7 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
var combatCommand = new LiveCombatModeCommandController(
|
||||
new LiveSessionCombatModeAuthority(sessionHost),
|
||||
new LocalPlayerCombatEquipmentSource(
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
d.PlayerIdentity),
|
||||
d.Combat,
|
||||
new ItemInteractionCombatModeIntentSink(
|
||||
|
|
@ -890,7 +891,7 @@ internal sealed class SessionPlayerCompositionPhase
|
|||
liveSessionCommands,
|
||||
d.PlayerIdentity,
|
||||
live.LiveEntities,
|
||||
d.Objects,
|
||||
d.EntityObjects.Objects,
|
||||
d.Chat,
|
||||
d.PlayerController,
|
||||
worldReveal,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ using AcDream.Core.Social;
|
|||
using AcDream.Core.Spells;
|
||||
using AcDream.Core.World;
|
||||
using AcDream.Content;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Session;
|
||||
using AcDream.UI.Abstractions.Panels.Chat;
|
||||
using AcDream.UI.Abstractions.Panels.Vitals;
|
||||
|
|
@ -41,7 +42,7 @@ internal sealed record LiveSessionPlayerRuntime(
|
|||
DesiredComponentSnapshotState DesiredComponents);
|
||||
|
||||
internal sealed record LiveSessionDomainRuntime(
|
||||
ClientObjectTable Objects,
|
||||
RuntimeEntityObjectLifetime EntityObjects,
|
||||
LocalPlayerState LocalPlayer,
|
||||
Spellbook Spellbook,
|
||||
CombatState Combat,
|
||||
|
|
@ -173,7 +174,7 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
ExternalContainer = () => _domain.ExternalContainers.Reset(),
|
||||
InteractionAndSelection = _interaction.SelectionInteractions.ResetSession,
|
||||
SelectionPresentation = _world.SelectionScene.Reset,
|
||||
ObjectTable = _domain.Objects.Clear,
|
||||
ObjectTable = _domain.EntityObjects.ClearObjects,
|
||||
Spellbook = _domain.Spellbook.Clear,
|
||||
MagicRuntime = () => _ui.Magic?.Reset(),
|
||||
CombatAttack = _interaction.CombatAttack.ResetSession,
|
||||
|
|
@ -260,7 +261,7 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
}
|
||||
|
||||
private LiveInventorySessionBindings CreateInventoryBindings() => new(
|
||||
_domain.Objects,
|
||||
_domain.EntityObjects.Objects,
|
||||
_domain.LocalPlayer,
|
||||
PlayerGuid: () => _player.Identity.ServerGuid,
|
||||
OnShortcuts: list => _player.Shortcuts.Items = list,
|
||||
|
|
@ -333,7 +334,7 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
ShowSystemMessage: text => _domain.Chat.OnSystemMessage(text, 0u),
|
||||
ShowWeenieError: code => _domain.Chat.OnWeenieError(code, null),
|
||||
PlayerPublicWeenieBitfield: () =>
|
||||
_domain.Objects.Get(_player.Identity.ServerGuid)?
|
||||
_domain.EntityObjects.Objects.Get(_player.Identity.ServerGuid)?
|
||||
.PublicWeenieBitfield,
|
||||
ClientVersion: () =>
|
||||
typeof(LiveSessionRuntimeFactory).Assembly
|
||||
|
|
@ -351,7 +352,7 @@ internal sealed class LiveSessionRuntimeFactory
|
|||
SaveAutoUi: () => _ui.RetailUi?.SaveLayout(),
|
||||
LoadAutoUi: () => _ui.RetailUi?.RestoreLayout(),
|
||||
IsAway: () =>
|
||||
_domain.Objects.Get(_player.Identity.ServerGuid)?
|
||||
_domain.EntityObjects.Objects.Get(_player.Identity.ServerGuid)?
|
||||
.Properties.GetBool(0x6Eu) == true,
|
||||
SetAway: session.SendSetAfkMode,
|
||||
SetAwayMessage: session.SendSetAfkMessage,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using AcDream.App.Rendering.Wb;
|
|||
using AcDream.App.Settings;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Content;
|
||||
using AcDream.Runtime.Entities;
|
||||
using AcDream.Runtime.Session;
|
||||
using DatReaderWriter;
|
||||
using Silk.NET.Input;
|
||||
|
|
@ -340,7 +341,7 @@ public sealed class GameWindow :
|
|||
// installs that immutable table once DatCollection opens in OnLoad.
|
||||
public AcDream.Core.Spells.SpellTable SpellTable => SpellBook.Metadata;
|
||||
public readonly AcDream.Core.Spells.Spellbook SpellBook = null!;
|
||||
public readonly AcDream.Core.Items.ClientObjectTable Objects = new();
|
||||
private readonly RuntimeEntityObjectLifetime _runtimeEntityObjects = new();
|
||||
/// <summary>Persisted hotbar shortcuts from the last PlayerDescription (D.5.1 toolbar source).</summary>
|
||||
private readonly ShortcutSnapshotState _shortcutSnapshots = new();
|
||||
public IReadOnlyList<AcDream.Core.Items.ShortcutEntry> Shortcuts
|
||||
|
|
@ -1260,7 +1261,7 @@ public sealed class GameWindow :
|
|||
_combatAttackOperations,
|
||||
_selection,
|
||||
_externalContainers,
|
||||
Objects,
|
||||
_runtimeEntityObjects.Objects,
|
||||
contentEffectsAudio.MagicCatalog,
|
||||
SpellBook,
|
||||
Chat,
|
||||
|
|
@ -1314,7 +1315,7 @@ public sealed class GameWindow :
|
|||
_worldGameState,
|
||||
_worldEvents,
|
||||
_selection,
|
||||
Objects,
|
||||
_runtimeEntityObjects,
|
||||
_liveEntityRuntimeSlot,
|
||||
_liveEntityMotionBindings,
|
||||
_entityEffectAdvance,
|
||||
|
|
@ -1372,7 +1373,7 @@ public sealed class GameWindow :
|
|||
_worldGameState,
|
||||
_worldEvents,
|
||||
_selection,
|
||||
Objects,
|
||||
_runtimeEntityObjects,
|
||||
_classificationCache,
|
||||
_liveEntityRuntimeSlot,
|
||||
_animatedEntities,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using AcDream.App.Input;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Runtime.Entities;
|
||||
|
||||
namespace AcDream.App.World;
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ internal interface ILiveEntityPruneSink
|
|||
internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
||||
{
|
||||
private readonly LiveEntityRuntime _runtime;
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly ILiveEntityTeardownCoordinator _teardown;
|
||||
private readonly ILocalPlayerIdentitySource _identity;
|
||||
private readonly DormantLiveEntityStore _dormant;
|
||||
|
|
@ -25,14 +25,15 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
|
||||
public LiveEntityDeletionController(
|
||||
LiveEntityRuntime runtime,
|
||||
ClientObjectTable objects,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
ILiveEntityTeardownCoordinator teardown,
|
||||
ILocalPlayerIdentitySource identity,
|
||||
DormantLiveEntityStore? dormant = null,
|
||||
Action<string>? diagnostic = null)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_teardown = teardown ?? throw new ArgumentNullException(nameof(teardown));
|
||||
_identity = identity ?? throw new ArgumentNullException(nameof(identity));
|
||||
_dormant = dormant ?? new DormantLiveEntityStore();
|
||||
|
|
@ -56,11 +57,10 @@ internal sealed class LiveEntityDeletionController : ILiveEntityPruneSink
|
|||
bool removed = _runtime.UnregisterLiveEntity(
|
||||
delete,
|
||||
isLocalPlayer: false,
|
||||
beforeTeardown: () =>
|
||||
ObjectTableWiring.ApplyEntityDelete(_objects, delete));
|
||||
removeRetainedObject: true);
|
||||
bool removedDormant = _dormant.RemoveExact(delete);
|
||||
if (!removed && removedDormant)
|
||||
ObjectTableWiring.ApplyEntityDelete(_objects, delete);
|
||||
_entityObjects.ApplyAcceptedDormantDelete(delete);
|
||||
if (removed)
|
||||
{
|
||||
_dormant.RemoveExact(delete);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using AcDream.App.Rendering;
|
||||
using AcDream.App.Input;
|
||||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.World;
|
||||
|
|
@ -169,7 +168,7 @@ internal interface ILiveEntityWorldOriginCoordinator
|
|||
internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoadedSink
|
||||
{
|
||||
private readonly LiveEntityRuntime _runtime;
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly object _datLock;
|
||||
private readonly ILiveEntityProjectionMaterializer _materializer;
|
||||
private readonly ILiveEntityRelationshipProjection _relationships;
|
||||
|
|
@ -193,7 +192,7 @@ internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoaded
|
|||
|
||||
public LiveEntityHydrationController(
|
||||
LiveEntityRuntime runtime,
|
||||
ClientObjectTable objects,
|
||||
RuntimeEntityObjectLifetime entityObjects,
|
||||
object datLock,
|
||||
ILiveEntityProjectionMaterializer materializer,
|
||||
ILiveEntityRelationshipProjection relationships,
|
||||
|
|
@ -207,7 +206,8 @@ internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoaded
|
|||
Action<string>? diagnostic = null)
|
||||
{
|
||||
_runtime = runtime ?? throw new ArgumentNullException(nameof(runtime));
|
||||
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_datLock = datLock ?? throw new ArgumentNullException(nameof(datLock));
|
||||
_materializer = materializer ?? throw new ArgumentNullException(nameof(materializer));
|
||||
_relationships = relationships ?? throw new ArgumentNullException(nameof(relationships));
|
||||
|
|
@ -285,15 +285,13 @@ internal sealed class LiveEntityHydrationController : ILiveEntityLandblockLoaded
|
|||
if (_runtime.IsCurrentCreateIntegration(
|
||||
canonical,
|
||||
createIntegrationVersion)
|
||||
&& ObjectTableWiring.ApplyEntitySpawn(
|
||||
_objects,
|
||||
&& _entityObjects.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
createIntegrationVersion,
|
||||
spawn,
|
||||
replaceGeneration: result.Disposition is
|
||||
AcDream.Core.Physics.CreateObjectTimestampDisposition.NewGeneration
|
||||
|| dormantDisposition is DormantCreateDisposition.NewGeneration,
|
||||
accepting: () => _runtime.IsCurrentCreateIntegration(
|
||||
canonical,
|
||||
createIntegrationVersion))
|
||||
|| dormantDisposition is DormantCreateDisposition.NewGeneration)
|
||||
&& _runtime.IsCurrentCreateIntegration(
|
||||
canonical,
|
||||
createIntegrationVersion))
|
||||
|
|
|
|||
|
|
@ -448,6 +448,7 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
private readonly GpuWorldState _spatial;
|
||||
private readonly ILiveEntityResourceLifecycle _resources;
|
||||
private readonly ILiveEntityRuntimeComponentLifecycle _runtimeComponentLifecycle;
|
||||
private readonly RuntimeEntityObjectLifetime _entityObjects;
|
||||
private readonly RuntimeEntityDirectory _directory;
|
||||
private readonly LiveEntityProjectionStore _projections;
|
||||
// Logical components survive retail's 25-second leave-visibility lifetime.
|
||||
|
|
@ -471,12 +472,12 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
public LiveEntityRuntime(
|
||||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
uint firstLocalEntityId = FirstLiveEntityId)
|
||||
RuntimeEntityObjectLifetime entityObjects)
|
||||
: this(
|
||||
spatial,
|
||||
resources,
|
||||
NullLiveEntityRuntimeComponentLifecycle.Instance,
|
||||
firstLocalEntityId)
|
||||
entityObjects)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -484,12 +485,12 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
Action<LiveEntityRecord> tearDownRuntimeComponents,
|
||||
uint firstLocalEntityId = FirstLiveEntityId)
|
||||
RuntimeEntityObjectLifetime entityObjects)
|
||||
: this(
|
||||
spatial,
|
||||
resources,
|
||||
new DelegateLiveEntityRuntimeComponentLifecycle(tearDownRuntimeComponents),
|
||||
firstLocalEntityId)
|
||||
entityObjects)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -497,13 +498,15 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
ILiveEntityRuntimeComponentLifecycle? runtimeComponentLifecycle,
|
||||
uint firstLocalEntityId = FirstLiveEntityId)
|
||||
RuntimeEntityObjectLifetime entityObjects)
|
||||
{
|
||||
_spatial = spatial ?? throw new ArgumentNullException(nameof(spatial));
|
||||
_resources = resources ?? throw new ArgumentNullException(nameof(resources));
|
||||
_runtimeComponentLifecycle = runtimeComponentLifecycle
|
||||
?? throw new ArgumentNullException(nameof(runtimeComponentLifecycle));
|
||||
_directory = new RuntimeEntityDirectory(firstLocalEntityId);
|
||||
_entityObjects = entityObjects
|
||||
?? throw new ArgumentNullException(nameof(entityObjects));
|
||||
_directory = _entityObjects.Entities;
|
||||
_projections = new LiveEntityProjectionStore(_directory);
|
||||
_spatial.LiveProjectionVisibilityChanged += OnSpatialVisibilityChanged;
|
||||
}
|
||||
|
|
@ -1187,6 +1190,7 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
public bool UnregisterLiveEntity(
|
||||
DeleteObject.Parsed delete,
|
||||
bool isLocalPlayer,
|
||||
bool removeRetainedObject = false,
|
||||
Action? beforeTeardown = null)
|
||||
{
|
||||
if (_isRegisteringResources)
|
||||
|
|
@ -1208,9 +1212,13 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
&& (record.DeleteAcceptedForTeardown
|
||||
|| _isClearing
|
||||
|| _sessionClearPendingFinalization);
|
||||
RuntimeEntityDeleteAcceptance? acceptedDelete = null;
|
||||
if (!retryingAcceptedDelete)
|
||||
{
|
||||
if (!_directory.TryDelete(delete, isLocalPlayer))
|
||||
if (!_entityObjects.TryAcceptDelete(
|
||||
delete,
|
||||
isLocalPlayer,
|
||||
out acceptedDelete))
|
||||
return false;
|
||||
AdvanceLifetimeMutation(delete.Guid);
|
||||
ParentAttachments.DeleteGeneration(delete.Guid, delete.InstanceSequence);
|
||||
|
|
@ -1258,6 +1266,18 @@ public sealed class LiveEntityRuntime : ILiveEntityRadarSource
|
|||
{
|
||||
if (!retryingAcceptedDelete)
|
||||
{
|
||||
if (removeRetainedObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
_entityObjects.CompleteAcceptedDelete(acceptedDelete!);
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
(failures ??= new List<Exception>()).Add(error);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
beforeTeardown?.Invoke();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ namespace AcDream.Core.Net;
|
|||
/// 64-bit qualities (experience), SetStackSize (0x0197) = stack count,
|
||||
/// InventoryRemoveObject (0x0024) = inventory-view removal.
|
||||
/// CreateObject/DeleteObject application remains exposed as pure helpers so
|
||||
/// the App live-entity owner can freshness-gate the shared projections first.
|
||||
/// the Runtime entity/object lifetime owner can freshness-gate the canonical
|
||||
/// incarnation before either graphical or retained-object projections mutate.
|
||||
/// Retail: ACCObjectMaint::CreateObject / DeleteObject (the weenie_object_table side).
|
||||
/// </summary>
|
||||
public static class ObjectTableWiring
|
||||
|
|
|
|||
135
src/AcDream.Runtime/Entities/RuntimeEntityObjectLifetime.cs
Normal file
135
src/AcDream.Runtime/Entities/RuntimeEntityObjectLifetime.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
using AcDream.Core.Items;
|
||||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
|
||||
namespace AcDream.Runtime.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// One exact DeleteObject acceptance issued by a
|
||||
/// <see cref="RuntimeEntityObjectLifetime"/>. The graphical host retires the
|
||||
/// active identity before returning this token to the Runtime owner for the
|
||||
/// retained-object mutation, preserving retail callback order.
|
||||
/// </summary>
|
||||
public sealed class RuntimeEntityDeleteAcceptance
|
||||
{
|
||||
internal RuntimeEntityDeleteAcceptance(
|
||||
RuntimeEntityObjectLifetime owner,
|
||||
DeleteObject.Parsed delete)
|
||||
{
|
||||
Owner = owner;
|
||||
Delete = delete;
|
||||
}
|
||||
|
||||
internal RuntimeEntityObjectLifetime Owner { get; }
|
||||
internal bool Completed { get; set; }
|
||||
public DeleteObject.Parsed Delete { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Presentation-free ownership root for one session's canonical entity and
|
||||
/// retained object lifetimes. Graphical and direct hosts borrow these exact
|
||||
/// instances; they never allocate a second directory or object table.
|
||||
/// </summary>
|
||||
public sealed class RuntimeEntityObjectLifetime
|
||||
{
|
||||
public RuntimeEntityObjectLifetime(
|
||||
uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId)
|
||||
{
|
||||
Entities = new RuntimeEntityDirectory(firstLocalEntityId);
|
||||
Objects = new ClientObjectTable();
|
||||
}
|
||||
|
||||
public RuntimeEntityDirectory Entities { get; }
|
||||
public ClientObjectTable Objects { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Applies the retained-object half of an accepted CreateObject while the
|
||||
/// exact canonical incarnation and its integration version remain current.
|
||||
/// Object-table callbacks are synchronous and may re-enter entity lifetime,
|
||||
/// so the acceptance predicate is checked before, during, and after apply.
|
||||
/// </summary>
|
||||
public bool ApplyAcceptedSpawn(
|
||||
RuntimeEntityRecord canonical,
|
||||
ulong expectedCreateIntegrationVersion,
|
||||
WorldSession.EntitySpawn spawn,
|
||||
bool replaceGeneration)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(canonical);
|
||||
if (canonical.ServerGuid != spawn.Guid
|
||||
|| canonical.Incarnation != spawn.InstanceSequence)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsCurrent() =>
|
||||
Entities.IsCurrent(canonical)
|
||||
&& canonical.CreateIntegrationVersion
|
||||
== expectedCreateIntegrationVersion;
|
||||
|
||||
return IsCurrent()
|
||||
&& ObjectTableWiring.ApplyEntitySpawn(
|
||||
Objects,
|
||||
spawn,
|
||||
replaceGeneration,
|
||||
IsCurrent)
|
||||
&& IsCurrent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Accepts the exact DeleteObject generation without yet publishing the
|
||||
/// retained-object removal. This split lets the graphical host retire the
|
||||
/// active identity first, matching the established reentrant callback
|
||||
/// order, while Runtime remains the only freshness authority.
|
||||
/// </summary>
|
||||
public bool TryAcceptDelete(
|
||||
DeleteObject.Parsed delete,
|
||||
bool isLocalPlayer,
|
||||
out RuntimeEntityDeleteAcceptance acceptance)
|
||||
{
|
||||
if (!Entities.TryDelete(delete, isLocalPlayer))
|
||||
{
|
||||
acceptance = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
acceptance = new RuntimeEntityDeleteAcceptance(this, delete);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Completes a previously accepted delete exactly once. Marking the token
|
||||
/// complete before synchronous callbacks preserves the current retry rule:
|
||||
/// a throwing observer does not replay an already-committed removal.
|
||||
/// </summary>
|
||||
public void CompleteAcceptedDelete(
|
||||
RuntimeEntityDeleteAcceptance acceptance)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(acceptance);
|
||||
if (!ReferenceEquals(acceptance.Owner, this))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"A delete acceptance belongs to a different Runtime lifetime.");
|
||||
}
|
||||
if (acceptance.Completed)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"A delete acceptance has already been completed.");
|
||||
}
|
||||
|
||||
acceptance.Completed = true;
|
||||
ObjectTableWiring.ApplyEntityDelete(Objects, acceptance.Delete);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a delete accepted by the dormant exact-incarnation owner after
|
||||
/// the active Runtime directory correctly reports no live record.
|
||||
/// </summary>
|
||||
public void ApplyAcceptedDormantDelete(DeleteObject.Parsed delete) =>
|
||||
ObjectTableWiring.ApplyEntityDelete(Objects, delete);
|
||||
|
||||
/// <summary>
|
||||
/// Clears retained object state at the Runtime-owned reset stage. App
|
||||
/// projection teardown remains a later acknowledged stage.
|
||||
/// </summary>
|
||||
public void ClearObjects() => Objects.Clear();
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ public sealed class CombatAttackTargetSourceTests
|
|||
0x0101_FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Runtime = new LiveEntityRuntime(spatial, new Resources());
|
||||
Runtime = LiveEntityRuntimeFixture.Create(spatial, new Resources());
|
||||
var identity = new LocalPlayerIdentityState { ServerGuid = Player };
|
||||
Targets = new CombatAttackTargetSource(
|
||||
Selection,
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ public sealed class LivePresentationCompositionTests
|
|||
Assert.Contains("d.PortalTunnelFallback.AcquirePrepared(", phase);
|
||||
}
|
||||
|
||||
private static LiveEntityRuntime Runtime() => new(
|
||||
private static LiveEntityRuntime Runtime() => LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(static _ => { }, static _ => { }));
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public sealed class WorldSelectionQueryTests
|
|||
0x0101_FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Runtime = new LiveEntityRuntime(spatial, new Resources());
|
||||
Runtime = LiveEntityRuntimeFixture.Create(spatial, new Resources());
|
||||
Scene = new RetailSelectionScene(new GeometrySource(Mesh()));
|
||||
Query = new WorldSelectionQuery(
|
||||
Runtime,
|
||||
|
|
|
|||
50
tests/AcDream.App.Tests/LiveEntityRuntimeFixture.cs
Normal file
50
tests/AcDream.App.Tests/LiveEntityRuntimeFixture.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using AcDream.App.Streaming;
|
||||
using AcDream.App.World;
|
||||
using AcDream.Runtime.Entities;
|
||||
|
||||
namespace AcDream.App.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Explicit isolated lifetime-group seam for App projection tests. Production
|
||||
/// composition supplies its session-owned group from GameWindow; focused tests
|
||||
/// use a fresh group per runtime so identity never leaks between fixtures.
|
||||
/// </summary>
|
||||
internal static class LiveEntityRuntimeFixture
|
||||
{
|
||||
public static LiveEntityRuntime Create(
|
||||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId)
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime(firstLocalEntityId);
|
||||
return new LiveEntityRuntime(spatial, resources, lifetime);
|
||||
}
|
||||
|
||||
public static LiveEntityRuntime Create(
|
||||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
Action<LiveEntityRecord> tearDownRuntimeComponents,
|
||||
uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId)
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime(firstLocalEntityId);
|
||||
return new LiveEntityRuntime(
|
||||
spatial,
|
||||
resources,
|
||||
tearDownRuntimeComponents,
|
||||
lifetime);
|
||||
}
|
||||
|
||||
public static LiveEntityRuntime Create(
|
||||
GpuWorldState spatial,
|
||||
ILiveEntityResourceLifecycle resources,
|
||||
ILiveEntityRuntimeComponentLifecycle runtimeComponentLifecycle,
|
||||
uint firstLocalEntityId = RuntimeEntityDirectory.FirstLocalEntityId)
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime(firstLocalEntityId);
|
||||
return new LiveEntityRuntime(
|
||||
spatial,
|
||||
resources,
|
||||
runtimeComponentLifecycle,
|
||||
lifetime);
|
||||
}
|
||||
}
|
||||
|
|
@ -210,7 +210,7 @@ public sealed class LiveSessionResetPlanTests
|
|||
landblock,
|
||||
new LandBlock(),
|
||||
new List<WorldEntity> { staticEntity }));
|
||||
var live = new LiveEntityRuntime(spatial, new FailingOnceResources());
|
||||
var live = LiveEntityRuntimeFixture.Create(spatial, new FailingOnceResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(playerA, 1, 1, 0x01010001u);
|
||||
live.RegisterLiveEntity(spawn);
|
||||
live.MaterializeLiveEntity(
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ public sealed class LiveEntityInboundAuthorityGateTests
|
|||
accepted.VelocityAuthorityVersion));
|
||||
}
|
||||
|
||||
private static LiveEntityRuntime Runtime() => new(
|
||||
private static LiveEntityRuntime Runtime() => LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public sealed class LiveEntityOrdinaryPhysicsUpdaterTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0xAAB4FFFFu));
|
||||
var live = new LiveEntityRuntime(
|
||||
var live = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
|
|
@ -90,7 +90,7 @@ public sealed class LiveEntityOrdinaryPhysicsUpdaterTests
|
|||
{
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
var live = new LiveEntityRuntime(
|
||||
var live = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
|
|
|
|||
|
|
@ -1457,7 +1457,7 @@ public sealed class ProjectileControllerTests
|
|||
{
|
||||
if (loadInitialLandblock)
|
||||
Spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
Live = new LiveEntityRuntime(Spatial, Resources);
|
||||
Live = LiveEntityRuntimeFixture.Create(Spatial, Resources);
|
||||
Engine = physicsEngine ?? new PhysicsEngine();
|
||||
Origin.Recenter(1, 1);
|
||||
Controller = new ProjectileController(
|
||||
|
|
|
|||
|
|
@ -692,7 +692,7 @@ public sealed class RemotePhysicsUpdaterTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var live = new LiveEntityRuntime(
|
||||
var live = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
BindHiddenRemote(live, firstGuid);
|
||||
|
|
@ -840,7 +840,7 @@ public sealed class RemotePhysicsUpdaterTests
|
|||
0xA9B4FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Live = new LiveEntityRuntime(
|
||||
Live = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }),
|
||||
record =>
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
const uint destinationCell = 0xAAB40001u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
var live = new LiveEntityRuntime(spatial, new Resources());
|
||||
var live = LiveEntityRuntimeFixture.Create(spatial, new Resources());
|
||||
live.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -228,7 +228,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
const uint sourceCell = 0xA9B40039u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
var live = new LiveEntityRuntime(spatial, new Resources());
|
||||
var live = LiveEntityRuntimeFixture.Create(spatial, new Resources());
|
||||
live.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -319,7 +319,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
Vector3 sourcePosition = new(191f, 10f, 50f);
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
var live = new LiveEntityRuntime(spatial, new Resources());
|
||||
var live = LiveEntityRuntimeFixture.Create(spatial, new Resources());
|
||||
live.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1101,7 +1101,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
]));
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
var live = new LiveEntityRuntime(spatial, resources);
|
||||
var live = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
live.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1179,7 +1179,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0xA9B4FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0xAAB4FFFFu));
|
||||
var live = new LiveEntityRuntime(spatial, new Resources());
|
||||
var live = LiveEntityRuntimeFixture.Create(spatial, new Resources());
|
||||
live.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = live.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1383,7 +1383,7 @@ public sealed class RemoteTeleportControllerTests
|
|||
internal RollbackFixture(bool celllessSource = false)
|
||||
{
|
||||
Spatial.AddLandblock(EmptyLandblock(SourceLandblock));
|
||||
Live = new LiveEntityRuntime(Spatial, new Resources());
|
||||
Live = LiveEntityRuntimeFixture.Create(Spatial, new Resources());
|
||||
Live.RegisterLiveEntity(Spawn(Guid, SourceCell));
|
||||
Entity = Live.MaterializeLiveEntity(
|
||||
Guid,
|
||||
|
|
|
|||
|
|
@ -1161,7 +1161,7 @@ public sealed class EquippedChildProjectionWithdrawalTests
|
|||
(Cell & 0xFFFF0000u) | 0xFFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Live = new LiveEntityRuntime(
|
||||
Live = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }),
|
||||
_lifecycle);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public sealed class LiveAppearanceAnimationTests
|
|||
public void Capture_UsesCanonicalRecordEntityAndAnimationOwner()
|
||||
{
|
||||
const uint guid = 0x70000002u;
|
||||
var runtime = new AcDream.App.World.LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
new AcDream.App.Streaming.GpuWorldState(),
|
||||
new AcDream.App.World.DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
var spawn = new AcDream.Core.Net.WorldSession.EntitySpawn(
|
||||
|
|
@ -118,7 +118,7 @@ public sealed class LiveAppearanceAnimationTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
WorldSession.EntitySpawn first = Spawn(guid, cell, instance: 1);
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ public sealed class LiveEntityAnimationPresenterTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var live = new LiveEntityRuntime(
|
||||
var live = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
return Add(live, guid, partCount, scale, withSequencer);
|
||||
|
|
|
|||
|
|
@ -679,7 +679,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var live = new LiveEntityRuntime(
|
||||
var live = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
|
|
@ -800,7 +800,7 @@ public sealed class LiveEntityAnimationSchedulerTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var live = new LiveEntityRuntime(
|
||||
var live = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRecord record = live.RegisterAndMaterializeProjection(
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ public sealed class LiveEntityCreateSupersessionRecoveryTests
|
|||
0x0101FFFFu,
|
||||
new DatReaderWriter.DBObjs.LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
return new LiveEntityRuntime(
|
||||
return LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
resources,
|
||||
new DelegateLiveEntityRuntimeComponentLifecycle(_ => { }));
|
||||
|
|
|
|||
|
|
@ -357,7 +357,7 @@ public sealed class LiveRenderProjectionJournalTests
|
|||
var resources = new DelegateLiveEntityResourceLifecycle(
|
||||
static _ => { },
|
||||
entity => sink?.OnResourceUnregister(entity));
|
||||
var runtime = new LiveEntityRuntime(state, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(state, resources);
|
||||
var journal = new RenderProjectionJournal(
|
||||
RenderSceneGeneration.FromRaw(1));
|
||||
var projections = new LiveRenderProjectionJournal(
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ public sealed class EntityEffectControllerTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Runtime = new LiveEntityRuntime(
|
||||
Runtime = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new NoopResources(),
|
||||
record => _controller?.OnLiveEntityUnregistered(record));
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ public sealed class LiveEntityLightControllerTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Runtime = new LiveEntityRuntime(Spatial, new NoopResources(), _ => { });
|
||||
Runtime = LiveEntityRuntimeFixture.Create(Spatial, new NoopResources(), _ => { });
|
||||
Sink = new LightingHookSink(Lights, Poses);
|
||||
Controller = new LiveEntityLightController(
|
||||
Runtime,
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ public sealed class CurrentGameRuntimeAdapterTests
|
|||
public Harness()
|
||||
{
|
||||
Identity = new LocalPlayerIdentityState();
|
||||
Entities = new LiveEntityRuntime(
|
||||
Entities = LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new NoopEntityResources());
|
||||
Objects = new ClientObjectTable();
|
||||
|
|
|
|||
|
|
@ -579,7 +579,7 @@ public sealed class GpuWorldStateVisibilityTests
|
|||
const uint landblock = 0x0101FFFFu;
|
||||
const uint cell = 0x01010001u;
|
||||
var state = new GpuWorldState();
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
state,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
WorldSession.EntitySpawn first = Spawn(0x70000011u, cell);
|
||||
|
|
@ -624,7 +624,7 @@ public sealed class GpuWorldStateVisibilityTests
|
|||
landblock,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
state,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, cell);
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ public sealed class LocalPlayerTeleportControllerTests
|
|||
0x2021FFFFu,
|
||||
new DatReaderWriter.DBObjs.LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var runtime = new LiveEntityRuntime(world, new NullResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(world, new NullResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, cell));
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -479,7 +479,7 @@ public sealed class LocalPlayerTeleportControllerTests
|
|||
destinationCell & 0xFFFF0000u | 0xFFFFu,
|
||||
new DatReaderWriter.DBObjs.LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var runtime = new LiveEntityRuntime(world, new NullResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(world, new NullResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, sourceCell));
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
|
|||
|
|
@ -506,7 +506,9 @@ public sealed class StreamingFrameControllerTests
|
|||
}
|
||||
|
||||
private static LiveEntityRuntime Runtime(GpuWorldState state) =>
|
||||
new(state, new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
LiveEntityRuntimeFixture.Create(
|
||||
state,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
|
||||
private static LoadedLandblock EmptyLandblock(uint landblock) =>
|
||||
new(landblock, new LandBlock(), Array.Empty<WorldEntity>());
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ public sealed class DeferredLiveEntityRuntimeComponentLifecycleTests
|
|||
{
|
||||
const uint guid = 0x70000002u;
|
||||
var bridge = new DeferredLiveEntityRuntimeComponentLifecycle();
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }),
|
||||
bridge);
|
||||
|
|
@ -136,7 +136,7 @@ public sealed class DeferredLiveEntityRuntimeComponentLifecycleTests
|
|||
|
||||
private static LiveEntityRecord CreateRecord()
|
||||
{
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
return runtime.RegisterAndMaterializeProjection(
|
||||
|
|
|
|||
|
|
@ -1828,7 +1828,8 @@ public sealed class LiveEntityHydrationControllerTests
|
|||
private sealed class Fixture : IDisposable
|
||||
{
|
||||
public readonly List<string> Operations = [];
|
||||
public readonly ClientObjectTable Objects = new();
|
||||
public readonly RuntimeEntityObjectLifetime EntityObjects = new();
|
||||
public ClientObjectTable Objects => EntityObjects.Objects;
|
||||
public readonly RecordingResources Resources;
|
||||
public readonly LiveEntityRuntime Runtime;
|
||||
public readonly RecordingMaterializer Materializer;
|
||||
|
|
@ -1861,7 +1862,8 @@ public sealed class LiveEntityHydrationControllerTests
|
|||
Runtime = new LiveEntityRuntime(
|
||||
spatial,
|
||||
Resources,
|
||||
Teardown);
|
||||
Teardown,
|
||||
EntityObjects);
|
||||
Materializer = new RecordingMaterializer(Runtime, Operations);
|
||||
Relationships = new RecordingRelationships(Operations);
|
||||
Ready = new RecordingReadyPublisher(Operations);
|
||||
|
|
@ -1887,13 +1889,13 @@ public sealed class LiveEntityHydrationControllerTests
|
|||
};
|
||||
var deletion = new LiveEntityDeletionController(
|
||||
Runtime,
|
||||
Objects,
|
||||
EntityObjects,
|
||||
Teardown,
|
||||
identity,
|
||||
Dormant);
|
||||
Controller = new LiveEntityHydrationController(
|
||||
Runtime,
|
||||
Objects,
|
||||
EntityObjects,
|
||||
new object(),
|
||||
Materializer,
|
||||
Relationships,
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ public sealed class LiveEntityLifecycleStressTests
|
|||
randomUnit: () => 0.5,
|
||||
canAdvanceOwner: ownerId => _effects?.CanAdvanceOwner(ownerId) ?? true);
|
||||
|
||||
Runtime = new LiveEntityRuntime(
|
||||
Runtime = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(
|
||||
entity =>
|
||||
|
|
@ -489,7 +489,7 @@ public sealed class LiveEntityLifecycleStressTests
|
|||
EntityEffectController? effects = null;
|
||||
LiveEntityPresentationController? presentation = null;
|
||||
RemoteTeleportController? teleport = null;
|
||||
Runtime = new LiveEntityRuntime(
|
||||
Runtime = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(
|
||||
entity =>
|
||||
|
|
|
|||
|
|
@ -630,10 +630,10 @@ public sealed class LiveEntityPhysicsHostOwnershipTests
|
|||
|
||||
private static LiveEntityRuntime Runtime(Action<LiveEntityRecord>? teardown = null) =>
|
||||
teardown is null
|
||||
? new LiveEntityRuntime(
|
||||
? LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }))
|
||||
: new LiveEntityRuntime(
|
||||
: LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }),
|
||||
teardown);
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ public sealed class LiveEntityPresentationControllerTests
|
|||
const uint pendingCell = 0x02020001u;
|
||||
var spatial = new GpuWorldState();
|
||||
var shadows = new ShadowObjectRegistry();
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
runtime.RegisterLiveEntity(Fixture.Spawn(
|
||||
|
|
@ -487,7 +487,7 @@ public sealed class LiveEntityPresentationControllerTests
|
|||
const uint pendingCell = 0x02020001u;
|
||||
var spatial = new GpuWorldState();
|
||||
var shadows = new ShadowObjectRegistry();
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
runtime.RegisterLiveEntity(Fixture.Spawn(
|
||||
|
|
@ -667,7 +667,7 @@ public sealed class LiveEntityPresentationControllerTests
|
|||
0x0101FFFFu,
|
||||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
Runtime = new LiveEntityRuntime(
|
||||
Runtime = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }));
|
||||
WorldSession.EntitySpawn spawn = Spawn(initialState);
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ public sealed class LiveEntityProjectionWithdrawalControllerTests
|
|||
new LandBlock(),
|
||||
Array.Empty<WorldEntity>()));
|
||||
var lifecycle = new DeferredLiveEntityRuntimeComponentLifecycle();
|
||||
Live = new LiveEntityRuntime(
|
||||
Live = LiveEntityRuntimeFixture.Create(
|
||||
Spatial,
|
||||
new DelegateLiveEntityResourceLifecycle(_ => { }, _ => { }),
|
||||
lifecycle);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
public void RuntimeSlot_BindsExactlyOnceWithoutOwningEntityState()
|
||||
{
|
||||
var spatial = new GpuWorldState();
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
var slot = new LiveEntityRuntimeSlot();
|
||||
|
||||
Assert.Null(slot.Current);
|
||||
|
|
@ -176,7 +176,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0x0102FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000001u, 1, 1, 0x01010001u);
|
||||
|
||||
LiveEntityRegistrationResult registered = runtime.RegisterLiveEntity(spawn);
|
||||
|
|
@ -213,7 +213,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000071u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(
|
||||
guid,
|
||||
instance: 1,
|
||||
|
|
@ -325,7 +325,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000074u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(
|
||||
guid,
|
||||
instance: 1,
|
||||
|
|
@ -417,7 +417,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000070u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -476,7 +476,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000071u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -513,7 +513,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint secondGuid = 0x70000074u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
foreach (uint guid in new[] { firstGuid, secondGuid })
|
||||
{
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
|
|
@ -545,7 +545,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000075u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -580,7 +580,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000072u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity oldEntity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -617,7 +617,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000073u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -672,7 +672,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0x0102FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 6, 1, 0x01010001u);
|
||||
LiveEntityRegistrationResult registration =
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
|
|
@ -702,7 +702,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
const uint parentGuid = 0x70000020u;
|
||||
const uint childGuid = 0x70000021u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(parentGuid, 9, 1, 0x01010001u));
|
||||
runtime.ParentAttachments.Enqueue(new ParentEvent.Parsed(
|
||||
parentGuid, childGuid, 1, 2, 9, 5));
|
||||
|
|
@ -725,7 +725,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
const uint parentGuid = 0x70000022u;
|
||||
const uint childGuid = 0x70000023u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(childGuid, 3, 4, 0x01010001u));
|
||||
runtime.ParentAttachments.AcceptCreateObjectRelation(new ParentAttachmentRelation(
|
||||
parentGuid, childGuid, 1, 2, 9, 4));
|
||||
|
|
@ -743,7 +743,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn first = Spawn(0x70000002u, 4, 10, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(first);
|
||||
WorldEntity original = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -771,7 +771,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
int runtimeTearDowns = 0;
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
resources,
|
||||
_ => runtimeTearDowns++);
|
||||
|
|
@ -803,7 +803,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000004u, 2, 3, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -833,7 +833,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
const uint guid = 0x70000005u;
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 3, 1, 0x01010001u));
|
||||
WorldEntity first = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -863,7 +863,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000006u, 3, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
|
||||
|
|
@ -900,7 +900,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
var spatial = new GpuWorldState();
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000007u, 1, 1, 0x01020001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -929,7 +929,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000025u;
|
||||
var spatial = new GpuWorldState();
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 2, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -983,7 +983,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 4, 10, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1063,7 +1063,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000027u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1104,7 +1104,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0x0102FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
LiveEntityRecord record = RegisterProjection(runtime, spawn);
|
||||
RetailObjectQuantumClock clock = record.ObjectClock;
|
||||
|
|
@ -1143,7 +1143,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000049u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(
|
||||
guid,
|
||||
1,
|
||||
|
|
@ -1166,7 +1166,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint staticGuid = 0x70000051u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
|
||||
LiveEntityRecord ordinary = RegisterProjection(
|
||||
runtime,
|
||||
|
|
@ -1204,7 +1204,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint staticGuid = 0x70000054u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
|
||||
LiveEntityRecord ordinary = RegisterProjection(
|
||||
runtime,
|
||||
|
|
@ -1279,7 +1279,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
const uint parentGuid = 0x50000010u;
|
||||
const uint childGuid = 0x70000055u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(parentGuid, 1, 1, 0x01010001u));
|
||||
LiveEntityRecord child = RegisterProjection(
|
||||
runtime,
|
||||
|
|
@ -1314,7 +1314,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000048u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn firstSpawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
LiveEntityRecord first = RegisterProjection(runtime, firstSpawn);
|
||||
RetailObjectQuantumClock firstClock = first.ObjectClock;
|
||||
|
|
@ -1341,7 +1341,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
const uint stateBeforeBindGuid = 0x70000037u;
|
||||
const uint bindBeforeStateGuid = 0x70000038u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(stateBeforeBindGuid, 1, 1, 0x01010001u));
|
||||
runtime.RegisterLiveEntity(Spawn(bindBeforeStateGuid, 1, 1, 0x01010001u));
|
||||
|
||||
|
|
@ -1381,7 +1381,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
public void ParentDrivenChildNoDrawKeepsBoundBodyInCanonicalState()
|
||||
{
|
||||
const uint guid = 0x70000039u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1401,7 +1401,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
public void InitiallyVisibleCreate_DoesNotManufactureUnHideTransition()
|
||||
{
|
||||
const uint guid = 0x70000040u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
|
||||
LiveEntityRecord record = RegisterProjection(
|
||||
runtime,
|
||||
|
|
@ -1418,7 +1418,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000041u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(
|
||||
guid,
|
||||
1,
|
||||
|
|
@ -1448,7 +1448,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000042u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1486,7 +1486,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
public void PositionAfterPickup_RequiresTeleportHookEvenWithEqualTeleportStamp()
|
||||
{
|
||||
const uint guid = 0x70000043u;
|
||||
var runtime = new LiveEntityRuntime(new GpuWorldState(), new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(new GpuWorldState(), new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
Assert.True(runtime.TryApplyPickup(
|
||||
|
|
@ -1524,7 +1524,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000044u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1563,7 +1563,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000024u, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1593,7 +1593,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000009u, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1620,7 +1620,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
int runtimeTearDowns = 0;
|
||||
var runtime = new LiveEntityRuntime(spatial, resources, _ => runtimeTearDowns++);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources, _ => runtimeTearDowns++);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000008u, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1645,7 +1645,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingRegisterResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x7000000Au, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
|
||||
|
|
@ -1671,7 +1671,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingRegisterAndRollbackOnceResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
|
||||
Assert.Throws<AggregateException>(() => runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1709,7 +1709,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingRegisterAndRollbackOnceResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
Assert.Throws<AggregateException>(() => runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1736,7 +1736,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingRegisterAndRollbackOnceResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
Assert.Throws<AggregateException>(() => runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1764,7 +1764,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingUnregisterResources(0x7000000Bu);
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
foreach (uint guid in new[] { 0x7000000Bu, 0x7000000Cu })
|
||||
{
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
|
|
@ -1792,7 +1792,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingOnceUnregisterResources(guid);
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
|
|
@ -1819,7 +1819,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingOnceUnregisterResources(guid);
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
|
|
@ -1852,7 +1852,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
if (!adapter.OnRemove(entity))
|
||||
throw new InvalidOperationException("presentation owner was not registered");
|
||||
});
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.ProjectionVisibilityChanged += (record, visible) =>
|
||||
{
|
||||
if (record.WorldEntity is { } entity)
|
||||
|
|
@ -1887,7 +1887,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingUnregisterResources(guid);
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn first = Spawn(guid, 1, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(first);
|
||||
runtime.MaterializeLiveEntity(
|
||||
|
|
@ -1918,7 +1918,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0x0102FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010022u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010022u, id => Entity(id, guid));
|
||||
|
||||
|
|
@ -1940,7 +1940,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0x0102FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity attached = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -1965,7 +1965,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(
|
||||
var runtime = LiveEntityRuntimeFixture.Create(
|
||||
spatial,
|
||||
new RecordingResources(),
|
||||
firstLocalEntityId: LiveEntityRuntime.LastLiveEntityId);
|
||||
|
|
@ -1984,7 +1984,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
Assert.NotEqual(0u, secondEntity.Id);
|
||||
Assert.True(runtime.TryGetLocalEntityId(second.Guid, out uint resolved));
|
||||
Assert.Equal(secondEntity.Id, resolved);
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new LiveEntityRuntime(
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => LiveEntityRuntimeFixture.Create(
|
||||
new GpuWorldState(),
|
||||
new RecordingResources(),
|
||||
firstLocalEntityId: uint.MaxValue));
|
||||
|
|
@ -1996,7 +1996,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x7000002Au;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2022,7 +2022,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
public void SessionClear_ForgetsPersistentClassificationWithoutMaterializedRecord()
|
||||
{
|
||||
var spatial = new GpuWorldState();
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
spatial.MarkPersistent(0x7000002Bu);
|
||||
|
||||
runtime.Clear();
|
||||
|
|
@ -2037,7 +2037,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x7000002Du;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2067,7 +2067,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000040u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity entity = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2096,7 +2096,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000041u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2127,7 +2127,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000044u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
bool replaced = false;
|
||||
|
|
@ -2161,7 +2161,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000045u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity original = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2200,7 +2200,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x70000046u;
|
||||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
bool reprojected = false;
|
||||
|
|
@ -2228,7 +2228,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
{
|
||||
const uint guid = 0x70000075u;
|
||||
var spatial = new GpuWorldState();
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity pending = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2277,7 +2277,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new FailingOnceUnregisterResources(guid);
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity? replacementEntity = null;
|
||||
bool replaced = false;
|
||||
|
|
@ -2318,7 +2318,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
spatial.AddLandblock(EmptyLandblock(0x0303FFFFu));
|
||||
var runtime = new LiveEntityRuntime(spatial, new RecordingResources());
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, new RecordingResources());
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity original = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2352,7 +2352,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x7000002Cu;
|
||||
var spatial = new GpuWorldState();
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2394,7 +2394,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
const uint guid = 0x7000002Eu;
|
||||
var spatial = new GpuWorldState();
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2434,7 +2434,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
WorldEntity old = runtime.MaterializeLiveEntity(
|
||||
guid,
|
||||
|
|
@ -2477,7 +2477,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2508,7 +2508,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2538,7 +2538,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2568,7 +2568,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2600,7 +2600,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2632,7 +2632,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(guid, 0x01010001u, id => Entity(id, guid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2660,7 +2660,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
resources.OnRegister = _ =>
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 2, 1, 0x01010001u));
|
||||
|
|
@ -2686,7 +2686,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(guid, 1, 1, 0x01010001u));
|
||||
resources.OnRegister = _ => runtime.Clear();
|
||||
|
||||
|
|
@ -2711,7 +2711,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(firstGuid, 1, 1, 0x01010001u));
|
||||
runtime.RegisterLiveEntity(Spawn(secondGuid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(firstGuid, 0x01010001u, id => Entity(id, firstGuid));
|
||||
|
|
@ -2744,7 +2744,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new CallbackResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
runtime.RegisterLiveEntity(Spawn(oldGuid, 1, 1, 0x01010001u));
|
||||
runtime.MaterializeLiveEntity(oldGuid, 0x01010001u, id => Entity(id, oldGuid));
|
||||
resources.OnUnregister = _ =>
|
||||
|
|
@ -2785,7 +2785,7 @@ public sealed class LiveEntityRuntimeTests
|
|||
var spatial = new GpuWorldState();
|
||||
spatial.AddLandblock(EmptyLandblock(0x0101FFFFu));
|
||||
var resources = new RecordingResources();
|
||||
var runtime = new LiveEntityRuntime(spatial, resources);
|
||||
var runtime = LiveEntityRuntimeFixture.Create(spatial, resources);
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x7000000Du, 4, 1, 0x01010001u);
|
||||
runtime.RegisterLiveEntity(spawn);
|
||||
runtime.MaterializeLiveEntity(
|
||||
|
|
|
|||
|
|
@ -13,8 +13,19 @@ namespace AcDream.App.Tests.World;
|
|||
public sealed class RuntimeEntityOwnershipTests
|
||||
{
|
||||
[Fact]
|
||||
public void LiveEntityRuntime_ComposesCanonicalRuntimeDirectory()
|
||||
public void LiveEntityRuntime_BorrowsCanonicalRuntimeDirectory()
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime();
|
||||
var runtime = new LiveEntityRuntime(
|
||||
new GpuWorldState(),
|
||||
new DelegateLiveEntityResourceLifecycle(
|
||||
static _ => { },
|
||||
static _ => { }),
|
||||
lifetime);
|
||||
FieldInfo owner = typeof(LiveEntityRuntime).GetField(
|
||||
"_entityObjects",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
?? throw new InvalidOperationException("Missing Runtime lifetime root.");
|
||||
FieldInfo directory = typeof(LiveEntityRuntime).GetField(
|
||||
"_directory",
|
||||
BindingFlags.Instance | BindingFlags.NonPublic)
|
||||
|
|
@ -25,9 +36,62 @@ public sealed class RuntimeEntityOwnershipTests
|
|||
?? throw new InvalidOperationException("Missing App projection sidecar store.");
|
||||
|
||||
Assert.Equal(typeof(RuntimeEntityDirectory), directory.FieldType);
|
||||
Assert.Same(lifetime, owner.GetValue(runtime));
|
||||
Assert.Same(lifetime.Entities, directory.GetValue(runtime));
|
||||
Assert.Equal(typeof(LiveEntityProjectionStore), sidecars.FieldType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProductionComposition_HasOneRuntimeEntityObjectConstructionRoot()
|
||||
{
|
||||
string root = FindRepositoryRoot();
|
||||
string appRoot = Path.Combine(root, "src", "AcDream.App");
|
||||
string runtimeRoot = Path.Combine(root, "src", "AcDream.Runtime");
|
||||
string[] appSources = Directory.GetFiles(
|
||||
appRoot,
|
||||
"*.cs",
|
||||
SearchOption.AllDirectories);
|
||||
string[] runtimeSources = Directory.GetFiles(
|
||||
runtimeRoot,
|
||||
"*.cs",
|
||||
SearchOption.AllDirectories);
|
||||
|
||||
string[] appObjectAllocators = appSources
|
||||
.Where(path => !path.Contains(
|
||||
$"{Path.DirectorySeparatorChar}Studio{Path.DirectorySeparatorChar}",
|
||||
StringComparison.OrdinalIgnoreCase))
|
||||
.Where(path => File.ReadAllText(path).Contains(
|
||||
"new ClientObjectTable",
|
||||
StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
string[] appDirectoryAllocators = appSources
|
||||
.Where(path => File.ReadAllText(path).Contains(
|
||||
"new RuntimeEntityDirectory",
|
||||
StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
string[] runtimeObjectAllocators = runtimeSources
|
||||
.Where(path => File.ReadAllText(path).Contains(
|
||||
"new ClientObjectTable",
|
||||
StringComparison.Ordinal))
|
||||
.Select(path => Path.GetFileName(path)!)
|
||||
.ToArray();
|
||||
string[] runtimeDirectoryAllocators = runtimeSources
|
||||
.Where(path => File.ReadAllText(path).Contains(
|
||||
"new RuntimeEntityDirectory",
|
||||
StringComparison.Ordinal))
|
||||
.Select(path => Path.GetFileName(path)!)
|
||||
.ToArray();
|
||||
|
||||
Assert.Empty(appObjectAllocators);
|
||||
Assert.Empty(appDirectoryAllocators);
|
||||
Assert.Equal(
|
||||
["RuntimeEntityObjectLifetime.cs"],
|
||||
runtimeObjectAllocators);
|
||||
Assert.Equal(
|
||||
["RuntimeEntityObjectLifetime.cs"],
|
||||
runtimeDirectoryAllocators);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppProjectionOwners_UseExactRuntimeKeysAndNoGuidDictionary()
|
||||
{
|
||||
|
|
@ -212,4 +276,18 @@ public sealed class RuntimeEntityOwnershipTests
|
|||
field.FieldType.IsGenericType
|
||||
&& field.FieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>)
|
||||
&& field.FieldType.GetGenericArguments()[0] == keyType;
|
||||
|
||||
private static string FindRepositoryRoot()
|
||||
{
|
||||
DirectoryInfo? directory = new(AppContext.BaseDirectory);
|
||||
while (directory is not null)
|
||||
{
|
||||
if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
||||
return directory.FullName;
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException(
|
||||
$"Could not find AcDream.slnx above {AppContext.BaseDirectory}.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
using AcDream.Core.Net;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Core.Physics;
|
||||
using AcDream.Runtime.Entities;
|
||||
|
||||
namespace AcDream.Runtime.Tests.Entities;
|
||||
|
||||
public sealed class RuntimeEntityObjectLifetimeTests
|
||||
{
|
||||
[Fact]
|
||||
public void Owner_ConstructsOneExactDirectoryAndObjectTablePerInstance()
|
||||
{
|
||||
var first = new RuntimeEntityObjectLifetime();
|
||||
var second = new RuntimeEntityObjectLifetime();
|
||||
|
||||
Assert.NotSame(first.Entities, second.Entities);
|
||||
Assert.NotSame(first.Objects, second.Objects);
|
||||
Assert.Same(first.Entities, first.Entities);
|
||||
Assert.Same(first.Objects, first.Objects);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Owner_ConstructionLoadsNoPresentationOrBackendAssembly()
|
||||
{
|
||||
_ = new RuntimeEntityObjectLifetime();
|
||||
|
||||
string[] loaded = AppDomain.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.Select(assembly => assembly.GetName().Name ?? string.Empty)
|
||||
.ToArray();
|
||||
Assert.DoesNotContain(loaded, name =>
|
||||
name.StartsWith("AcDream.App", StringComparison.Ordinal)
|
||||
|| name.StartsWith("AcDream.UI.", StringComparison.Ordinal)
|
||||
|| name.StartsWith("Silk.NET", StringComparison.Ordinal)
|
||||
|| name.StartsWith("OpenAL", StringComparison.Ordinal)
|
||||
|| name.StartsWith("ImGui", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SeparateOwners_IsolateConflictingGuidsAndContents()
|
||||
{
|
||||
const uint guid = 0x70000001u;
|
||||
var first = new RuntimeEntityObjectLifetime();
|
||||
var second = new RuntimeEntityObjectLifetime();
|
||||
RuntimeEntityRecord firstRecord = Accept(first, Spawn(guid, 1, "first"));
|
||||
RuntimeEntityRecord secondRecord = Accept(second, Spawn(guid, 9, "second"));
|
||||
|
||||
Assert.True(first.ApplyAcceptedSpawn(
|
||||
firstRecord,
|
||||
firstRecord.CreateIntegrationVersion,
|
||||
firstRecord.Snapshot,
|
||||
replaceGeneration: false));
|
||||
Assert.True(second.ApplyAcceptedSpawn(
|
||||
secondRecord,
|
||||
secondRecord.CreateIntegrationVersion,
|
||||
secondRecord.Snapshot,
|
||||
replaceGeneration: false));
|
||||
|
||||
Assert.Equal("first", first.Objects.Get(guid)!.Name);
|
||||
Assert.Equal("second", second.Objects.Get(guid)!.Name);
|
||||
Assert.Equal((ushort)1, firstRecord.Incarnation);
|
||||
Assert.Equal((ushort)9, secondRecord.Incarnation);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AcceptedSpawn_RejectsWrongOrSupersededCanonicalIncarnation()
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime();
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000002u, 3, "current");
|
||||
RuntimeEntityRecord canonical = Accept(lifetime, spawn);
|
||||
var wrong = new RuntimeEntityObjectLifetime();
|
||||
RuntimeEntityRecord wrongCanonical = Accept(wrong, spawn);
|
||||
|
||||
Assert.False(lifetime.ApplyAcceptedSpawn(
|
||||
wrongCanonical,
|
||||
wrongCanonical.CreateIntegrationVersion,
|
||||
spawn,
|
||||
replaceGeneration: false));
|
||||
|
||||
ulong expectedVersion = canonical.CreateIntegrationVersion;
|
||||
lifetime.Entities.AdvanceCreateAuthority(canonical);
|
||||
Assert.False(lifetime.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
expectedVersion,
|
||||
spawn,
|
||||
replaceGeneration: false));
|
||||
Assert.Null(lifetime.Objects.Get(spawn.Guid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AcceptedSpawn_RevalidatesAfterSynchronousObjectCallbacks()
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime();
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000003u, 4, "reentrant");
|
||||
RuntimeEntityRecord canonical = Accept(lifetime, spawn);
|
||||
ulong expectedVersion = canonical.CreateIntegrationVersion;
|
||||
lifetime.Objects.ObjectAdded += _ =>
|
||||
lifetime.Entities.AdvanceCreateAuthority(canonical);
|
||||
|
||||
Assert.False(lifetime.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
expectedVersion,
|
||||
spawn,
|
||||
replaceGeneration: false));
|
||||
Assert.NotNull(lifetime.Objects.Get(spawn.Guid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AcceptedDelete_RemovesOnlyMatchingLogicalGeneration()
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime();
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000004u, 6, "retained");
|
||||
RuntimeEntityRecord canonical = Accept(lifetime, spawn);
|
||||
Assert.True(lifetime.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
canonical.CreateIntegrationVersion,
|
||||
spawn,
|
||||
replaceGeneration: true));
|
||||
|
||||
Assert.False(lifetime.TryAcceptDelete(
|
||||
new DeleteObject.Parsed(spawn.Guid, 7),
|
||||
isLocalPlayer: false,
|
||||
out _));
|
||||
Assert.NotNull(lifetime.Objects.Get(spawn.Guid));
|
||||
|
||||
Assert.True(lifetime.TryAcceptDelete(
|
||||
new DeleteObject.Parsed(spawn.Guid, 6),
|
||||
isLocalPlayer: false,
|
||||
out RuntimeEntityDeleteAcceptance accepted));
|
||||
lifetime.CompleteAcceptedDelete(accepted);
|
||||
Assert.Null(lifetime.Objects.Get(spawn.Guid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DeleteAcceptance_CannotCrossOwnersOrReplay()
|
||||
{
|
||||
var owner = new RuntimeEntityObjectLifetime();
|
||||
var other = new RuntimeEntityObjectLifetime();
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000006u, 8, "token");
|
||||
RuntimeEntityRecord canonical = Accept(owner, spawn);
|
||||
Assert.True(owner.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
canonical.CreateIntegrationVersion,
|
||||
spawn,
|
||||
replaceGeneration: true));
|
||||
Assert.True(owner.TryAcceptDelete(
|
||||
new DeleteObject.Parsed(spawn.Guid, spawn.InstanceSequence),
|
||||
isLocalPlayer: false,
|
||||
out RuntimeEntityDeleteAcceptance acceptance));
|
||||
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => other.CompleteAcceptedDelete(acceptance));
|
||||
owner.CompleteAcceptedDelete(acceptance);
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
() => owner.CompleteAcceptedDelete(acceptance));
|
||||
Assert.Null(owner.Objects.Get(spawn.Guid));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClearObjects_DoesNotResetCanonicalEntityIdentity()
|
||||
{
|
||||
var lifetime = new RuntimeEntityObjectLifetime();
|
||||
WorldSession.EntitySpawn spawn = Spawn(0x70000005u, 2, "clear");
|
||||
RuntimeEntityRecord canonical = Accept(lifetime, spawn);
|
||||
Assert.True(lifetime.ApplyAcceptedSpawn(
|
||||
canonical,
|
||||
canonical.CreateIntegrationVersion,
|
||||
spawn,
|
||||
replaceGeneration: false));
|
||||
|
||||
lifetime.ClearObjects();
|
||||
|
||||
Assert.Null(lifetime.Objects.Get(spawn.Guid));
|
||||
Assert.True(lifetime.Entities.TryGetActive(spawn.Guid, out var retained));
|
||||
Assert.Same(canonical, retained);
|
||||
}
|
||||
|
||||
private static RuntimeEntityRecord Accept(
|
||||
RuntimeEntityObjectLifetime lifetime,
|
||||
WorldSession.EntitySpawn spawn)
|
||||
{
|
||||
InboundCreateResult accepted = lifetime.Entities.AcceptCreate(spawn);
|
||||
return lifetime.Entities.AddActive(accepted.Snapshot);
|
||||
}
|
||||
|
||||
private static WorldSession.EntitySpawn Spawn(
|
||||
uint guid,
|
||||
ushort instance,
|
||||
string name)
|
||||
{
|
||||
var position = new CreateObject.ServerPosition(
|
||||
0x0101FFFFu,
|
||||
10f,
|
||||
20f,
|
||||
5f,
|
||||
1f,
|
||||
0f,
|
||||
0f,
|
||||
0f);
|
||||
var timestamps = new PhysicsTimestamps(
|
||||
Position: 1,
|
||||
Movement: 1,
|
||||
State: 1,
|
||||
Vector: 1,
|
||||
Teleport: 0,
|
||||
ServerControlledMove: 1,
|
||||
ForcePosition: 0,
|
||||
ObjDesc: 1,
|
||||
Instance: instance);
|
||||
var physics = new PhysicsSpawnData(
|
||||
RawState: 0x408u,
|
||||
Position: position,
|
||||
Movement: null,
|
||||
AnimationFrame: null,
|
||||
SetupTableId: 0x02000001u,
|
||||
MotionTableId: 0x09000001u,
|
||||
SoundTableId: null,
|
||||
PhysicsScriptTableId: null,
|
||||
Parent: null,
|
||||
Children: null,
|
||||
Scale: null,
|
||||
Friction: null,
|
||||
Elasticity: null,
|
||||
Translucency: null,
|
||||
Velocity: null,
|
||||
Acceleration: null,
|
||||
AngularVelocity: null,
|
||||
DefaultScriptType: null,
|
||||
DefaultScriptIntensity: null,
|
||||
Timestamps: timestamps);
|
||||
return new WorldSession.EntitySpawn(
|
||||
guid,
|
||||
position,
|
||||
0x02000001u,
|
||||
Array.Empty<CreateObject.AnimPartChange>(),
|
||||
Array.Empty<CreateObject.TextureChange>(),
|
||||
Array.Empty<CreateObject.SubPaletteSwap>(),
|
||||
null,
|
||||
null,
|
||||
name,
|
||||
null,
|
||||
null,
|
||||
0x09000001u,
|
||||
PhysicsState: 0x408u,
|
||||
InstanceSequence: instance,
|
||||
MovementSequence: 1,
|
||||
ServerControlSequence: 1,
|
||||
PositionSequence: 1,
|
||||
Physics: physics);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue