fix(chat): CH1 review fixes — sbb-idiom channel catch-all, command-output typing
Applies the Opus review findings on CH1 (172c6f9a), the exact retail chat
color table. Two blockers plus should-fixes/nits, one commit:
BLOCKER 1 — LegacyChannelChatType.Resolve's channel-bit table was wrong.
Binary Ninja renders retail's `neg esi; sbb esi, esi` idiom (a branchless
select between Channel 0x08 and Channel_Send 0x09) as the trivial pseudo-C
`esi - esi` (always 0), hiding the real values. Corrected by decoding the
raw bytes at the PDB-paired binary: HEAR sbb site VA 0x00570F0A (mask -6 ->
0x08), SEND sbb site VA 0x00570D4F (mask -5 -> 0x09). The generic
admin/audit/sentinel catch-all is Channel/Channel_Send, NOT Abuse (0x0E) —
Abuse is retail's ONLY 0x0E producer (bit 0x0001). The unnamed
FellowBroadcast bit (0x4000000) is hear=Channel(0x08)/send=Fellowship(0x13),
not a flat 0x13. ACE's PDB-sourced Channel enum corroborates. Introduces
`RetailLogTextType`, the 34-value named enum for the wire LogTextType space
(values only, no color — Core stays presentation-free).
BLOCKER 2 — three ChatLog.OnSystemMessage sinks (ChatVM.ShowSystemMessage,
LiveSessionRuntimeFactory's ShowSystemMessage delegate,
HeadlessGameplayOperations.DisplayMessage) were typing ALL
ClientCommandController output 0x1A (bright red), including informational
command output (@version, /loc, friends list, usage lines). Retail types
the great majority of that output 0x00 Default (green) and reserves 0x1A
for genuine refusals/errors. Reverted to 0x00 with a comment noting the
refusal-vs-info split lands with CH2's SpewBox producer rewiring. The five
App composition sites that pass 0x1A for actual refusal text
(InteractionRetainedUiComposition, SessionPlayerComposition) were already
correct and are untouched (aside from converting the literal to the new
enum).
Also: AP-176 divergence-register row for OnWeenieError/OnCombatLine's
single-type approximation of retail's per-code/per-message dispatch; a
carry-forward test for the out-of-range LogTextType color fallback in
ChatWindowController; decomp-confirmed anchors replacing ACE-inferred
citations in CombatChatTranslator and ChatLog.OnPlayerKilled; required
(non-optional) logTextType parameters on OnLocalSpeech/OnTellReceived/
OnCombatLine/OnSelfSent since no production caller relied on a default;
LegacyChannelChatType.Resolve's parameter renamed channelBit -> channelId
with a doc note on multi-bit ids; corrections to the color-table research
doc's §3.3 wire tables; and issue #359 for the pre-existing (not
CH1-introduced) 0x019E PlayerKilled participant-suppression gap retail has
and acdream lacks.
dotnet build clean; full Release suite 11,835 passed / 4 skipped / 0 failed
(11,839 total), up from the CH1 baseline of 11,833/4/0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e306c979ae
commit
34d8a3c0e7
31 changed files with 481 additions and 213 deletions
|
|
@ -98,10 +98,11 @@ public sealed class ChatLog
|
|||
/// (<c>speech.ChatType</c>) — passed through VERBATIM, with zero
|
||||
/// remapping, matching retail's <c>Handle_Communication__HearSpeech
|
||||
/// @0x005712A0</c> (the raw <c>arg5</c> feeds <c>AddTextToScroll</c>
|
||||
/// directly). Defaults to <c>0x02</c> (Speech) for callers that
|
||||
/// directly). Required — no production caller relies on a default;
|
||||
/// retail's normal value is <c>0x02</c> (Speech) for callers that
|
||||
/// don't have a wire value in hand.
|
||||
/// </param>
|
||||
public void OnLocalSpeech(string sender, string text, uint senderGuid, bool isRanged, uint logTextType = 0x02u)
|
||||
public void OnLocalSpeech(string sender, string text, uint senderGuid, bool isRanged, uint logTextType)
|
||||
{
|
||||
// Phase J: ACE's HandleActionTalk broadcasts a HearSpeech echo
|
||||
// back to the sender too. Detect own echo by guid match and
|
||||
|
|
@ -134,7 +135,7 @@ public sealed class ChatLog
|
|||
// Retail hard-codes Emote (0x0C) for every HearEmote line —
|
||||
// ClientCommunicationSystem::HearEmote @0x0057CBE0, the
|
||||
// literal constant at 0x0057CF94. Not a wire value.
|
||||
LogTextType = 0x0Cu,
|
||||
LogTextType = (uint)RetailLogTextType.Emote,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +151,7 @@ public sealed class ChatLog
|
|||
{
|
||||
// HearSoulEmote tail-calls HearEmote @0x0057D096 — same
|
||||
// hard-coded 0x0C.
|
||||
LogTextType = 0x0Cu,
|
||||
LogTextType = (uint)RetailLogTextType.Emote,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -171,14 +172,13 @@ public sealed class ChatLog
|
|||
SenderGuid: victimGuid,
|
||||
ChannelId: killerGuid)
|
||||
{
|
||||
// Inferred by analogy from the sibling GameEvents this opcode
|
||||
// shares a dispatch pattern with: VictimNotification (0x01AC)
|
||||
// and KillerNotification (0x01AD) both route through the SAME
|
||||
// retail handler, ClientCombatSystem::HandleKillerNotification
|
||||
// Event @0x0056C410 (cases 0xa/0xb of the combat-envelope
|
||||
// switch, pc:359548-359559), which calls
|
||||
// AddTextToScroll(..., 0, 1, 0) — type 0x00 Default. No direct
|
||||
// decomp citation was traced for 0x019E PlayerKilled itself.
|
||||
// Direct anchor (corrected 2026-08-09, Opus review of
|
||||
// 172c6f9a — replaces the earlier sibling-opcode analogy):
|
||||
// opcode 0x019E dispatches via UIQueueManager::ProcessNet
|
||||
// BlobData's byte table @0x55CB07 -> case 7 ->
|
||||
// ClientCombatSystem::HandlePlayerDeathEvent @0x0056C320 ->
|
||||
// AddTextToScroll(..., 0, 1, 0) @0x0056C3D8. Type 0x00 Default
|
||||
// confirmed.
|
||||
LogTextType = 0x00u,
|
||||
});
|
||||
}
|
||||
|
|
@ -216,8 +216,9 @@ public sealed class ChatLog
|
|||
// Retail's HandleFailureEvent @0x00571990 dispatches per ERROR
|
||||
// CODE across an ~87-case switch, mostly AddTextToScroll(...,
|
||||
// 0, ...) with a scattered handful at 0x1a (client-local red).
|
||||
// A full per-code port is future work; 0x00 (Default) matches
|
||||
// the switch's majority behavior and is the safe baseline.
|
||||
// A full per-code port is future work (register row AP-176);
|
||||
// 0x00 (Default) matches the switch's majority behavior and is
|
||||
// the safe baseline.
|
||||
LogTextType = 0x00u,
|
||||
});
|
||||
}
|
||||
|
|
@ -262,11 +263,11 @@ public sealed class ChatLog
|
|||
/// <summary>GameEvent Tell (0x02BD) — whisper received.</summary>
|
||||
/// <param name="logTextType">
|
||||
/// The wire <c>chatType</c> from the Tell GameEvent payload
|
||||
/// (<c>GameEvents.Tell.ChatType</c>) — retail's normal value is
|
||||
/// <c>0x03</c> (Tell), which is also this parameter's default for
|
||||
/// callers without a wire value in hand.
|
||||
/// (<c>GameEvents.Tell.ChatType</c>) — required; no production caller
|
||||
/// relies on a default. Retail's normal value is <c>0x03</c> (Tell)
|
||||
/// for callers without a wire value in hand.
|
||||
/// </param>
|
||||
public void OnTellReceived(string sender, string text, uint senderGuid, uint logTextType = 0x03u)
|
||||
public void OnTellReceived(string sender, string text, uint senderGuid, uint logTextType)
|
||||
{
|
||||
Append(new ChatEntry(
|
||||
Kind: ChatKind.Tell,
|
||||
|
|
@ -352,19 +353,26 @@ public sealed class ChatLog
|
|||
/// <c>warning().combat()</c> / <c>error().combat()</c> tag flow at
|
||||
/// <c>chat.rs:221-308</c>.
|
||||
/// </summary>
|
||||
/// <param name="text">The pre-formatted combat line text.</param>
|
||||
/// <param name="logTextType">
|
||||
/// The retail <c>LogTextType</c> for this combat line. Callers should
|
||||
/// pass one of the ACE-cited combat types (<c>0x16</c> Combat_Self for
|
||||
/// lines about the local player's OWN offensive action, <c>0x15</c>
|
||||
/// Combat_Enemy for lines about an enemy's action against the local
|
||||
/// player — see <see cref="CombatChatTranslator"/>) or <c>0x00</c>
|
||||
/// Default for retail's decompiled kill/death-notification color
|
||||
/// (<c>HandleKillerNotificationEvent @0x0056C410</c>). Defaults to
|
||||
/// <c>0x06</c> (the generic Combat slot) for callers with no more
|
||||
/// specific classification in hand.
|
||||
/// The retail <c>LogTextType</c> for this combat line — required; no
|
||||
/// production caller relies on a default. Callers should pass one of
|
||||
/// the ACE-cited combat types (<c>0x16</c> Combat_Self for lines about
|
||||
/// the local player's OWN offensive action, <c>0x15</c> Combat_Enemy
|
||||
/// for lines about an enemy's action against the local player — see
|
||||
/// <see cref="CombatChatTranslator"/>), <c>0x00</c> Default for
|
||||
/// retail's decompiled kill/death-notification color
|
||||
/// (<c>HandleKillerNotificationEvent @0x0056C410</c>), or <c>0x06</c>
|
||||
/// (the generic Combat slot) when no more specific classification is
|
||||
/// in hand — the generic-slot choice is a registered approximation of
|
||||
/// retail's per-message dispatch (register row AP-176).
|
||||
/// </param>
|
||||
/// <param name="kind">
|
||||
/// Severity bucket for panel coloring; defaults to
|
||||
/// <see cref="Combat.CombatLineKind.Info"/>.
|
||||
/// </param>
|
||||
public void OnCombatLine(
|
||||
string text, Combat.CombatLineKind kind = Combat.CombatLineKind.Info, uint logTextType = 0x06u)
|
||||
string text, uint logTextType, Combat.CombatLineKind kind = Combat.CombatLineKind.Info)
|
||||
{
|
||||
Append(new ChatEntry(
|
||||
Kind: ChatKind.Combat,
|
||||
|
|
@ -400,17 +408,16 @@ public sealed class ChatLog
|
|||
/// (a real incoming Tell carries the sender's player guid).
|
||||
/// </remarks>
|
||||
/// <param name="logTextType">
|
||||
/// The retail <c>LogTextType</c> for this self-sent line. When
|
||||
/// <see langword="null"/>, defaults to <c>0x04</c> Speech_Direct_Send
|
||||
/// for Tell (retail's own-echo "You tell ..." type — cross-check
|
||||
/// ACE's <c>ChatMessageType.OutgoingTell</c> comment "You tell ...") or
|
||||
/// <c>0x0B</c> Social_Send for Channel (the simplified own-send default
|
||||
/// research doc §3.3 records; the LiveSessionCommandRouter production
|
||||
/// caller overrides this with the precise per-channel-bit value from
|
||||
/// <see cref="LegacyChannelChatType.Resolve"/> instead of relying on
|
||||
/// this fallback).
|
||||
/// The retail <c>LogTextType</c> for this self-sent line — required;
|
||||
/// no production caller relies on a default (the old null-fallback
|
||||
/// ternary is retired). Pass <c>0x04</c> Speech_Direct_Send for Tell
|
||||
/// (retail's own-echo "You tell ..." type — cross-check ACE's
|
||||
/// <c>ChatMessageType.OutgoingTell</c> comment "You tell ...") or, for
|
||||
/// Channel, the precise per-channel-bit value from
|
||||
/// <see cref="LegacyChannelChatType.Resolve"/> — the
|
||||
/// LiveSessionCommandRouter production caller does exactly this.
|
||||
/// </param>
|
||||
public void OnSelfSent(ChatKind kind, string text, string targetOrChannel = "", uint? logTextType = null)
|
||||
public void OnSelfSent(ChatKind kind, string text, uint logTextType, string targetOrChannel = "")
|
||||
{
|
||||
Append(new ChatEntry(
|
||||
Kind: kind,
|
||||
|
|
@ -425,7 +432,7 @@ public sealed class ChatLog
|
|||
ChannelId: 0)
|
||||
{
|
||||
ChannelName = kind == ChatKind.Channel ? targetOrChannel : "",
|
||||
LogTextType = logTextType ?? (kind == ChatKind.Tell ? 0x04u : 0x0Bu),
|
||||
LogTextType = logTextType,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue