fix(ui): port retail item drag visuals
Keep retail's underlay-free m_pDragIcon separate from the full cell icon and reveal the authored ghost mesh on physical source cells for the complete drag lifecycle. This removes the backpack backing from the cursor and retires AP-47. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
3e84027885
commit
ace5880fed
14 changed files with 307 additions and 44 deletions
|
|
@ -41,6 +41,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
private readonly ClientObjectTable _objects;
|
||||
private readonly Func<uint> _playerGuid;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint>? _dragIconIds;
|
||||
private readonly Func<int?> _strength;
|
||||
private readonly Func<string>? _ownerName;
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
ClientObjectTable objects,
|
||||
Func<uint> playerGuid,
|
||||
Func<ItemType, uint, uint, uint, uint, uint> iconIds,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds,
|
||||
Func<int?> strength,
|
||||
SelectionState selection,
|
||||
Func<string>? ownerName,
|
||||
|
|
@ -94,6 +96,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
_objects = objects;
|
||||
_playerGuid = playerGuid;
|
||||
_iconIds = iconIds;
|
||||
_dragIconIds = dragIconIds;
|
||||
_strength = strength;
|
||||
_ownerName = ownerName;
|
||||
_sendUse = sendUse;
|
||||
|
|
@ -214,8 +217,9 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
Action<uint, uint>? notifyMergeAttempt = null,
|
||||
ItemInteractionController? itemInteraction = null,
|
||||
Action? onClose = null,
|
||||
StackSplitQuantityState? stackSplitQuantity = null)
|
||||
=> new InventoryController(layout, objects, playerGuid, iconIds, strength, selection,
|
||||
StackSplitQuantityState? stackSplitQuantity = null,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds = null)
|
||||
=> new InventoryController(layout, objects, playerGuid, iconIds, dragIconIds, strength, selection,
|
||||
ownerName, datFont,
|
||||
contentsEmptySprite, sideBagEmptySprite, mainPackEmptySprite,
|
||||
sendUse, sendNoLongerViewing, sendPutItemInContainer,
|
||||
|
|
@ -315,7 +319,11 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
const uint PlayerPackBaseIcon = 0x0600127Eu; // constant main-pack backpack (visual gate)
|
||||
_topContainer.Flush();
|
||||
var main = new UiItemSlot { SpriteResolve = _topContainer.SpriteResolve };
|
||||
main.SetItem(p, _iconIds(ItemType.Container, PlayerPackBaseIcon, 0u, 0u, 0u));
|
||||
main.SetItem(
|
||||
p,
|
||||
_iconIds(ItemType.Container, PlayerPackBaseIcon, 0u, 0u, 0u),
|
||||
dragIconTexture: _dragIconIds?.Invoke(
|
||||
ItemType.Container, PlayerPackBaseIcon, 0u, 0u, 0u) ?? 0u);
|
||||
main.DragAcceptSprite = 0x060011F7u; main.DragRejectSprite = 0x060011F8u;
|
||||
main.Clicked = () =>
|
||||
{
|
||||
|
|
@ -351,8 +359,11 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
var item = _objects.Get(guid);
|
||||
uint tex = item is null ? 0u
|
||||
: _iconIds(item.Type, item.IconId, item.IconUnderlayId, item.IconOverlayId, item.Effects);
|
||||
uint dragTex = item is null ? 0u
|
||||
: _dragIconIds?.Invoke(
|
||||
item.Type, item.IconId, item.IconUnderlayId, item.IconOverlayId, item.Effects) ?? 0u;
|
||||
var cell = new UiItemSlot { SpriteResolve = list.SpriteResolve };
|
||||
cell.SetItem(guid, tex);
|
||||
cell.SetItem(guid, tex, dragIconTexture: dragTex);
|
||||
cell.SlotIndex = list.GetNumUIItems(); // index it will occupy (== its slot in a packed list)
|
||||
cell.DragAcceptSprite = 0x060011F7u; // green insert arrow (export-confirmed)
|
||||
cell.DragRejectSprite = 0x060011F8u; // red circle
|
||||
|
|
@ -400,7 +411,7 @@ public sealed class InventoryController : IItemListDragHandler, IRetainedPanelCo
|
|||
|
||||
// ── IItemListDragHandler (B-Drag) — drop an item to move it (optimistic + wire) ──────────────
|
||||
/// <summary>Inventory items do NOT lift-remove (unlike the toolbar): the item stays in its slot
|
||||
/// until the server confirms the move. Retail dims the source; we leave it + the floating ghost.</summary>
|
||||
/// while <see cref="UiItemSlot"/> reveals retail's waiting/ghosted mesh until release.</summary>
|
||||
public void OnDragLift(UiItemList sourceList, UiItemSlot sourceCell, ItemDragPayload payload) { }
|
||||
|
||||
/// <summary>Advisory neutral/accept/reject overlay. Shortcut aliases stay neutral; physical grid
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
private readonly ClientObjectTable _objects;
|
||||
private readonly Func<uint> _playerGuid;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint>? _dragIconIds;
|
||||
private readonly Action<uint, uint>? _sendWield; // (itemGuid, equipMask) → GetAndWieldItem 0x001A
|
||||
private readonly ItemInteractionController? _itemInteraction;
|
||||
private readonly SelectionState _selection;
|
||||
|
|
@ -96,9 +97,11 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
Func<ItemType, uint, uint, uint, uint, uint> iconIds, SelectionState selection,
|
||||
Action<uint, uint>? sendWield,
|
||||
uint emptySlotSprite, UiDatFont? datFont, ItemInteractionController? itemInteraction,
|
||||
PaperdollClickMap? clickMap)
|
||||
PaperdollClickMap? clickMap,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds)
|
||||
{
|
||||
_objects = objects; _playerGuid = playerGuid; _iconIds = iconIds; _sendWield = sendWield;
|
||||
_dragIconIds = dragIconIds;
|
||||
_itemInteraction = itemInteraction;
|
||||
_selection = selection ?? throw new ArgumentNullException(nameof(selection));
|
||||
_clickMap = clickMap;
|
||||
|
|
@ -195,10 +198,11 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
Action<uint, uint>? sendWield = null,
|
||||
uint emptySlotSprite = 0u, UiDatFont? datFont = null,
|
||||
ItemInteractionController? itemInteraction = null,
|
||||
PaperdollClickMap? clickMap = null)
|
||||
PaperdollClickMap? clickMap = null,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds = null)
|
||||
=> new PaperdollController(
|
||||
layout, objects, playerGuid, iconIds, selection, sendWield, emptySlotSprite,
|
||||
datFont, itemInteraction, clickMap);
|
||||
datFont, itemInteraction, clickMap, dragIconIds);
|
||||
|
||||
private void HandleDollClick(int x, int y)
|
||||
{
|
||||
|
|
@ -256,7 +260,9 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
|
||||
if (worn is null) { list.Cell.Clear(); continue; }
|
||||
uint tex = _iconIds(worn.Type, worn.IconId, worn.IconUnderlayId, worn.IconOverlayId, worn.Effects);
|
||||
list.Cell.SetItem(worn.ObjectId, tex);
|
||||
uint dragTex = _dragIconIds?.Invoke(
|
||||
worn.Type, worn.IconId, worn.IconUnderlayId, worn.IconOverlayId, worn.Effects) ?? 0u;
|
||||
list.Cell.SetItem(worn.ObjectId, tex, dragIconTexture: dragTex);
|
||||
}
|
||||
ApplySelectionIndicators();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
private readonly CombatState? _combatState;
|
||||
private readonly Func<IReadOnlyList<ShortcutEntry>> _shortcuts;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds; // (itemType, icon, underlay, overlay, effects) → GL tex
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint>? _dragIconIds;
|
||||
private readonly Action<uint> _useItem; // guid → fire UseObject
|
||||
private readonly ShortcutStore _store = new();
|
||||
private bool _storeLoaded;
|
||||
|
|
@ -107,12 +108,14 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
Func<uint>? selectedObjectId = null,
|
||||
Func<uint>? playerGuid = null,
|
||||
Action<uint, uint, int>? sendPutItemInContainer = null,
|
||||
UiDatFont? ammoFont = null)
|
||||
UiDatFont? ammoFont = null,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds = null)
|
||||
{
|
||||
_repo = repo;
|
||||
_combatState = combatState;
|
||||
_shortcuts = shortcuts;
|
||||
_iconIds = iconIds;
|
||||
_dragIconIds = dragIconIds;
|
||||
_useItem = useItem;
|
||||
_peaceDigits = peaceDigits;
|
||||
_warDigits = warDigits;
|
||||
|
|
@ -322,12 +325,14 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
Func<uint>? selectedObjectId = null,
|
||||
Func<uint>? playerGuid = null,
|
||||
Action<uint, uint, int>? sendPutItemInContainer = null,
|
||||
UiDatFont? ammoFont = null)
|
||||
UiDatFont? ammoFont = null,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds = null)
|
||||
{
|
||||
var c = new ToolbarController(layout, repo, shortcuts, iconIds, useItem, combatState,
|
||||
peaceDigits, warDigits, emptyDigits, itemInteraction,
|
||||
sendAddShortcut, sendRemoveShortcut, toggleCombat, selectItem,
|
||||
selectedObjectId, playerGuid, sendPutItemInContainer, ammoFont);
|
||||
selectedObjectId, playerGuid, sendPutItemInContainer, ammoFont,
|
||||
dragIconIds);
|
||||
c.Populate();
|
||||
return c;
|
||||
}
|
||||
|
|
@ -401,7 +406,9 @@ public sealed class ToolbarController : IItemListDragHandler, IRetainedPanelCont
|
|||
var item = _repo.Get(guid);
|
||||
if (item is null) continue; // deferred: ObjectAdded re-calls Populate
|
||||
uint tex = _iconIds(item.Type, item.IconId, item.IconUnderlayId, item.IconOverlayId, item.Effects);
|
||||
list.Cell.SetItem(guid, tex, entry);
|
||||
uint dragTex = _dragIconIds?.Invoke(
|
||||
item.Type, item.IconId, item.IconUnderlayId, item.IconOverlayId, item.Effects) ?? 0u;
|
||||
list.Cell.SetItem(guid, tex, entry, dragTex);
|
||||
}
|
||||
|
||||
// Re-stamp slot number labels after any item change.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue