From 1d8371dbe5d56fb1cc26ae361dac975d73685aa8 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 31 Jul 2026 08:22:46 +0200 Subject: [PATCH] fix(ui): refresh live skill rows --- .../UI/Layout/CharacterStatController.cs | 18 ++++++++++-- src/AcDream.App/UI/RetailUiRuntime.cs | 12 ++++++-- .../UI/Layout/CharacterStatControllerTests.cs | 29 +++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/AcDream.App/UI/Layout/CharacterStatController.cs b/src/AcDream.App/UI/Layout/CharacterStatController.cs index d8b56b46..63c250d2 100644 --- a/src/AcDream.App/UI/Layout/CharacterStatController.cs +++ b/src/AcDream.App/UI/Layout/CharacterStatController.cs @@ -776,12 +776,14 @@ public static class CharacterStatController foreach (var skill in skills) { int rowIndex = bindings.Count; + CharacterSkill LiveSkill() => + FindSkill(data(), skill.Id) ?? skill; var row = AddRow(list, datFont, spriteResolve, left: 0f, top: y, width: listW, height: SkillRowHeight, iconDid: skill.IconDid, nameText: skill.Name, - valueProvider: () => skill.CurrentLevel.ToString(), - valueColorProvider: () => SkillValueColor(skill), + valueProvider: () => LiveSkill().CurrentLevel.ToString(), + valueColorProvider: () => SkillValueColor(LiveSkill()), nameColor: Vector4.One); row.OnClick = () => { @@ -857,6 +859,18 @@ public static class CharacterStatController return result; } + private static CharacterSkill? FindSkill(CharacterSheet sheet, uint skillId) + { + IReadOnlyList skills = sheet.Skills; + for (int i = 0; i < skills.Count; i++) + { + CharacterSkill skill = skills[i]; + if (skill.Id == skillId) + return skill; + } + return null; + } + private static CharacterSkill? SkillAtDisplayIndex(CharacterSheet sheet, int index) { if (index < 0) return null; diff --git a/src/AcDream.App/UI/RetailUiRuntime.cs b/src/AcDream.App/UI/RetailUiRuntime.cs index 4d436089..cec6f563 100644 --- a/src/AcDream.App/UI/RetailUiRuntime.cs +++ b/src/AcDream.App/UI/RetailUiRuntime.cs @@ -209,6 +209,7 @@ public sealed class RetailUiRuntime : IDisposable private UiShortcutDigitGraphics? _shortcutDigitGraphics; private ItemCooldownUiController? _itemCooldownController; private VividTargetIndicatorController? _vividTargetIndicator; + private IDisposable? _characterSheetSubscription; private ResourceShutdownTransaction? _shutdown; private bool _disposed; @@ -1676,9 +1677,12 @@ public sealed class RetailUiRuntime : IDisposable return; } CharacterSheetProvider provider = _bindings.Character.Provider; + CharacterSheet currentSheet = provider.BuildSheet(); + _characterSheetSubscription = provider.SubscribeChanged( + () => currentSheet = provider.BuildSheet()); CharacterStatController.Bind( layout, - provider.BuildSheet, + () => currentSheet, _bindings.Assets.DefaultFont, _bindings.Assets.ResolveFont(0x40000001u) ?? _bindings.Assets.DefaultFont, _bindings.Assets.ResolveSprite, @@ -1922,7 +1926,11 @@ public sealed class RetailUiRuntime : IDisposable _shutdown ??= CreateShutdownTransaction( () => _automation?.Dispose(), () => _persistence?.Dispose(), - () => Host.WindowManager.WindowVisibilityChanged -= OnWindowVisibilityChanged, + () => + { + _characterSheetSubscription?.Dispose(); + Host.WindowManager.WindowVisibilityChanged -= OnWindowVisibilityChanged; + }, () => _itemConfirmationController?.Dispose(), () => _gameplayConfirmationController?.Dispose(), () => DialogFactory?.Dispose(), diff --git a/tests/AcDream.App.Tests/UI/Layout/CharacterStatControllerTests.cs b/tests/AcDream.App.Tests/UI/Layout/CharacterStatControllerTests.cs index 212b0af4..430452f6 100644 --- a/tests/AcDream.App.Tests/UI/Layout/CharacterStatControllerTests.cs +++ b/tests/AcDream.App.Tests/UI/Layout/CharacterStatControllerTests.cs @@ -1476,6 +1476,35 @@ public class CharacterStatControllerTests Assert.Equal((" (+50)", buff), (runs[2].Text, runs[2].Color)); } + [Fact] + public void SkillRow_ValueAndColorFollowLiveSheetWithoutTabRebuild() + { + var list = new UiPanel { Width = 300 }; + var layout = Fake((CharacterStatController.ListBoxId, list)); + CharacterSheet sheet = VitaeSkillSheet( + currentLevel: 300, + baseLevel: 300, + vitaeModifier: 0); + + CharacterStatController.Bind( + layout, + () => sheet, + spriteResolve: id => (id, 16, 16)); + ClickTab(layout, left: 92f); + + UiText value = SkillRows(list)[0].Children.OfType().ToList()[2]; + Assert.Equal("300", value.LinesProvider()[0].Text); + Assert.Equal(Vector4.One, value.LinesProvider()[0].Color); + + sheet = VitaeSkillSheet( + currentLevel: 350, + baseLevel: 300, + vitaeModifier: 0); + + Assert.Equal("350", value.LinesProvider()[0].Text); + Assert.Equal(new Vector4(0f, 1f, 0f, 1f), value.LinesProvider()[0].Color); + } + [Fact] public void SkillClick_ZeroDelta_NoParentheticals() {