refactor(settings): OP9 — retire the dead F11 settings surface + fully-superseded GameplaySettings
Campaign OP slice OP9 code retirement (docs/plans/2026-08-10-options-panel-campaign.md
§OP9). The retail four-tab Options panel (OP1-OP8) is now acdream's one
in-client settings surface (D1) — this commit deletes the pre-retail-UI
surfaces it fully superseded. Pure retirement: no behavior change to
anything live, verified by dispositioning every one of the 15 src files
and 8 test files that referenced the deleted types before touching any
of them.
1. SettingsVM + SettingsPanel (the old F11 IPanel surface, unrendered
since Campaign V slice V11's ImGui deletion) deleted outright, plus
their two dedicated test files. IPanel/IPanelRenderer stay — ChatPanel/
DebugPanel/VitalsPanel still implement IPanel, so the contract does NOT
become unreferenced.
2. RuntimeSettingsController's SettingsVM binding seam deleted:
CreateViewModel, CreateViewModelBinding, RuntimeSettingsViewModelBinding,
the _viewModel field, UnbindViewModel, and every _viewModel? notification
call (ToggleFrameRate, LoadCharacterContext, RestoreDefaultCharacterContext,
SyncChatFromServerOptions). CreateViewModelBinding had zero production
callers (test-only). HasDraftPreview/DisplayPreview/AudioPreview stay on
IRuntimeSettingsPreviewSource (WorldRenderFrameBuilder and
SettingsParticleRangeSource still consume it) but now trivially mirror
the committed Display/Audio snapshot — HasDraftPreview was already
always false in production. GameWindowLifetime's matching
"settings view model" shutdown stage is deleted.
3. IDevToolsGameplayCommands + DevToolsGameplayCommands deleted from
GameplayInputCommandController.cs. All three members were dead:
ToggleSettingsPanel() had ZERO dispatch sites (ToggleOptionsPanel always
routed to _retained, never to _devTools); ToggleDebugPanel()/
FocusChatInput() had dispatch sites (F1/Ctrl+F1, Tab) but empty no-op
bodies (their ImGui DebugPanel/ChatPanel targets were already gone).
The two live dispatch sites are kept as inert `return true;` cases
(still consuming the key, matching the prior no-op's "handled"
contract) instead of falling through to a lower-priority scope.
SessionPlayerComposition.cs's `new DevToolsGameplayCommands()`
construction is removed. No `ToggleSettingsPanel` InputAction exists
(only `ToggleOptionsPanel`, rebound at OP3) — nothing to remove there
or from KeyBindings.RetailDefaults()/keymap fixtures.
4. GameplaySettings deleted entirely (the type, SettingsStore's
LoadGameplay/SaveGameplay/BuildGameplayObject, RuntimeSettingsController's
Gameplay property/SetAcceptLootPermits). Verified all 13 remaining
members (ToggleRun, AdvancedCombatUI, ShowTooltips,
VividTargetingIndicator, SideBySideVitals, CoordinatesOnRadar,
SpellDuration, AllowGive, ShowHelm, ShowCloak, LockUI, UseMouseTurning,
AcceptLootPermits — the three combat ones already died at OP4/AP-196)
were ALREADY bound through CharacterOptionTable/
CharacterOptionsPageController's server-bit seam at OP4 before deleting
the client-local mirror — no (c)-case genuinely-client-local member
was found; disposition (b) covers 100% of the surface. SetUiLocked
rewritten to compare only against the last value actually pushed to
_runtimeTargets (MUST-FIX 4's guard), with no second store left to
read or write. LiveSessionRuntimeFactory's SetAcceptLootPermits binding
now sends the wire option only (the GameplaySettings write-behind call
removed as dead output). CharacterSettings/DisplaySettings/
AudioSettings/ChatSettings and their SettingsStore Load/Save surfaces
are UNTOUCHED per the campaign contract.
Per-file disposition (15 src + 8 test files that referenced
GameplaySettings before this commit):
- GameplaySettings.cs, SettingsVM.cs, SettingsPanel.cs: the types
themselves — deleted.
- SettingsStore.cs, RuntimeSettingsController.cs,
LiveSessionRuntimeFactory.cs: real usage — API deleted/rewritten.
- RetailUiRuntime.cs, InteractionRetainedUiComposition.cs,
SessionPlayerComposition.cs, CombatUiController.cs,
LiveCombatAttackOperations.cs, LivePresentationComposition.cs,
FrameRootComposition.cs, RuntimeCharacterState.cs,
CombatCameraTargetSource.cs: doc-comment-only or interface-name
substring matches (ICombatGameplaySettingsSource) — left as accurate
historical record, no forward reference to the deleted type.
- Tests: RuntimeSettingsControllerTests.cs and SettingsStoreTests.cs
rewritten (Gameplay-specific tests deleted; SaveDisplay/SaveAudio/
SaveChat tests re-targeted off the now-public methods instead of the
retired SettingsVM draft/Save() indirection); GameplaySettingsTests.cs/
SettingsVMTests.cs/SettingsPanelTests.cs deleted; the remaining three
(CharacterOptionCombatSettingsSourceTests.cs,
CombatCameraTargetSourceTests.cs, LiveCombatAttackOperationsTests.cs)
were comment/interface-name-only, untouched.
5. Register: AP-196 (OP4's partial GameplaySettings retirement, which left
five fields as write-behind mirrors) is fully retired now that the
record is gone outright — marked ~~AP-196~~ RETIRED with its retirement
note, active-row count 143 -> 142. No other row cited the deleted types
directly (AP-194/AP-193 cite CharacterOptionTable.cs, not
GameplaySettings.cs).
6. Settings.json migration honesty: SettingsStore no longer reads or
writes the "gameplay" top-level key, so an existing file carrying one
from a pre-OP9 build is neither parsed nor dropped — the existing
SaveSection raw-JSON-text preservation mechanism (unknown top-level
keys survive every subsequent save) carries it forward untouched.
Two new targeted tests
(LeftoverGameplaySection_FromAnOlderSettingsJson_DoesNotBreakOtherLoads,
LeftoverGameplaySection_SurvivesAnUnrelatedSave) pin this.
InputAction.ToggleOptionsPanel's stale doc comment (still describing the
retired ImGui SettingsPanel) and a handful of other dangling doc
references (DisplaySettings.cs, ChatOpacityLink.cs,
SettingsDevToolsComposition.cs, InputDispatcherCaptureTests.cs) are
reworded to point at the current retail Options panel / OP8
KeyboardConfigController.
Build: dotnet build -c Release green, 0 errors. Tests: dotnet test -c
Release --no-build — 13,075 passed / 4 skipped / 0 failed (13,079 total),
down from the stated baseline of 13,155 passed / 4 skipped / 0 failed
(13,159 total) — the -80 delta is exactly the deleted SettingsVM/
SettingsPanel/GameplaySettings test surface (three whole files plus the
Gameplay-specific cases trimmed from RuntimeSettingsControllerTests.cs/
SettingsStoreTests.cs), with zero regressions elsewhere.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
1a57f96efe
commit
371197a345
22 changed files with 228 additions and 3260 deletions
|
|
@ -11,10 +11,11 @@ namespace AcDream.UI.Abstractions.Panels.Settings;
|
|||
public readonly record struct UiWindowPosition(float X, float Y);
|
||||
|
||||
/// <summary>
|
||||
/// JSON-backed persistence for non-keybind settings (Display today; future
|
||||
/// tabs Audio / Gameplay / Chat / Character will be added to the same
|
||||
/// file). The graphical host supplies a canonical portable configuration
|
||||
/// path. Coexists
|
||||
/// JSON-backed persistence for non-keybind settings (Display / Audio / Chat /
|
||||
/// Character; the OP9-retired <c>Gameplay</c> section is no longer read or
|
||||
/// written — see the class's Schema note below for how a leftover
|
||||
/// <c>"gameplay"</c> block from an older settings.json is tolerated). The
|
||||
/// graphical host supplies a canonical portable configuration path. Coexists
|
||||
/// with <c>keybinds.json</c>, which retains its own
|
||||
/// <see cref="Input.KeyBindings.LoadOrDefault"/> path.
|
||||
///
|
||||
|
|
@ -29,7 +30,11 @@ public readonly record struct UiWindowPosition(float X, float Y);
|
|||
/// </code>
|
||||
/// Unknown top-level keys are preserved on save so future tab additions
|
||||
/// from a newer client don't get clobbered by an older client writing
|
||||
/// out only the sections it knows about.
|
||||
/// out only the sections it knows about — the SAME round-trip preservation
|
||||
/// (<see cref="SaveSection"/>'s raw-JSON-text carry-forward) that keeps an
|
||||
/// EXISTING file's now-orphaned <c>"gameplay"</c> block intact forever: no
|
||||
/// <c>Load*</c> method here reads it, so it is neither parsed nor dropped,
|
||||
/// just silently carried along untouched on every subsequent save.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public sealed class SettingsStore
|
||||
|
|
@ -149,49 +154,6 @@ public sealed class SettingsStore
|
|||
public void SaveAudio(AudioSettings audio)
|
||||
=> SaveSection("audio", BuildAudioObject(audio));
|
||||
|
||||
/// <summary>
|
||||
/// Load Gameplay settings (subset of retail CharacterOption flags).
|
||||
/// Same fall-back behaviour as <see cref="LoadDisplay"/>.
|
||||
/// </summary>
|
||||
public GameplaySettings LoadGameplay()
|
||||
{
|
||||
if (!File.Exists(_path)) return GameplaySettings.Default;
|
||||
try
|
||||
{
|
||||
using var stream = File.OpenRead(_path);
|
||||
var doc = JsonDocument.Parse(stream);
|
||||
var root = doc.RootElement;
|
||||
if (!root.TryGetProperty("gameplay", out var gp)
|
||||
|| gp.ValueKind != JsonValueKind.Object)
|
||||
return GameplaySettings.Default;
|
||||
|
||||
var d = GameplaySettings.Default;
|
||||
return new GameplaySettings(
|
||||
ToggleRun: ReadBool(gp, "toggleRun", d.ToggleRun),
|
||||
AdvancedCombatUI: ReadBool(gp, "advancedCombatUI", d.AdvancedCombatUI),
|
||||
ShowTooltips: ReadBool(gp, "showTooltips", d.ShowTooltips),
|
||||
VividTargetingIndicator: ReadBool(gp, "vividTargetingIndicator", d.VividTargetingIndicator),
|
||||
SideBySideVitals: ReadBool(gp, "sideBySideVitals", d.SideBySideVitals),
|
||||
CoordinatesOnRadar: ReadBool(gp, "coordinatesOnRadar", d.CoordinatesOnRadar),
|
||||
SpellDuration: ReadBool(gp, "spellDuration", d.SpellDuration),
|
||||
AllowGive: ReadBool(gp, "allowGive", d.AllowGive),
|
||||
ShowHelm: ReadBool(gp, "showHelm", d.ShowHelm),
|
||||
ShowCloak: ReadBool(gp, "showCloak", d.ShowCloak),
|
||||
LockUI: ReadBool(gp, "lockUI", d.LockUI),
|
||||
UseMouseTurning: ReadBool(gp, "useMouseTurning", d.UseMouseTurning),
|
||||
AcceptLootPermits: ReadBool(gp, "acceptLootPermits", d.AcceptLootPermits));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"settings: failed to load {_path}: {ex.Message} — using defaults");
|
||||
return GameplaySettings.Default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Save Gameplay settings, preserving all other top-level keys.</summary>
|
||||
public void SaveGameplay(GameplaySettings gameplay)
|
||||
=> SaveSection("gameplay", BuildGameplayObject(gameplay));
|
||||
|
||||
/// <summary>Load Chat settings. Same fall-back behaviour as <see cref="LoadDisplay"/>.</summary>
|
||||
public ChatSettings LoadChat()
|
||||
{
|
||||
|
|
@ -624,24 +586,6 @@ public sealed class SettingsStore
|
|||
["showTimestamps"] = c.ShowTimestamps,
|
||||
};
|
||||
|
||||
private static SortedDictionary<string, object> BuildGameplayObject(GameplaySettings g)
|
||||
=> new(StringComparer.Ordinal)
|
||||
{
|
||||
["advancedCombatUI"] = g.AdvancedCombatUI,
|
||||
["acceptLootPermits"] = g.AcceptLootPermits,
|
||||
["allowGive"] = g.AllowGive,
|
||||
["coordinatesOnRadar"] = g.CoordinatesOnRadar,
|
||||
["lockUI"] = g.LockUI,
|
||||
["showCloak"] = g.ShowCloak,
|
||||
["showHelm"] = g.ShowHelm,
|
||||
["showTooltips"] = g.ShowTooltips,
|
||||
["sideBySideVitals"] = g.SideBySideVitals,
|
||||
["spellDuration"] = g.SpellDuration,
|
||||
["toggleRun"] = g.ToggleRun,
|
||||
["useMouseTurning"] = g.UseMouseTurning,
|
||||
["vividTargetingIndicator"] = g.VividTargetingIndicator,
|
||||
};
|
||||
|
||||
private static SortedDictionary<string, object> BuildDisplayObject(DisplaySettings d)
|
||||
=> new(StringComparer.Ordinal)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue