feat(ui): port retail dialog factory lifecycle
Replace the single mutable confirmation service with retail's property-backed DialogFactory model: fresh DAT roots, context ids, queue groups, priority preemption, callback/close-notice ordering, and context cancellation. Route /die, server confirmation aborts, and guarded item use through focused semantic owners. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
43f7c7807c
commit
66bdae7a83
22 changed files with 1442 additions and 220 deletions
|
|
@ -107,6 +107,9 @@ public sealed record RetailUiCursorBindings(
|
|||
CursorFeedbackController Feedback,
|
||||
RetailCursorManager Manager);
|
||||
|
||||
public sealed record ConfirmationRuntimeBindings(
|
||||
Action<uint, uint, bool> SendResponse);
|
||||
|
||||
public sealed record RetailUiRuntimeBindings(
|
||||
UiHost Host,
|
||||
RetailUiAssets Assets,
|
||||
|
|
@ -120,6 +123,7 @@ public sealed record RetailUiRuntimeBindings(
|
|||
CharacterRuntimeBindings Character,
|
||||
InventoryRuntimeBindings Inventory,
|
||||
RetailUiCursorBindings Cursor,
|
||||
ConfirmationRuntimeBindings Confirmations,
|
||||
StackSplitQuantityState StackSplitQuantity,
|
||||
BufferedUiRegistry? Plugins,
|
||||
RetailUiPersistenceBindings? Persistence,
|
||||
|
|
@ -136,6 +140,8 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
private StackSplitQuantityState StackSplitQuantity => _bindings.StackSplitQuantity;
|
||||
private readonly RetailWindowLayoutPersistence? _persistence;
|
||||
private readonly RetailUiAutomationScriptRunner? _automation;
|
||||
private GameplayConfirmationController? _gameplayConfirmationController;
|
||||
private RetailItemConfirmationController? _itemConfirmationController;
|
||||
private bool _disposed;
|
||||
|
||||
private RetailUiRuntime(RetailUiRuntimeBindings bindings)
|
||||
|
|
@ -148,7 +154,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
MountToolbar();
|
||||
MountCombat();
|
||||
MountJumpPowerbar();
|
||||
MountConfirmationDialogs();
|
||||
MountDialogFactory();
|
||||
MountCharacter();
|
||||
MountPlugins();
|
||||
MountInventory();
|
||||
|
|
@ -191,7 +197,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
public SelectedObjectController? SelectedObjectController { get; private set; }
|
||||
public UiViewport? PaperdollViewportWidget { get; private set; }
|
||||
public UiNineSlicePanel? InventoryFrame { get; private set; }
|
||||
public RetailConfirmationDialogService? ConfirmationDialogs { get; private set; }
|
||||
public RetailDialogFactory? DialogFactory { get; private set; }
|
||||
|
||||
public static RetailUiRuntime Mount(RetailUiRuntimeBindings bindings)
|
||||
{
|
||||
|
|
@ -212,7 +218,7 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
FpsController?.Tick();
|
||||
JumpPowerbarController?.Tick();
|
||||
SelectedObjectController?.Tick(deltaSeconds);
|
||||
ConfirmationDialogs?.Tick();
|
||||
DialogFactory?.Tick();
|
||||
Host.Tick(deltaSeconds);
|
||||
_automation?.Tick(deltaSeconds);
|
||||
}
|
||||
|
|
@ -222,6 +228,21 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
public bool HandleInputAction(AcDream.UI.Abstractions.Input.InputAction action)
|
||||
=> ToolbarInputController?.Handle(action) == true;
|
||||
|
||||
public bool HandleConfirmationRequest(GameEvents.CharacterConfirmationRequest request)
|
||||
=> _gameplayConfirmationController?.HandleRequest(request) == true;
|
||||
|
||||
public bool HandleConfirmationDone(GameEvents.CharacterConfirmationDone done)
|
||||
=> _gameplayConfirmationController?.HandleDone(done) == true;
|
||||
|
||||
public uint ShowConfirmation(string message, Action<bool> completed)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(message);
|
||||
ArgumentNullException.ThrowIfNull(completed);
|
||||
return DialogFactory?.MakeConfirmation(
|
||||
message,
|
||||
data => completed(data.GetBoolean(RetailDialogProperty.ConfirmationResult))) ?? 0u;
|
||||
}
|
||||
|
||||
public void UpdateCursor(IEnumerable<IMouse> mice)
|
||||
{
|
||||
CursorFeedback feedback = _bindings.Cursor.Feedback.Update(Host.Root);
|
||||
|
|
@ -645,34 +666,49 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
Console.WriteLine("[D.6] retail jump bar from gmFloatyPowerBarUI LayoutDesc 0x21000072.");
|
||||
}
|
||||
|
||||
private void MountConfirmationDialogs()
|
||||
private void MountDialogFactory()
|
||||
{
|
||||
ImportedLayout? layout;
|
||||
uint layoutId;
|
||||
lock (_bindings.Assets.DatLock)
|
||||
{
|
||||
// DialogFactory::CreateDialog_ @ 0x00477AD0 calls
|
||||
// GetDIDByEnum(2, 5), then creates root element 0x15.
|
||||
// DialogFactory::CreateDialog_ @ 0x00477AD0 resolves the shared
|
||||
// catalog through GetDIDByEnum(2, 5). Each shown DialogInfo then
|
||||
// creates a fresh type-specific root from that catalog.
|
||||
layoutId = RetailDataIdResolver.Resolve(_bindings.Assets.Dats, 2u, 5u);
|
||||
layout = layoutId == 0u
|
||||
? null
|
||||
: LayoutImporter.Import(
|
||||
_bindings.Assets.Dats,
|
||||
layoutId,
|
||||
RetailConfirmationDialogService.RootElementId,
|
||||
_bindings.Assets.ResolveSprite,
|
||||
_bindings.Assets.DefaultFont,
|
||||
_bindings.Assets.ResolveFont);
|
||||
}
|
||||
|
||||
if (layout is null)
|
||||
if (layoutId == 0u)
|
||||
{
|
||||
Console.WriteLine("[UI] confirmation dialog catalog could not be resolved.");
|
||||
Console.WriteLine("[UI] retail dialog catalog could not be resolved.");
|
||||
return;
|
||||
}
|
||||
|
||||
ConfirmationDialogs = new RetailConfirmationDialogService(Host.Root, layout);
|
||||
Console.WriteLine($"[UI] retail confirmation dialogs from LayoutDesc 0x{layoutId:X8} element 0x15.");
|
||||
ImportedLayout? CreateLayout(RetailDialogType type)
|
||||
{
|
||||
uint rootElementId = RetailDialogFactory.RootElementId(type);
|
||||
if (rootElementId == 0u)
|
||||
return null;
|
||||
lock (_bindings.Assets.DatLock)
|
||||
{
|
||||
return LayoutImporter.Import(
|
||||
_bindings.Assets.Dats,
|
||||
layoutId,
|
||||
rootElementId,
|
||||
_bindings.Assets.ResolveSprite,
|
||||
_bindings.Assets.DefaultFont,
|
||||
_bindings.Assets.ResolveFont);
|
||||
}
|
||||
}
|
||||
|
||||
DialogFactory = new RetailDialogFactory(Host.Root, CreateLayout);
|
||||
_gameplayConfirmationController = new GameplayConfirmationController(
|
||||
DialogFactory,
|
||||
_bindings.Confirmations.SendResponse);
|
||||
_itemConfirmationController = new RetailItemConfirmationController(
|
||||
DialogFactory,
|
||||
ItemInteraction);
|
||||
Console.WriteLine(
|
||||
$"[UI] retail DialogFactory from LayoutDesc 0x{layoutId:X8}; confirmation root 0x15.");
|
||||
}
|
||||
|
||||
private (uint[] Regular, uint[] Ghosted, uint[]? Empty) LoadToolbarDigits()
|
||||
|
|
@ -889,6 +925,9 @@ public sealed class RetailUiRuntime : IDisposable
|
|||
_disposed = true;
|
||||
_persistence?.Dispose();
|
||||
Host.WindowManager.WindowVisibilityChanged -= OnWindowVisibilityChanged;
|
||||
_itemConfirmationController?.Dispose();
|
||||
_gameplayConfirmationController?.Dispose();
|
||||
DialogFactory?.Dispose();
|
||||
Host.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue