refactor(core): D.5.3/B.2 — move ShortcutStore to Core.Items (decouple Load from the wire type)
Matches the ClientObjectTable model-placement convention; Load now takes (slot,objGuid) pairs so the store has no Core.Net dependency. + self-drop wire-count assert + comment fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
250f7827be
commit
ff3592ec25
4 changed files with 32 additions and 28 deletions
|
|
@ -60,7 +60,7 @@ public sealed class ToolbarController : IItemListDragHandler
|
|||
private readonly Func<IReadOnlyList<PlayerDescriptionParser.ShortcutEntry>> _shortcuts;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds; // (itemType, icon, underlay, overlay, effects) → GL tex
|
||||
private readonly Action<uint> _useItem; // guid → fire UseObject
|
||||
private readonly AcDream.Core.Net.Items.ShortcutStore _store = new();
|
||||
private readonly AcDream.Core.Items.ShortcutStore _store = new();
|
||||
private bool _storeLoaded;
|
||||
private readonly Action<uint, uint>? _sendAddShortcut; // (index, objectGuid)
|
||||
private readonly Action<uint>? _sendRemoveShortcut; // (index)
|
||||
|
|
@ -143,7 +143,7 @@ public sealed class ToolbarController : IItemListDragHandler
|
|||
|
||||
/// <summary>
|
||||
/// Returns true if <paramref name="guid"/> is one of the currently-active shortcut guids
|
||||
/// (i.e., present in the live <see cref="AcDream.Core.Net.Items.ShortcutStore"/>).
|
||||
/// (i.e., present in the live <see cref="AcDream.Core.Items.ShortcutStore"/>).
|
||||
/// Used to gate repo-event subscriptions so we don't re-populate on every creature spawn.
|
||||
/// Falls back to scanning <c>_shortcuts()</c> before the store is loaded (pre-PD window).
|
||||
/// </summary>
|
||||
|
|
@ -151,7 +151,7 @@ public sealed class ToolbarController : IItemListDragHandler
|
|||
{
|
||||
if (_storeLoaded)
|
||||
{
|
||||
for (int s = 0; s < AcDream.Core.Net.Items.ShortcutStore.SlotCount; s++)
|
||||
for (int s = 0; s < AcDream.Core.Items.ShortcutStore.SlotCount; s++)
|
||||
if (_store.Get(s) == guid) return true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -217,14 +217,18 @@ public sealed class ToolbarController : IItemListDragHandler
|
|||
/// Entries whose item is not yet in the repo are silently skipped here; the
|
||||
/// <c>ObjectAdded</c> event re-fires this method when the item arrives
|
||||
/// (matching retail's <c>SetDelayedShortcutNum</c> deferred-rebind path).
|
||||
/// As of B.2: the <see cref="AcDream.Core.Net.Items.ShortcutStore"/> is the
|
||||
/// As of B.2: the <see cref="AcDream.Core.Items.ShortcutStore"/> is the
|
||||
/// authoritative in-session slot map; <c>_shortcuts()</c> seeds it on first call.
|
||||
/// </summary>
|
||||
public void Populate()
|
||||
{
|
||||
// Lazy-load the store from the login shortcut list the first time it's present (PD arrives
|
||||
// after Bind); thereafter the store is authoritative and drag ops mutate it directly.
|
||||
if (!_storeLoaded && _shortcuts().Count > 0) { _store.Load(_shortcuts()); _storeLoaded = true; }
|
||||
if (!_storeLoaded && _shortcuts().Count > 0)
|
||||
{
|
||||
_store.Load(System.Linq.Enumerable.Select(_shortcuts(), e => ((int)e.Index, e.ObjectGuid)));
|
||||
_storeLoaded = true;
|
||||
}
|
||||
|
||||
foreach (var list in _slots) list?.Cell.Clear();
|
||||
|
||||
|
|
@ -350,7 +354,7 @@ public sealed class ToolbarController : IItemListDragHandler
|
|||
// evict the target's occupant, place the dragged item there, and bump the evicted item into
|
||||
// the (now-vacated) source slot if it's free.
|
||||
int target = targetCell.SlotIndex;
|
||||
uint evicted = _store.Get(target); // RemoveShortcutInSlotNum(target)
|
||||
uint evicted = _store.Get(target); // RemoveShortCutInSlotNum(target)
|
||||
if (evicted != 0) { _store.Remove(target); _sendRemoveShortcut?.Invoke((uint)target); }
|
||||
_store.Set(target, payload.ObjId); // AddShortcut(dragged, target)
|
||||
_sendAddShortcut?.Invoke((uint)target, payload.ObjId);
|
||||
|
|
|
|||
|
|
@ -1,28 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AcDream.Core.Net.Messages;
|
||||
|
||||
namespace AcDream.Core.Net.Items;
|
||||
namespace AcDream.Core.Items;
|
||||
|
||||
/// <summary>
|
||||
/// Mutable client-side model of the 18 toolbar shortcut slots — port of retail
|
||||
/// <c>ShortCutManager::shortCuts_[18]</c> (acclient.h:36492). Holds the bound object guid per
|
||||
/// slot (0 = empty). Loaded from the login PlayerDescription, then mutated by drag-drop
|
||||
/// (lift removes, drop places); the server is notified via AddShortcut/RemoveShortcut so the
|
||||
/// store stays the client's source of truth within a session (retail: client owns the array).
|
||||
/// Item shortcuts only — spell shortcuts (ObjectGuid 0) are skipped on Load.
|
||||
/// slot (0 = empty). Loaded from the login shortcut list, then mutated by drag-drop (lift
|
||||
/// removes, drop places); the server is notified via AddShortcut/RemoveShortcut so the store
|
||||
/// stays the client's source of truth within a session (retail: client owns the array).
|
||||
/// Item shortcuts only — entries with ObjGuid 0 (spell-only) are skipped on Load. Pure model
|
||||
/// (no Core.Net dependency): callers project their wire entries to (slot, objGuid) pairs.
|
||||
/// </summary>
|
||||
public sealed class ShortcutStore
|
||||
{
|
||||
public const int SlotCount = 18;
|
||||
private readonly uint[] _objIds = new uint[SlotCount];
|
||||
|
||||
/// <summary>Replace all slots from the login PlayerDescription shortcut list (item entries only).</summary>
|
||||
public void Load(IReadOnlyList<PlayerDescriptionParser.ShortcutEntry> entries)
|
||||
/// <summary>Replace all slots from a (slot, objectGuid) sequence (item entries only;
|
||||
/// ObjGuid 0 and out-of-range slots are skipped).</summary>
|
||||
public void Load(IEnumerable<(int Slot, uint ObjGuid)> entries)
|
||||
{
|
||||
Array.Clear(_objIds);
|
||||
foreach (var e in entries)
|
||||
if (e.Index < SlotCount && e.ObjectGuid != 0) _objIds[(int)e.Index] = e.ObjectGuid;
|
||||
foreach (var (slot, objGuid) in entries)
|
||||
if ((uint)slot < SlotCount && objGuid != 0) _objIds[slot] = objGuid;
|
||||
}
|
||||
|
||||
/// <summary>Bound object guid at <paramref name="slot"/>, or 0 (empty / out of range).</summary>
|
||||
Loading…
Add table
Add a link
Reference in a new issue