fix(net): Campaign LA LA7a review fixes — AD-97 register row, corrected restore justification

The Opus retail-lens review decoded the PDB-paired binary at
CPlayerSystem::RestoreCharacter@0x0055d760 and refuted the
uninitialized-edx justification: the two extra arguments are real
push imm32 of a constant PStringBase (BN mis-renders them, but they
pack to >=4 bytes each), so retail 0xF7D9 is >=16 bytes where ours
is 8. The guid-only CODE stands (ACE reads only the guid; holtburger
consensus) but it is an adaptation, not a corrected decompile — filed
as divergence register AD-97 and the doc comment now states the true
mechanism.

Also from the review: the 0xF643 conditional-parse doc now names BOTH
ACE flag-only failure branches (NameInUse + Corrupt); CharacterError
0x08 doc corrected (ACE misnames it ServerCrash2 — the port corrects
an ACE misnaming; ACE omits three values, not four); LA7b hazard notes
added (ACE silent no-reply on unknown restore guid; retail SendToLogon
vs SendToControl routing; NumErrors never rendered); two review-nit
tests (flag=0 Undef flag-only, non-Ok body with trailing bytes
ignored).

Core.Net suite: 953 passed / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-14 16:01:52 +02:00
parent 6a32f37589
commit 4338b1c1f3
5 changed files with 100 additions and 34 deletions

View file

@ -43,11 +43,15 @@ namespace AcDream.Core.Net.Messages;
/// It is a strict superset of ACE's <c>ACE.Server.Network.Enum.CharacterError</c>
/// (<c>references/ACE/Source/ACE.Server/Network/Enum/CharacterError.cs</c>):
/// retail additionally names 0x2 (<c>LoggedOn</c>), 0x7 (<c>NoPremade</c>),
/// 0x8 (<c>AccountInUse</c>), and 0x16 (<c>CharacterIsBooted</c>), none of
/// which ACE's server ever sends but all of which retail's client can
/// receive from a genuine retail server — per the project's
/// property-enum-divergence lesson, we port the complete oracle, not just
/// what today's one server implementation emits. ACE's per-value doc
/// and 0x16 (<c>CharacterIsBooted</c>) — three values ACE omits entirely,
/// none of which ACE's server ever sends but all of which retail's client
/// can receive from a genuine retail server. At 0x8 the port additionally
/// CORRECTS an ACE misnaming: ACE defines 0x8 as <c>ServerCrash2</c> with a
/// doc comment duplicating 0x4's <c>ID_CHAR_ERROR_SERVER_CRASH</c> text,
/// but retail's header names 0x8 <c>CHAR_ERROR_ACCOUNT_IN_USE</c> — the
/// header wins. Per the project's property-enum-divergence lesson, we port
/// the complete oracle, not just what today's one server implementation
/// emits. ACE's per-value doc
/// comments (themselves sourced from the client's <c>ID_CHAR_ERROR_*</c>
/// string table) are folded in below where they exist. One retail member,
/// <c>FORCE_charError_32_BIT = 0x7FFFFFFF</c>, is a compiler
@ -111,7 +115,11 @@ public static class CharacterError
/// <summary>0x07 — CHAR_ERROR_NO_PREMADE. Retail-only; no ACE member.</summary>
NoPremade = 0x07,
/// <summary>0x08 — CHAR_ERROR_ACCOUNT_IN_USE. Retail-only; no ACE member.</summary>
/// <summary>
/// 0x08 — CHAR_ERROR_ACCOUNT_IN_USE. ACE misnames this value
/// <c>ServerCrash2</c> (its doc comment duplicates 0x04's text);
/// retail's header is the authority. See the class doc comment.
/// </summary>
AccountInUse = 0x08,
/// <summary>
@ -228,7 +236,8 @@ public static class CharacterError
/// sentinel (the array-bound idiom, one past the last real code) —
/// never sent on the wire as an actual error. Kept for verbatim
/// completeness of the enum range; do not treat a received 0x19
/// as meaningful.
/// as meaningful, and LA7b's error-to-string mapping must not
/// render it as a user-facing message.
/// </summary>
NumErrors = 0x19,
}