Use name cache for combatlog player name, remove SignalEvent probe

Switch from GetObjectPtr→GetUnitName (object manager, not populated
at LoggingCombat time) to RetrieveNPCDataFromCache (name cache,
available early). Remove the SignalEvent probe hook that was only
for discovery.
This commit is contained in:
MarcelineVQ
2026-03-03 15:13:14 -08:00
parent 11030e0566
commit 049f6cd851
2 changed files with 33 additions and 37 deletions
+26 -30
View File
@@ -95,35 +95,32 @@ fn getPlayerGUID() u64 {
return (@as(u64, hi) << 32) | lo;
}
/// Look up a unit name by GUID — two-step approach matching perfboost:
/// 1. GetObjectPtr (0x464870) — __stdcall(u64 guid) → object ptr in EAX
/// 2. CGUnit_C::GetUnitName (0x609210) — __thiscall(ECX=unit, stack: 0) → char*
fn getNameFromGUID(guid: u64) ?[*:0]const u8 {
if (guid == 0) return null;
// Step 1: GUID → object pointer via __stdcall (GUID pushed on stack as 8 bytes)
const guid_lo: u32 = @truncate(guid);
const guid_hi: u32 = @truncate(guid >> 32);
const obj: u32 = asm volatile (
\\ push %[hi]
\\ push %[lo]
\\ call *%[func]
: [ret] "={eax}" (-> u32),
: [lo] "r" (guid_lo),
[hi] "r" (guid_hi),
[func] "r" (@as(u32, o.FN_GET_OBJECT_PTR)),
: .{ .ecx = true, .edx = true, .memory = true, .cc = true });
if (obj == 0) return null;
// Step 2: object pointer → name (__thiscall: ECX=this, push flag=0)
/// Look up a player name from the name cache by GUID.
/// Calls RetrieveNPCDataFromCache — __thiscall(ECX=cache), 6 stack params, RET 0x18.
/// Available before the object manager is populated (unlike GetObjectPtr → GetUnitName).
fn getNameFromGUID(guid_lo: u32, guid_hi: u32) ?[*:0]const u8 {
if (guid_lo == 0 and guid_hi == 0) return null;
var name_buf: [2]u32 = .{ 0, 0 };
const stack_args = [6]u32{
guid_lo,
guid_hi,
@intFromPtr(&name_buf),
0, 0, 0,
};
const result: u32 = asm volatile (
\\ push $0
\\ push 20(%[a])
\\ push 16(%[a])
\\ push 12(%[a])
\\ push 8(%[a])
\\ push 4(%[a])
\\ push (%[a])
\\ call *%[func]
: [ret] "={eax}" (-> u32),
: [_] "{ecx}" (obj),
[func] "r" (@as(u32, o.FN_GET_UNIT_NAME)),
: [_] "{ecx}" (@as(u32, o.NAME_CACHE_OBJ)),
[a] "r" (&stack_args),
[func] "r" (@as(u32, o.FN_NAME_CACHE_LOOKUP)),
: .{ .ecx = true, .edx = true, .memory = true, .cc = true });
return if (result != 0 and result >= 0x10000) @ptrFromInt(result) else null;
return if (result != 0) @ptrFromInt(result) else null;
}
// =============================================================================
@@ -141,12 +138,11 @@ fn maybeWriteSessionMarker() void {
const player_guid = getPlayerGUID();
if (player_guid == 0) return;
const guid_lo: u32 = @truncate(player_guid);
const guid_hi: u32 = @truncate(player_guid >> 32);
const name = getNameFromGUID(player_guid) orelse {
// TODO: If player name is unavailable at this point (e.g.
// LoggingCombat enabled before login), could hook OnWorldUpdate for a
// per-frame retry until name is available.
con.print("[combatlog] session marker: player name not yet available\n");
const name = getNameFromGUID(guid_lo, guid_hi) orelse {
con.print("[combatlog] session marker: player name not in cache yet\n");
return;
};
+7 -7
View File
@@ -32,16 +32,16 @@ pub const FN_WRITE_FMT_LOG_MSG: usize = 0x0065ac20;
pub const FN_ENABLE_CHAT_LOGGING: usize = 0x0049fe50;
// =============================================================================
// Player identity (shared with markers module)
// Player identity
// =============================================================================
/// GetPlayerGUID — __fastcall(), no params, returns EAX(low):EDX(high).
pub const FN_GET_PLAYER_GUID: usize = 0x00468550;
/// GetObjectPtr — __stdcall(u64 guid) → object ptr in EAX.
/// GUID is pushed on the stack as 8 bytes. (perfboost: 0x464870)
pub const FN_GET_OBJECT_PTR: usize = 0x00464870;
/// RetrieveNPCDataFromCache — __thiscall(ECX=cache_obj), 6 stack params, RET 0x18.
/// (guid_low, guid_high, name_buf_ptr, 0, 0, 0) → char* name or NULL in EAX.
/// Resolves player/NPC names from the name cache — available before the object manager.
pub const FN_NAME_CACHE_LOOKUP: usize = 0x0055f080;
/// CGUnit_C::GetUnitName — __thiscall(ECX=unit_ptr, stack: flag=0) → char* in EAX.
/// (perfboost: 0x609210)
pub const FN_GET_UNIT_NAME: usize = 0x00609210;
/// Name cache object — static instance passed as ECX (this) to RetrieveNPCDataFromCache.
pub const NAME_CACHE_OBJ: usize = 0x00c0e228;