Add logging module with auto-prefix, route all output through Logger

Replace console.zig with logging.zig: per-module Logger with auto
[name] prefix, optional file output, and destination routing. Convert
all modules from manual [name] prefixes and global con.print to Logger
instances. Remove redundant "Module loaded" lines. Replace
OutputDebugStringA in outline/tracker with Logger. Add dpslog module
with structured combat log events (SPELL_DMG, PERIODIC, HEAL, MELEE).
Add clickthrough module and bigcursor D3D9 cursor scaling.
This commit is contained in:
MarcelineVQ
2026-03-10 13:26:45 -07:00
parent e403ee18f2
commit 0f14213b0b
21 changed files with 1058 additions and 298 deletions
+34 -4
View File
@@ -22,6 +22,14 @@ pub const module_name: [*:0]const u8 = "clickthrough";
const ADDR_WorldIntersectionTest: usize = 0x480DF0;
const ADDR_GetObjectByGUID: usize = 0x464870;
// Map identification (Map.dbc lookup)
const OBJECT_MANAGER_PTR: usize = 0x00B41414;
const OBJMGR_MAP_ID_OFFSET: usize = 0xCC;
const MAP_DBC_DATA: usize = 0x00C0DAA8;
const MAP_DBC_MAX: usize = 0x00C0DAAC;
const MAP_DBC_MAP_TYPE_OFFSET: usize = 0x08;
const MAP_TYPE_BATTLEGROUND: u32 = 3;
// =============================================================================
// HitTestResult layout
// =============================================================================
@@ -34,6 +42,8 @@ const HIT_RESULT_SIZE: usize = 0x34;
const OBJ_DESCRIPTOR: usize = 0x08;
const OBJ_TYPE_MASK_OFFSET: usize = 0x08; // at *(*(obj+8)+8)
// Object type + descriptor field offsets
// Type masks
const TYPE_UNIT: u32 = 0x09;
const TYPE_PLAYER: u32 = 0x19;
@@ -49,14 +59,34 @@ const OBJ_TYPE: usize = 0x14;
const OBJ_TYPE_UNIT: u32 = 3;
const OBJ_TYPE_GO: u32 = 5;
const DESC_NPC_FLAGS: usize = 0x93 * 4; // UNIT_NPC_FLAGS = OBJECT_END(0x06) + 0x8D = 0x93
const DESC_ENTRY: usize = 0x03 * 4; // OBJECT_FIELD_ENTRY
const ADDR_CallSpellCastHandler: usize = 0x5F8800;
// =============================================================================
// Battleground detection
// =============================================================================
/// Check if the current map is a battleground by reading Map.dbc mapType.
fn isInBattleground() bool {
const obj_mgr = hook.readMem(u32, OBJECT_MANAGER_PTR);
if (obj_mgr == 0) return false;
const map_id = hook.readMem(u32, obj_mgr + OBJMGR_MAP_ID_OFFSET);
const dbc_max = hook.readMem(u32, MAP_DBC_MAX);
if (map_id > dbc_max) return false;
const table_base = hook.readMem(u32, MAP_DBC_DATA);
if (table_base == 0) return false;
const row = hook.readMem(u32, table_base + map_id * 4);
if (row == 0) return false;
const map_type = hook.readMem(u32, row + MAP_DBC_MAP_TYPE_OFFSET);
return map_type == MAP_TYPE_BATTLEGROUND;
}
fn getObjectByGUID(guid_lo: u32, guid_hi: u32) u32 {
if (guid_lo == 0 and guid_hi == 0) return 0;
return hook.call(fn (u32, u32) callconv(hook.cc.stdcall) u32, ADDR_GetObjectByGUID, .{ guid_lo, guid_hi });
}
/// Check if the GUID refers to an interactable GO (mailbox, soulwell, etc.)
/// Check if the GUID refers to an interactable GO.
fn isInteractableGO(guid_lo: u32, guid_hi: u32) bool {
const obj = getObjectByGUID(guid_lo, guid_hi);
if (obj == 0) return false;
@@ -109,7 +139,8 @@ fn worldIntersectDetour(world_frame: u32, ray_start: u32, ray_end: u32, flags: u
// Call original with caller's flags
const hit_type = wit_hook.callOriginal(.{ world_frame, ray_start, ray_end, flags, hit_result });
if (!g_is_hook_owner or hit_result == 0 or hit_type != 2) return hit_type;
// No click-through in battlegrounds
if (!g_is_hook_owner or hit_result == 0 or hit_type != 2 or isInBattleground()) return hit_type;
// hitType 2 = object hit. Check if it's a unit/player.
const buf_lo = hook.readMem(u32, hit_result + HIT_GUID_LO);
@@ -161,7 +192,6 @@ pub fn isActive() bool {
}
pub fn installHooks() void {
logging.print("[clickthrough] Module loaded\n");
const result = mod_mutex.acquire(module_name);
g_mutex = result.handle;
@@ -171,7 +201,7 @@ pub fn installHooks() void {
log = logging.Logger.open(module_name, .both);
_ = wit_hook.attach(ADDR_WorldIntersectionTest, &worldIntersectDetour);
log.fmt("[clickthrough] WorldIntersectionTest hooked at 0x{x}\n", .{ADDR_WorldIntersectionTest});
log.fmt("WorldIntersectionTest hooked at 0x{x}\n", .{ADDR_WorldIntersectionTest});
}
pub fn removeHooks() void {