feat(ui): Campaign OP slice OP4 — the Character tab
Binds LayoutDesc 0x21000028 (gmCharacterSettingsUI) through OP2's template-list mechanism and OP3's OptionPage model: 6 authored group headers + 50 toggle rows (49 from the 2013 build + D3's "Listen to PK death messages", AP-193) in research doc §2's authored order, each row resolved by PlayerOption id through CharacterOptionTable, seeded from live RuntimeCharacterOptionsState, defaulted from CharacterOptionTable. ClientDefault (byte-verified against UIOption_Checkbox::SetPlayerOption @0x00486e80's own GetDefaultOptionValue call — AP-194 updated to confirm the directive was followed), labels/tooltips resolved by name from string table 0x23000003 (never hard-coded English), and registered with OptionsPanelController.CharacterPage. Apply/Reset/Defaults (0x100001FC/FD/FE) are now wired per-page via a scoped subtree search (UiElement.FindDescendant, promoted from UiTabPanel) since Character/ Chat/Config each author their own physical instance under the SAME element ids. Consumers: Group A (29 ids) wire+store only via the existing SetSingleCharacterOptionRuntimeCmd/TrySetOption seam. Group B: Display Timestamps prefixes new transcript lines (RuntimeCommunicationState. DisplayTimestampsSource); Disable Distance Fog forces FogMode.Off (WeatherSystem.DisableDistanceFogSource, retiring half of TS-73); Run as Default Movement inverts the walk-mode modifier's default (RuntimeLocalPlayerMovementState.RunAsDefaultMovementSource). Group C re-points AutoTarget/AutoRepeatAttack/ViewCombatTarget (CharacterOptionCombatSettingsSource), VividTargetingIndicator/ CoordinatesOnRadar/LockUI/AcceptLootPermits from the client-local GameplaySettings record to the canonical server bit — closing two previously-unfiled divergences where AutoRepeatAttack and AcceptCorpseLootingPermissions never reached the wire despite being retail auto-save ids. TS-73 narrowed to its two still-open cases; TS-75..TS-80 file the genuine gaps (no day/night force, no weather- particle/profanity-filter/salvage/housing/pickup-preference subsystem, fellowship-create's unaudited client-sourced field) rather than inventing stand-ins. Conformance: CharacterOptionsPageControllerTests pins all 50 rows against CharacterOptionTable in both directions (an invented or dropped row fails the build), the authored group/order row-by-row, and the build/seed/Apply/Reset/Defaults/wire-publish behavior end-to-end against the committed fixture. 52 new tests; full solution suite 13,008 passed / 4 skipped / 0 failed (was 12,956/4/0). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7e9f372ce8
commit
22b86b9ff4
25 changed files with 1674 additions and 41 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using AcDream.App.Input;
|
||||
using AcDream.App.Net;
|
||||
using AcDream.Core.Combat;
|
||||
using AcDream.Core.Net.Messages;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
using AcDream.UI.Abstractions.Panels.Settings;
|
||||
|
||||
|
|
@ -27,6 +28,42 @@ internal sealed class GameplaySettingsState : ICombatGameplaySettingsSource
|
|||
public bool ViewCombatTarget => Value.ViewCombatTarget;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// D7 Group-C re-point (Campaign OP slice OP4, 2026-08-11):
|
||||
/// <c>AutoTarget</c>/<c>AutoRepeatAttack</c>/<c>ViewCombatTarget</c> move
|
||||
/// from the client-local <c>GameplaySettings</c> record (what
|
||||
/// <see cref="GameplaySettingsState"/> and the legacy
|
||||
/// <c>RuntimeSettingsController</c> read) to the canonical
|
||||
/// server-authoritative <see cref="RuntimeCharacterOptionsState"/> — the
|
||||
/// CH3 precedent (server bit is authoritative; the Character-tab panel
|
||||
/// row's LED click writes THROUGH <c>RuntimeCharacterOptionsState.
|
||||
/// TrySetOption</c> before this source can ever observe the new value, so
|
||||
/// no separate reseed/sync step is needed here). Also closes two
|
||||
/// previously-unfiled divergences (character-options-map.md §0):
|
||||
/// <c>AutoRepeatAttack</c> and (via <c>ClientCommandController</c>'s
|
||||
/// <c>/consent</c> re-point, same commit) <c>AcceptCorpseLootingPermissions</c>
|
||||
/// were client-local and never reached the wire even though retail
|
||||
/// auto-saves both (<c>0x0005</c> immediately).
|
||||
/// </summary>
|
||||
internal sealed class CharacterOptionCombatSettingsSource : ICombatGameplaySettingsSource
|
||||
{
|
||||
private readonly RuntimeCharacterOptionsState _options;
|
||||
|
||||
public CharacterOptionCombatSettingsSource(RuntimeCharacterOptionsState options)
|
||||
{
|
||||
_options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
public bool AutoTarget =>
|
||||
_options.GetOptionBit(CharacterOptionId.AutoTarget);
|
||||
|
||||
public bool AutoRepeatAttack =>
|
||||
_options.GetOptionBit(CharacterOptionId.AutoRepeatAttack);
|
||||
|
||||
public bool ViewCombatTarget =>
|
||||
_options.GetOptionBit(CharacterOptionId.ViewCombatTarget);
|
||||
}
|
||||
|
||||
internal interface ICombatFeedbackSink
|
||||
{
|
||||
void Show(string message);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue