feat(ui): Phase D.2a — VitalsPanel wired into GameWindow + backend pivot
Closes Phase D.2a. Launch with ACDREAM_DEVTOOLS=1 now shows a live
ImGui "Vitals" window whose HP bar reads CombatState.GetHealthPercent
for the local player. Without the env var the branches are dead code,
no ImGui context is created, and behaviour is identical to before.
GameWindow hunks:
- fields: _imguiBootstrap / _panelHost / _vitalsVm + DevToolsEnabled
- init (OnLoad): construct bootstrap + host, register VitalsPanel
- GUID push: _vitalsVm?.SetLocalPlayerGuid(chosen.Id) at live-connect
- frame begin: _imguiBootstrap.BeginFrame(dt) after GL clear
- frame end: _panelHost.RenderAll(ctx) + _imguiBootstrap.Render() after debug overlay
- input gating: skip WASD when ImGui.GetIO().WantCaptureKeyboard
Backend pivot: Hexa.NET.ImGui → ImGui.NET + Silk.NET.OpenGL.Extensions.ImGui.
First-light integration with the Hexa backend crashed 0xC0000005 inside
Hexa.NET.ImGui.Backends.OpenGL3.ImGuiImplOpenGL3.InitNative. Root cause:
Hexa's native OpenGL3 backend resolves GL function pointers via GLFW or
SDL internally; with Silk.NET (which uses neither) the pointers are null
and the native code crashes on first use. The mitigation path was
already planned — the design doc's Risk section called a pivot to
ImGui.NET a "one-morning operation" — and that's exactly what happened.
- Packages: Hexa.NET.ImGui 2.2.9 + Hexa.NET.ImGui.Backends 1.0.18
→ ImGui.NET 1.91.6.1 + Silk.NET.OpenGL.Extensions.ImGui 2.23.0
- ImGuiBootstrapper: was static Initialize(gl)+Shutdown() wrapping
Hexa's OpenGL3 init; now an IDisposable wrapping Silk.NET's
ImGuiController instance which handles GL backend init + input
subscription in one go.
- SilkInputBridge.cs deleted (~190 LOC): ImGuiController subscribes
IKeyboard / IMouse events itself, we don't need a bespoke bridge.
- ImGuiPanelRenderer: ImGuiNET.ImGui.* calls instead of
Hexa.NET.ImGui.ImGui.*. Widget surface unchanged.
Boundary discipline is preserved — no panel imports ImGuiNET; only
ImGuiPanelRenderer does. The D.2b custom toolkit will implement the
same IPanelRenderer contract without touching panel code.
Out of scope (tracked for follow-up):
- Stam/Mana currently return float? null (VitalsVM). Absolute values
need LocalPlayerState + PlayerDescription (0x0013) parsing to be
stored rather than discarded — filed as a post-D.2a issue.
- Mouse-capture gating (WorldMouseFallThrough-style click-through
tests) — not needed until we add clickable inventory items.
Roadmap + memory + architecture doc + UI framework plan updated in the
same commit per CLAUDE.md roadmap-discipline rules. 753 tests pass
(550 Core + 192 Core.Net + 11 new UI.Abstractions), 0 build warnings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a7dbce3474
commit
55aaca7a14
13 changed files with 218 additions and 275 deletions
|
|
@ -1,31 +1,32 @@
|
|||
using System.Numerics;
|
||||
using AcDream.UI.Abstractions;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace AcDream.UI.ImGui;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="IPanelRenderer"/> implemented as thin wrappers around
|
||||
/// Hexa.NET.ImGui calls. This is the ONLY place where Hexa.NET.ImGui
|
||||
/// types appear outside of bootstrap / input-bridge plumbing — panels
|
||||
/// that need a feature must extend the abstraction here, not by importing
|
||||
/// ImGui in panel files.
|
||||
/// ImGui.NET calls. This is the ONLY place where ImGuiNET types appear
|
||||
/// outside of bootstrap plumbing — panels that need a feature must
|
||||
/// extend the abstraction here, not by importing ImGuiNET in panel
|
||||
/// files.
|
||||
/// </summary>
|
||||
public sealed class ImGuiPanelRenderer : IPanelRenderer
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public bool Begin(string title) => Hexa.NET.ImGui.ImGui.Begin(title);
|
||||
public bool Begin(string title) => ImGuiNET.ImGui.Begin(title);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void End() => Hexa.NET.ImGui.ImGui.End();
|
||||
public void End() => ImGuiNET.ImGui.End();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Text(string text) => Hexa.NET.ImGui.ImGui.TextUnformatted(text);
|
||||
public void Text(string text) => ImGuiNET.ImGui.TextUnformatted(text);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SameLine() => Hexa.NET.ImGui.ImGui.SameLine();
|
||||
public void SameLine() => ImGuiNET.ImGui.SameLine();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Separator() => Hexa.NET.ImGui.ImGui.Separator();
|
||||
public void Separator() => ImGuiNET.ImGui.Separator();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ProgressBar(float fraction, float width, string? overlay = null)
|
||||
|
|
@ -36,6 +37,6 @@ public sealed class ImGuiPanelRenderer : IPanelRenderer
|
|||
else if (fraction > 1f) fraction = 1f;
|
||||
|
||||
var size = new Vector2(width, 0f); // height 0 → ImGui picks based on font
|
||||
Hexa.NET.ImGui.ImGui.ProgressBar(fraction, size, overlay ?? string.Empty);
|
||||
ImGuiNET.ImGui.ProgressBar(fraction, size, overlay ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue