fix(portal): synchronize destination presentation state
This commit is contained in:
parent
4b1bceefbb
commit
e95f55f25b
42 changed files with 2815 additions and 288 deletions
|
|
@ -29,6 +29,10 @@ public sealed class ShadowObjectRegistry
|
|||
private readonly Dictionary<uint, List<ShadowEntry>> _cells = new();
|
||||
private readonly Dictionary<uint, List<uint>> _entityToCells = new(); // for deregistration
|
||||
private readonly HashSet<uint> _suspendedEntities = new();
|
||||
// Rows withdrawn because a touched landblock streamed out. The owner may
|
||||
// be seeded in an adjacent still-resident landblock, so its remaining rows
|
||||
// cannot by themselves tell RefloodLandblock that this prefix needs repair.
|
||||
private readonly Dictionary<uint, HashSet<uint>> _withdrawnPrefixesByOwner = new();
|
||||
|
||||
/// <summary>
|
||||
/// A6.P4 door fix (2026-05-24): per-entity original shape list, used by
|
||||
|
|
@ -367,7 +371,7 @@ public sealed class ShadowObjectRegistry
|
|||
public void RefloodLandblock(uint landblockId)
|
||||
{
|
||||
uint lbPrefix = landblockId & 0xFFFF0000u;
|
||||
var toReflood = new List<uint>();
|
||||
var toReflood = new HashSet<uint>();
|
||||
|
||||
foreach (var kvp in _entityReg)
|
||||
{
|
||||
|
|
@ -390,11 +394,17 @@ public sealed class ShadowObjectRegistry
|
|||
}
|
||||
}
|
||||
}
|
||||
if (_withdrawnPrefixesByOwner.TryGetValue(kvp.Key, out var prefixes)
|
||||
&& prefixes.Contains(lbPrefix))
|
||||
{
|
||||
toReflood.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (uint entityId in toReflood)
|
||||
{
|
||||
var reg = _entityReg[entityId];
|
||||
_withdrawnPrefixesByOwner.TryGetValue(entityId, out var withdrawnBeforeReflood);
|
||||
if (reg.IsMultiPart && _entityShapes.TryGetValue(entityId, out var shapes))
|
||||
{
|
||||
RegisterMultiPart(entityId, reg.EntityWorldPos, reg.EntityWorldRot, shapes,
|
||||
|
|
@ -408,6 +418,22 @@ public sealed class ShadowObjectRegistry
|
|||
reg.CollisionType, reg.CylHeight, reg.Scale,
|
||||
reg.State, reg.Flags, reg.SeedCellId, reg.IsStatic);
|
||||
}
|
||||
|
||||
// Register is also the authoritative movement/replacement API and
|
||||
// therefore clears obsolete markers. Only this streaming reflood
|
||||
// operation preserves the still-missing prefixes across replacement.
|
||||
if (withdrawnBeforeReflood is not null)
|
||||
_withdrawnPrefixesByOwner[entityId] = withdrawnBeforeReflood;
|
||||
|
||||
if (_entityToCells.TryGetValue(entityId, out var refreshedCells)
|
||||
&& refreshedCells.Exists(cell =>
|
||||
(cell & 0xFFFF0000u) == lbPrefix)
|
||||
&& _withdrawnPrefixesByOwner.TryGetValue(entityId, out var withdrawn))
|
||||
{
|
||||
withdrawn.Remove(lbPrefix);
|
||||
if (withdrawn.Count == 0)
|
||||
_withdrawnPrefixesByOwner.Remove(entityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,6 +501,29 @@ public sealed class ShadowObjectRegistry
|
|||
_entityShapes.Remove(entityId);
|
||||
_entityReg.Remove(entityId);
|
||||
_suspendedEntities.Remove(entityId);
|
||||
_withdrawnPrefixesByOwner.Remove(entityId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logically tear down every static object owned by a landblock, including
|
||||
/// shadow rows flooded into adjacent landblocks. Dynamic/server-live owners
|
||||
/// are deliberately retained for spatial reflood after streaming changes.
|
||||
/// </summary>
|
||||
public void DeregisterStaticOwnersForLandblock(uint landblockId)
|
||||
{
|
||||
uint prefix = landblockId & 0xFFFF0000u;
|
||||
var owners = new List<uint>();
|
||||
foreach (var (entityId, registration) in _entityReg)
|
||||
{
|
||||
if (registration.IsStatic
|
||||
&& (registration.SeedCellId & 0xFFFF0000u) == prefix)
|
||||
{
|
||||
owners.Add(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (uint entityId in owners)
|
||||
Deregister(entityId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -491,6 +540,18 @@ public sealed class ShadowObjectRegistry
|
|||
uint lbPrefix = landblockId & 0xFFFF0000u;
|
||||
var toRemove = new List<uint>();
|
||||
|
||||
foreach (var (entityId, cells) in _entityToCells)
|
||||
{
|
||||
if (!cells.Exists(cell => (cell & 0xFFFF0000u) == lbPrefix))
|
||||
continue;
|
||||
if (!_withdrawnPrefixesByOwner.TryGetValue(entityId, out var withdrawn))
|
||||
{
|
||||
withdrawn = new HashSet<uint>();
|
||||
_withdrawnPrefixesByOwner[entityId] = withdrawn;
|
||||
}
|
||||
withdrawn.Add(lbPrefix);
|
||||
}
|
||||
|
||||
foreach (var kvp in _cells)
|
||||
{
|
||||
if ((kvp.Key & 0xFFFF0000u) == lbPrefix)
|
||||
|
|
@ -520,6 +581,7 @@ public sealed class ShadowObjectRegistry
|
|||
_entityShapes.Remove(eid);
|
||||
_entityReg.Remove(eid);
|
||||
_suspendedEntities.Remove(eid);
|
||||
_withdrawnPrefixesByOwner.Remove(eid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -549,6 +611,18 @@ public sealed class ShadowObjectRegistry
|
|||
/// </summary>
|
||||
public int RetainedRegistrationCount => _entityReg.Count;
|
||||
|
||||
/// <summary>Number of owner/prefix repair markers awaiting a future reflood.</summary>
|
||||
public int WithdrawnPrefixMarkerCount
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
foreach (var prefixes in _withdrawnPrefixesByOwner.Values)
|
||||
count += prefixes.Count;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Suspended logical registrations awaiting spatial re-entry.</summary>
|
||||
public int SuspendedRegistrationCount => _suspendedEntities.Count;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue