feat(items): port retail external-container looting
Add the ClientUISystem ground-object lifecycle, authoritative root and nested ViewContents projections, replacement and close semantics, and the DAT-authored gmExternalContainerUI strip for chests and corpses. Route double-click loot and full or partial drag transfers through the shared retail item policy without optimistic external ownership. Remove the incorrect NoLongerViewingContents behavior from owned side packs and retire AP-106/#196. Release build succeeds and all 5,875 tests pass with five intentional skips. Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
parent
48a118db91
commit
20ce67b625
27 changed files with 1750 additions and 45 deletions
|
|
@ -118,13 +118,24 @@ public sealed record InventoryRuntimeBindings(
|
|||
Func<ItemType, uint, uint, uint, uint, uint> ResolveDragIcon,
|
||||
Func<int?> Strength,
|
||||
Action<uint>? SendUse,
|
||||
Action<uint>? SendNoLongerViewing,
|
||||
Action<uint, uint, int>? SendPutItemInContainer,
|
||||
Action<uint, uint, uint, uint>? SendStackableSplitToContainer,
|
||||
Action<uint, uint, uint>? SendStackableMerge,
|
||||
ItemInteractionController ItemInteraction,
|
||||
SelectionState Selection);
|
||||
|
||||
public sealed record ExternalContainerRuntimeBindings(
|
||||
ExternalContainerState State,
|
||||
ClientObjectTable Objects,
|
||||
Func<ItemType, uint, uint, uint, uint, uint> ResolveIcon,
|
||||
Func<ItemType, uint, uint, uint, uint, uint> ResolveDragIcon,
|
||||
ItemInteractionController ItemInteraction,
|
||||
SelectionState Selection,
|
||||
Action<uint> SendUse,
|
||||
Action<uint, uint, int> SendPutItemInContainer,
|
||||
Action<uint, uint, uint, uint> SendStackableSplitToContainer,
|
||||
Func<uint, bool> IsWithinUseRange);
|
||||
|
||||
public sealed record RetailUiPersistenceBindings(
|
||||
SettingsStore Store,
|
||||
Func<string> CharacterKey,
|
||||
|
|
@ -157,6 +168,7 @@ public sealed record RetailUiRuntimeBindings(
|
|||
ToolbarRuntimeBindings Toolbar,
|
||||
CharacterRuntimeBindings Character,
|
||||
InventoryRuntimeBindings Inventory,
|
||||
ExternalContainerRuntimeBindings ExternalContainer,
|
||||
RetailUiCursorBindings Cursor,
|
||||
ConfirmationRuntimeBindings Confirmations,
|
||||
StackSplitQuantityState StackSplitQuantity,
|
||||
|
|
@ -204,6 +216,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
MountCharacter();
|
||||
MountPlugins();
|
||||
MountInventory();
|
||||
MountExternalContainer();
|
||||
Host.WindowManager.WindowVisibilityChanged += OnWindowVisibilityChanged;
|
||||
BindToolbarPanelButtons();
|
||||
SyncToolbarWindowButtons();
|
||||
|
|
@ -215,7 +228,12 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
persistence.Store,
|
||||
persistence.CharacterKey,
|
||||
persistence.ScreenSize,
|
||||
stateManagedVisibilityWindows: [WindowNames.Combat, WindowNames.JumpPowerbar]);
|
||||
stateManagedVisibilityWindows:
|
||||
[
|
||||
WindowNames.Combat,
|
||||
WindowNames.JumpPowerbar,
|
||||
WindowNames.ExternalContainer,
|
||||
]);
|
||||
}
|
||||
|
||||
if (bindings.Probe.Enabled)
|
||||
|
|
@ -257,6 +275,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
public UiViewport? PaperdollViewportWidget { get; private set; }
|
||||
public UiNineSlicePanel? InventoryFrame { get; private set; }
|
||||
public RetailDialogFactory? DialogFactory { get; private set; }
|
||||
public ExternalContainerController? ExternalContainerController { get; private set; }
|
||||
|
||||
public static RetailUiRuntime Mount(RetailUiRuntimeBindings bindings)
|
||||
{
|
||||
|
|
@ -283,6 +302,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
IndicatorBarController?.Tick();
|
||||
JumpPowerbarController?.Tick();
|
||||
SelectedObjectController?.Tick(deltaSeconds);
|
||||
ExternalContainerController?.Tick();
|
||||
DialogFactory?.Tick();
|
||||
Host.Tick(deltaSeconds);
|
||||
_automation?.Tick(deltaSeconds);
|
||||
|
|
@ -1577,7 +1597,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
InventoryController inventory = InventoryController.Bind(
|
||||
layout, b.Objects, b.PlayerGuid, b.ResolveIcon, b.Strength, b.Selection,
|
||||
_bindings.Assets.DefaultFont, _bindings.Character.Provider.CharacterName,
|
||||
contents, sideBag, mainPack, b.SendUse, b.SendNoLongerViewing,
|
||||
contents, sideBag, mainPack, b.SendUse,
|
||||
b.SendPutItemInContainer, b.SendStackableSplitToContainer, b.SendStackableMerge,
|
||||
notifyMergeAttempt, b.ItemInteraction,
|
||||
() => CloseWindow(WindowNames.Inventory),
|
||||
|
|
@ -1596,6 +1616,83 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
Console.WriteLine("[D.2b-B] retail inventory window from LayoutDesc importer (0x21000023).");
|
||||
}
|
||||
|
||||
private void MountExternalContainer()
|
||||
{
|
||||
ImportedLayout? layout;
|
||||
lock (_bindings.Assets.DatLock)
|
||||
{
|
||||
layout = LayoutImporter.Import(
|
||||
_bindings.Assets.Dats,
|
||||
ExternalContainerController.LayoutId,
|
||||
ExternalContainerController.RootId,
|
||||
_bindings.Assets.ResolveSprite,
|
||||
_bindings.Assets.DefaultFont,
|
||||
_bindings.Assets.ResolveFont);
|
||||
}
|
||||
if (layout is null)
|
||||
{
|
||||
Console.WriteLine("[D.2b] external container: LayoutDesc 0x21000008 not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
UiElement root = layout.Root;
|
||||
RetailWindowHandle handle = RetailWindowFrame.Mount(
|
||||
Host.Root,
|
||||
root,
|
||||
_bindings.Assets.ResolveSprite,
|
||||
new RetailWindowFrame.Options
|
||||
{
|
||||
WindowName = WindowNames.ExternalContainer,
|
||||
Chrome = RetailWindowChrome.Imported,
|
||||
Left = root.Left,
|
||||
Top = root.Top,
|
||||
ContentWidth = root.Width,
|
||||
ContentHeight = root.Height,
|
||||
Visible = false,
|
||||
Draggable = false,
|
||||
Resizable = false,
|
||||
ResizeX = false,
|
||||
ResizeY = false,
|
||||
});
|
||||
|
||||
uint contentsEmpty;
|
||||
uint containerEmpty;
|
||||
lock (_bindings.Assets.DatLock)
|
||||
{
|
||||
contentsEmpty = ItemListCellTemplate.ResolveEmptySprite(
|
||||
_bindings.Assets.Dats,
|
||||
ExternalContainerController.LayoutId,
|
||||
ExternalContainerController.ContentsListId);
|
||||
containerEmpty = ItemListCellTemplate.ResolveEmptySprite(
|
||||
_bindings.Assets.Dats,
|
||||
ExternalContainerController.LayoutId,
|
||||
ExternalContainerController.ContainerListId);
|
||||
}
|
||||
|
||||
ExternalContainerRuntimeBindings b = _bindings.ExternalContainer;
|
||||
ExternalContainerController = ExternalContainerController.Bind(
|
||||
layout,
|
||||
b.State,
|
||||
b.Objects,
|
||||
b.Selection,
|
||||
b.ItemInteraction,
|
||||
StackSplitQuantity,
|
||||
b.ResolveIcon,
|
||||
b.ResolveDragIcon,
|
||||
b.SendUse,
|
||||
b.SendPutItemInContainer,
|
||||
b.SendStackableSplitToContainer,
|
||||
b.IsWithinUseRange,
|
||||
handle,
|
||||
contentsEmpty,
|
||||
containerEmpty);
|
||||
Host.WindowManager.AttachController(
|
||||
WindowNames.ExternalContainer,
|
||||
ExternalContainerController);
|
||||
Console.WriteLine(
|
||||
"[D.2b] retail external-container strip mounted from LayoutDesc 0x21000008.");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue