fix(ui): port live experience quality updates (#217)
Parse retail PrivateUpdatePropertyInt64 and route authoritative Total/Available Experience through both local-player projections so Attributes, the level meter, and Skills refresh together. Preserve the existing retail XP curve and right-align the Total XP value. Close the user-confirmed item-give gate for #216 and record the named-retail/ACE/holtburger conformance evidence. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
30d294506c
commit
84b7d2d7cd
15 changed files with 391 additions and 29 deletions
|
|
@ -2537,7 +2537,8 @@ public sealed class GameWindow : IDisposable
|
|||
// D.5.4: ingest CreateObject into the object table (upsert) and wire Delete +
|
||||
// UiEffects live update. Wire BEFORE EntitySpawned += OnLiveEntitySpawned so
|
||||
// the table is populated before the render handler runs.
|
||||
AcDream.Core.Net.ObjectTableWiring.Wire(session, Objects, () => _playerServerGuid);
|
||||
AcDream.Core.Net.ObjectTableWiring.Wire(
|
||||
session, Objects, () => _playerServerGuid, LocalPlayer);
|
||||
AcDream.Core.Net.CombatStateWiring.Wire(session, Combat);
|
||||
_liveSession.EntitySpawned += OnLiveEntitySpawned;
|
||||
_liveSession.EntityDeleted += OnLiveEntityDeleted;
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ public static class CharacterStatController
|
|||
|
||||
// TotalXpLabel (16px from dat) + TotalXp (16px from dat): pass null → keep dat font.
|
||||
LabelLeft(layout, contentPage, TotalXpLabelId, null, Body, static () => "Total Experience (XP):");
|
||||
Label(layout, contentPage, TotalXpId, null, Body, () => data().TotalXp.ToString("N0"));
|
||||
LabelRight(layout, contentPage, TotalXpId, null, Body, () => data().TotalXp.ToString("N0"));
|
||||
|
||||
// XP-to-level meter fill (gmStatManagementUI::UpdateExperience 0x004f0a70).
|
||||
// Fix 5: child elements 0x10000237 (label) and 0x10000238 (value) are now built by
|
||||
|
|
@ -1810,6 +1810,28 @@ public static class CharacterStatController
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>Right-justified numeric header value. The imported layout owns
|
||||
/// bounds/font; the controller owns runtime text and explicit justification.</summary>
|
||||
private static void LabelRight(
|
||||
ImportedLayout layout,
|
||||
UiElement? scope,
|
||||
uint id,
|
||||
UiDatFont? datFont,
|
||||
Vector4 color,
|
||||
Func<string> text)
|
||||
{
|
||||
if (FindTextByDatId(layout, scope, id) is UiText t)
|
||||
{
|
||||
if (datFont is not null) t.DatFont = datFont;
|
||||
t.Centered = false;
|
||||
t.RightAligned = true;
|
||||
t.OneLine = true;
|
||||
t.ClickThrough = true;
|
||||
t.Padding = 0f;
|
||||
t.LinesProvider = () => new[] { new UiText.Line(text(), color) };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Bind a directly-located <see cref="UiText"/> widget with a provider.
|
||||
/// Used when the widget was found by subtree walk rather than <c>FindElement</c>.
|
||||
/// Sets <c>Padding = 0</c> to prevent the scroll-clip from hiding text in small
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue