diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 1488fc3a..2c19fde5 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -1780,6 +1780,11 @@ public sealed class GameWindow : IDisposable return (t, w, h); } + // Phase D.5.1 — icon composer for the toolbar shortcut slots. + // Constructed once here so the closure below can capture it; needs + // the same cache reference that ResolveChrome uses above. + var iconComposer = new AcDream.App.UI.IconComposer(_dats!, cache); + // Phase D.2b — optional retail stylesheet. controls.ini lives under // the AC install (ACDREAM_AC_DIR); absent → source-verified fallback. var controls = _options.AcDir is { } acDir @@ -1902,6 +1907,29 @@ public sealed class GameWindow : IDisposable } else Console.WriteLine("[D.2b] chat: LayoutDesc 0x21000006 not found."); + // Phase D.5.1 — toolbar window, data-driven from LayoutDesc 0x21000016 + // (gmToolbarUI). Mirrors the vitals/chat import+bind+mount pattern above. + AcDream.App.UI.Layout.ImportedLayout? toolbarLayout; + lock (_datLock) + toolbarLayout = AcDream.App.UI.Layout.LayoutImporter.Import( + _dats!, 0x21000016u, ResolveChrome, vitalsDatFont); + if (toolbarLayout is not null) + { + AcDream.App.UI.Layout.ToolbarController.Bind( + toolbarLayout, Items, + () => Shortcuts, + iconIds: (icon, under, over) => iconComposer.GetIcon(icon, under, over), + useItem: guid => UseItemByGuid(guid)); + + var toolbarRoot = toolbarLayout.Root; + toolbarRoot.Left = 10; toolbarRoot.Top = 300; + toolbarRoot.Anchors = AcDream.App.UI.AnchorEdges.Left | AcDream.App.UI.AnchorEdges.Top; + toolbarRoot.Draggable = true; + _uiHost.Root.AddChild(toolbarRoot); + Console.WriteLine("[D.5.1] retail toolbar window from LayoutDesc importer (0x21000016)."); + } + else Console.WriteLine("[D.5.1] toolbar: LayoutDesc 0x21000016 not found."); + // Drain plugin-registered markup panels (buffered before the GL // window opened) into the same UiRoot tree. A faulty plugin markup // file is isolated — logged + skipped, never crashes the client. @@ -11594,6 +11622,17 @@ public sealed class GameWindow : IDisposable } } + // Phase D.5.1 — direct use-by-guid for toolbar shortcut clicks. + // Mirrors the B.4b far-range send path; no proximity / auto-walk needed + // for items already in the player's inventory. + private void UseItemByGuid(uint guid) + { + if (_liveSession is null) return; + var seq = _liveSession.NextGameActionSequence(); + var body = AcDream.Core.Net.Messages.InteractRequests.BuildUse(seq, guid); + _liveSession.SendGameAction(body); + } + private void SendPickUp(uint itemGuid) { if (_liveSession is null