refactor(world): canonicalize live physics host ownership
This commit is contained in:
parent
5882b308c1
commit
fcb66198fc
21 changed files with 1546 additions and 323 deletions
|
|
@ -49,6 +49,7 @@ public sealed class TargetManager
|
|||
private readonly IPhysicsObjHost _host;
|
||||
|
||||
private TargetInfo? _targetInfo; // retail target_info (watcher role)
|
||||
private IPhysicsObjHost? _targetHost; // exact App incarnation token
|
||||
private Dictionary<uint, TargettedVoyeurInfo>? _voyeurTable; // retail voyeur_table (watched role)
|
||||
private double _lastUpdateTime; // retail last_update_time (throttle base)
|
||||
|
||||
|
|
@ -67,6 +68,12 @@ public sealed class TargetManager
|
|||
/// quantum, 0 when tracking nothing.</summary>
|
||||
public double GetTargetQuantum() => _targetInfo?.Quantum ?? 0.0;
|
||||
|
||||
/// <summary>The pointer-like target identity captured by SetTarget.</summary>
|
||||
public IPhysicsObjHost? GetRelationshipTarget(uint objectId) =>
|
||||
_targetInfo is { } info && info.ObjectId == objectId
|
||||
? _targetHost
|
||||
: null;
|
||||
|
||||
// ── watcher role ───────────────────────────────────────────────────────
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -101,7 +108,8 @@ public sealed class TargetManager
|
|||
LastUpdateTime: _host.CurTime);
|
||||
|
||||
var target = _host.GetObjectA(objectId);
|
||||
target?.AddVoyeur(_host.Id, radius, quantum);
|
||||
_targetHost = target;
|
||||
target?.AddVoyeur(_host, radius, quantum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -115,8 +123,9 @@ public sealed class TargetManager
|
|||
return;
|
||||
|
||||
_targetInfo = ti with { Quantum = quantum };
|
||||
var target = _host.GetObjectA(ti.ObjectId);
|
||||
target?.AddVoyeur(_host.Id, ti.Radius, quantum);
|
||||
var target = _targetHost ?? _host.GetObjectA(ti.ObjectId);
|
||||
_targetHost = target;
|
||||
target?.AddVoyeur(_host, ti.Radius, quantum);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -128,9 +137,10 @@ public sealed class TargetManager
|
|||
if (_targetInfo is not { } ti)
|
||||
return;
|
||||
|
||||
var target = _host.GetObjectA(ti.ObjectId);
|
||||
target?.RemoveVoyeur(_host.Id);
|
||||
var target = _targetHost ?? _host.GetObjectA(ti.ObjectId);
|
||||
target?.RemoveVoyeur(_host.Id, _host);
|
||||
_targetInfo = null;
|
||||
_targetHost = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -141,10 +151,17 @@ public sealed class TargetManager
|
|||
/// time, recomputes the self→target interpolated heading (falls back to +Z
|
||||
/// when degenerate), fans the snapshot to the host, and drops the
|
||||
/// subscription on an ExitWorld status.
|
||||
/// Receives the update only from the exact target incarnation that
|
||||
/// established this relationship. The sender token stays outside the
|
||||
/// retail TargetInfo payload.
|
||||
/// </summary>
|
||||
public void ReceiveUpdate(TargetInfo update)
|
||||
public void ReceiveUpdate(TargetInfo update, IPhysicsObjHost sender)
|
||||
{
|
||||
if (_targetInfo is not { } ti || ti.ObjectId != update.ObjectId)
|
||||
ArgumentNullException.ThrowIfNull(sender);
|
||||
if (_targetInfo is not { } ti
|
||||
|| ti.ObjectId != update.ObjectId
|
||||
|| _targetHost is null
|
||||
|| !ReferenceEquals(_targetHost, sender))
|
||||
return;
|
||||
|
||||
// Copy radius/quantum/positions/velocity/status from the wire; keep our
|
||||
|
|
@ -181,25 +198,53 @@ public sealed class TargetManager
|
|||
/// radius/quantum in place (no immediate send); otherwise creates the entry
|
||||
/// and pushes an immediate initial snapshot (<c>Ok</c>).
|
||||
/// </summary>
|
||||
public void AddVoyeur(uint watcherId, float radius, double quantum)
|
||||
public void AddVoyeur(IPhysicsObjHost watcher, float radius, double quantum)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(watcher);
|
||||
uint watcherId = watcher.Id;
|
||||
_voyeurTable ??= new Dictionary<uint, TargettedVoyeurInfo>();
|
||||
|
||||
if (_voyeurTable.TryGetValue(watcherId, out var existing))
|
||||
{
|
||||
existing.Radius = radius;
|
||||
existing.Quantum = quantum;
|
||||
return;
|
||||
if (ReferenceEquals(existing.WatcherHost, watcher))
|
||||
{
|
||||
existing.Radius = radius;
|
||||
existing.Quantum = quantum;
|
||||
return;
|
||||
}
|
||||
|
||||
// A later INSTANCE_TS reused the GUID. Replace the pointer-like
|
||||
// subscription; the retiring watcher can no longer remove it via
|
||||
// its exact identity token.
|
||||
_voyeurTable.Remove(watcherId);
|
||||
}
|
||||
|
||||
var voyeur = new TargettedVoyeurInfo(watcherId, radius, quantum);
|
||||
var voyeur = new TargettedVoyeurInfo(
|
||||
watcherId,
|
||||
radius,
|
||||
quantum,
|
||||
watcher);
|
||||
_voyeurTable[watcherId] = voyeur;
|
||||
SendVoyeurUpdate(voyeur, _host.Position, TargetStatus.Ok);
|
||||
}
|
||||
|
||||
/// <summary>Retail <c>TargetManager::RemoveVoyeur</c> (0x0051ad90).</summary>
|
||||
public bool RemoveVoyeur(uint watcherId)
|
||||
=> _voyeurTable?.Remove(watcherId) ?? false;
|
||||
/// <summary>
|
||||
/// Retail <c>TargetManager::RemoveVoyeur</c> (0x0051ad90). Removes a
|
||||
/// relationship only when it still belongs to the exact watcher
|
||||
/// incarnation that established it in the App lifetime model.
|
||||
/// </summary>
|
||||
public bool RemoveVoyeur(uint watcherId, IPhysicsObjHost expectedWatcher)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(expectedWatcher);
|
||||
if (_voyeurTable is null
|
||||
|| !_voyeurTable.TryGetValue(watcherId, out var existing)
|
||||
|| !ReferenceEquals(existing.WatcherHost, expectedWatcher))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return _voyeurTable.Remove(watcherId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>TargetManager::HandleTargetting</c> (0x0051aa90). THE per-tick
|
||||
|
|
@ -280,8 +325,7 @@ public sealed class TargetManager
|
|||
Quantum: voyeur.Quantum,
|
||||
Velocity: _host.Velocity);
|
||||
|
||||
var voyeurObj = _host.GetObjectA(voyeur.ObjectId);
|
||||
voyeurObj?.ReceiveTargetUpdate(info);
|
||||
voyeur.WatcherHost.ReceiveTargetUpdate(info, _host);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue