feat(D.5.4): live container membership index (object_inventory_table)
Reindex on Ingest/MoveItem/Remove; GetContents(containerId) ordered by slot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d9c427cd6c
commit
2e3f209707
2 changed files with 83 additions and 3 deletions
|
|
@ -42,6 +42,7 @@ public sealed class ClientObjectTable
|
|||
{
|
||||
private readonly ConcurrentDictionary<uint, ClientObject> _objects = new();
|
||||
private readonly ConcurrentDictionary<uint, Container> _containers = new();
|
||||
private readonly Dictionary<uint, List<uint>> _containerIndex = new();
|
||||
|
||||
/// <summary>Fires when an object is first added to the session.</summary>
|
||||
public event Action<ClientObject>? ObjectAdded;
|
||||
|
|
@ -89,6 +90,7 @@ public sealed class ClientObjectTable
|
|||
/// Register / refresh an object in the table. Called on
|
||||
/// CreateObject for item-typed weenies and on IdentifyObjectResponse
|
||||
/// to fill in detail properties.
|
||||
/// Does NOT update the container index — use Ingest for container-tracked objects.
|
||||
/// </summary>
|
||||
public void AddOrUpdate(ClientObject item)
|
||||
{
|
||||
|
|
@ -123,7 +125,7 @@ public sealed class ClientObjectTable
|
|||
item.ContainerId = newContainerId;
|
||||
item.ContainerSlot = newSlot;
|
||||
item.CurrentlyEquippedLocation = newEquipLocation;
|
||||
|
||||
Reindex(item, oldContainer);
|
||||
ObjectMoved?.Invoke(item, oldContainer, newContainerId);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -135,6 +137,8 @@ public sealed class ClientObjectTable
|
|||
public bool Remove(uint itemId)
|
||||
{
|
||||
if (!_objects.TryRemove(itemId, out var item)) return false;
|
||||
if (item.ContainerId != 0 && _containerIndex.TryGetValue(item.ContainerId, out var l))
|
||||
l.Remove(itemId);
|
||||
ObjectRemoved?.Invoke(item);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -275,8 +279,31 @@ public sealed class ClientObjectTable
|
|||
return obj;
|
||||
}
|
||||
|
||||
// Filled in Task 6 (container index). No-op until then.
|
||||
private void Reindex(ClientObject obj, uint oldContainerId) { }
|
||||
private void Reindex(ClientObject obj, uint oldContainerId)
|
||||
{
|
||||
if (oldContainerId != obj.ContainerId && oldContainerId != 0
|
||||
&& _containerIndex.TryGetValue(oldContainerId, out var oldList))
|
||||
oldList.Remove(obj.ObjectId);
|
||||
|
||||
if (obj.ContainerId != 0)
|
||||
{
|
||||
if (!_containerIndex.TryGetValue(obj.ContainerId, out var list))
|
||||
_containerIndex[obj.ContainerId] = list = new List<uint>();
|
||||
if (!list.Contains(obj.ObjectId)) list.Add(obj.ObjectId);
|
||||
list.Sort((a, b) => SlotOf(a).CompareTo(SlotOf(b)));
|
||||
}
|
||||
}
|
||||
|
||||
private int SlotOf(uint guid) =>
|
||||
_objects.TryGetValue(guid, out var o) ? o.ContainerSlot : int.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// Ordered item guids in a container (retail object_inventory_table), by ContainerSlot.
|
||||
/// Returns a SNAPSHOT (safe to hold / read off-thread); empty for an unknown container.
|
||||
/// </summary>
|
||||
public IReadOnlyList<uint> GetContents(uint containerId) =>
|
||||
_containerIndex.TryGetValue(containerId, out var l)
|
||||
? l.ToArray() : System.Array.Empty<uint>();
|
||||
|
||||
/// <summary>
|
||||
/// Flush the table — typically called on logoff or teleport
|
||||
|
|
@ -286,5 +313,6 @@ public sealed class ClientObjectTable
|
|||
{
|
||||
_objects.Clear();
|
||||
_containers.Clear();
|
||||
_containerIndex.Clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue