fix #208: keep combat bar hidden in peace mode

Treat combat-window visibility as gameplay-state owned so character layout restoration cannot replay a stale visible bit. Reset combat state to NonCombat at character-session entry, matching retail ClientCombatSystem::Begin.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-12 22:30:55 +02:00
parent 00fe993f6f
commit 8e9c538519
8 changed files with 109 additions and 14 deletions

View file

@ -16,6 +16,7 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
private readonly SettingsStore _store;
private readonly Func<string> _characterKey;
private readonly Func<(int Width, int Height)> _screenSize;
private readonly HashSet<string> _stateManagedVisibilityWindows;
private readonly List<RetailWindowHandle> _attached = new();
private bool _restoring;
private bool _disposed;
@ -24,12 +25,16 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
RetailWindowManager manager,
SettingsStore store,
Func<string> characterKey,
Func<(int Width, int Height)> screenSize)
Func<(int Width, int Height)> screenSize,
IEnumerable<string>? stateManagedVisibilityWindows = null)
{
_manager = manager ?? throw new ArgumentNullException(nameof(manager));
_store = store ?? throw new ArgumentNullException(nameof(store));
_characterKey = characterKey ?? throw new ArgumentNullException(nameof(characterKey));
_screenSize = screenSize ?? throw new ArgumentNullException(nameof(screenSize));
_stateManagedVisibilityWindows = stateManagedVisibilityWindows is null
? new HashSet<string>(StringComparer.Ordinal)
: new HashSet<string>(stateManagedVisibilityWindows, StringComparer.Ordinal);
foreach (RetailWindowHandle handle in manager.Windows)
Attach(handle);
@ -54,7 +59,11 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
character, resolution, handle.Name, fallback);
if (saved is not { } layout) continue;
Apply(handle, layout, screen);
Apply(
handle,
layout,
screen,
restoreVisibility: !_stateManagedVisibilityWindows.Contains(handle.Name));
// Lazily migrate legacy position-only entries into the complete schema.
_store.SaveWindowLayout(character, resolution, handle.Name, Capture(handle));
}
@ -70,8 +79,11 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
_attached.Add(handle);
handle.Moved += OnChanged;
handle.Resized += OnChanged;
handle.Shown += OnChanged;
handle.Hidden += OnChanged;
if (!_stateManagedVisibilityWindows.Contains(handle.Name))
{
handle.Shown += OnChanged;
handle.Hidden += OnChanged;
}
}
private void OnChanged(RetailWindowHandle handle)
@ -111,7 +123,8 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
private static void Apply(
RetailWindowHandle handle,
UiWindowLayout layout,
(int Width, int Height) screen)
(int Width, int Height) screen,
bool restoreVisibility)
{
UiElement frame = handle.OuterFrame;
float width = ClampDimension(layout.Width, frame.Width, frame.MinWidth, frame.MaxWidth, screen.Width);
@ -128,8 +141,11 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
Collapsed: layout.Collapsed,
Maximized: layout.Maximized));
if (layout.Visible) handle.Show();
else handle.Hide();
if (restoreVisibility)
{
if (layout.Visible) handle.Show();
else handle.Hide();
}
}
private (int Width, int Height) ValidScreenSize()
@ -168,8 +184,11 @@ public sealed class RetailWindowLayoutPersistence : IDisposable
{
handle.Moved -= OnChanged;
handle.Resized -= OnChanged;
handle.Shown -= OnChanged;
handle.Hidden -= OnChanged;
if (!_stateManagedVisibilityWindows.Contains(handle.Name))
{
handle.Shown -= OnChanged;
handle.Hidden -= OnChanged;
}
}
_attached.Clear();
}