fix(ui,runtime): OP4 review fixes — live re-seed, enable-gating, Combat panel re-point, universal timestamps
Both OP4 reviews converged on one headline bug (Character-tab rows never re-read live server truth after their pre-login constructor-word seed) plus overlapping MUST-FIXes. All ten converged/consolidated findings land here: MUST-FIX: - BoolOptionRow.SaveCurrentValue now re-reads its live binding (retail's GetValue()-into-SaveCurrentValue) on every OnShown — panel open, tab switch in, initial activation — instead of trusting the pre-login constructor word it was built with. Reset/tab-switch can now only restore values that were actually live at the last show. LockUI's host.Root.UiLocked one-shot mount seed now also converges on every PlayerDescription via the existing OnCharacterOptionsChanged hook. - Apply/Reset are wired to OptionPage.OnOptionChanged in production (Ghosted when nothing changed, Normal when dirty, run once at bind so both start disabled per retail's PostInit); Defaults stays ungated. - The Combat panel's three LEDs (Repeat Attacks/Auto Target/Keep in View) now read/write the same RuntimeCharacterOptionsState seam the Character tab uses instead of a disconnected client-local GameplaySettings copy — closes the "two writable copies" divergence. The three now-orphaned GameplaySettings fields and RuntimeSettingsController's mirror properties/SetCombatGameplay are deleted outright; the headless host's hardcoded AutoRepeatAttack/AutoTarget now read the live option bit. - RuntimeSettingsController.SetUiLocked's convergence guard now compares against the last value actually applied to the runtime target instead of the persisted GameplaySettings.LockUI snapshot, which could already match a server-derived request without ever having been pushed. SHOULD-FIX: - DisplayTimeStamps now prefixes every chat producer (ChatLog.Append is the one seam all of them funnel through), not just AddText's own callers — heard speech, emotes, Turbine channels, and combat text were previously missed. The prefix format escapes its colons and forces InvariantCulture instead of the culture-dependent TimeSeparator placeholder. - sky.frag now honors uFogParams.w (fog mode) like the mesh/terrain shaders, so Disable Distance Fog stops the sky dome's horizon band from blending toward fog color too. - Corrected the "byte-verified" overclaim on the timestamp format string doc comment (BN-sourced, wire doc U6) and the AP-194 anchor-column class-name typo; the RunAsDefaultMovement doc comments now cite retail's actual acclient.h enumerator name. - Added: DispatcherMovementInputSource's option x modifier truth table (incl. || AutoRunActive with the option off), the per-page Apply/Reset enable-gate tests, a real checkbox.OnClick/ToggleBehavior-driven click test, and hash-pins for the six header string keys. - Gate script step 8 corrected for the logout-flush false-failure (closing the panel before relogging is load-bearing); a new step documents the enable-gate sequence and the Combat-panel/Character-tab cross-check. Register: AP-196 (the Group-C default-source change + GameplaySettings retirement) and AP-197 (the ignored per-character timestamp format override) filed in this commit. Full Release suite: 13,044 passed / 4 skipped / 0 failed (was 13,008/4/0; net +36 tests from new coverage and legitimate assertion updates from the GameplaySettings retirement). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
85afaae5fd
commit
bc43fb1d1d
36 changed files with 923 additions and 220 deletions
|
|
@ -1,3 +1,5 @@
|
|||
using System.Globalization;
|
||||
using System.Threading;
|
||||
using AcDream.Core.Chat;
|
||||
using AcDream.Core.Social;
|
||||
using AcDream.Runtime.Gameplay;
|
||||
|
|
@ -276,10 +278,56 @@ public sealed class RuntimeCommunicationStateTests
|
|||
Assert.NotEqual("Your spell fizzled.", text);
|
||||
// Retail ctor default format "%#H:%M:%S " (non-zero-padded 24h
|
||||
// hour, zero-padded minute:second, trailing space before the
|
||||
// text) — .NET "H:mm:ss " is the exact equivalent.
|
||||
// text) — .NET "H\:mm\:ss " (colons ESCAPED, not the
|
||||
// culture-dependent TimeSeparator placeholder) is the exact
|
||||
// equivalent (SF-1/S4, OP4 review-fix round, 2026-08-11).
|
||||
Assert.Matches(@"^\d{1,2}:\d{2}:\d{2} Your spell fizzled\.$", text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddText_TimestampsTrue_UsesLiteralColons_RegardlessOfCurrentCulture()
|
||||
{
|
||||
// SF-1/S4 (OP4 review-fix round, 2026-08-11): an unescaped "H:mm:ss"
|
||||
// format string renders ':' as CurrentCulture.DateTimeFormat.
|
||||
// TimeSeparator, which is NOT ':' on cultures like fi-FI ("."). The
|
||||
// fix escapes the colons and forces InvariantCulture — prove the
|
||||
// output stays colon-separated even under a culture that would
|
||||
// otherwise substitute a different separator.
|
||||
CultureInfo original = Thread.CurrentThread.CurrentCulture;
|
||||
try
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("fi-FI");
|
||||
using var state = new RuntimeCommunicationState { DisplayTimestampsSource = () => true };
|
||||
|
||||
state.AddText("Your spell fizzled.", RetailLogTextType.Default);
|
||||
|
||||
string text = state.Chat.Snapshot()[0].Text;
|
||||
Assert.Matches(@"^\d{1,2}:\d{2}:\d{2} Your spell fizzled\.$", text);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Thread.CurrentThread.CurrentCulture = original;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplayTimestampsSource_ForwardsToChat_TimestampingEveryProducer_NotJustAddText()
|
||||
{
|
||||
// S1 (OP4 review-fix round, 2026-08-11, blast lens): AddText's own
|
||||
// callers (ServerMessage/WeenieError) were a strict SUBSET of
|
||||
// every chat producer — heard speech, emotes, Turbine channels,
|
||||
// and combat text all bypassed it by calling ChatLog's own OnXxx
|
||||
// methods directly. Setting DisplayTimestampsSource on this class
|
||||
// must timestamp lines that never go through AddText at all.
|
||||
using var state = new RuntimeCommunicationState { DisplayTimestampsSource = () => true };
|
||||
|
||||
state.Chat.OnLocalSpeech("Alice", "hi", 0xAAu, isRanged: false, logTextType: 0x02u);
|
||||
|
||||
string text = state.Chat.Snapshot()[0].Text;
|
||||
Assert.EndsWith("hi", text);
|
||||
Assert.Matches(@"^\d{1,2}:\d{2}:\d{2} hi$", text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddText_TimestampsTrue_NeverAppliedToClientLocalSpewBox()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue