From 00749d574577ee61321fdfab78c97e66a64c2447 Mon Sep 17 00:00:00 2001 From: MarcelineVQ Date: Wed, 4 Mar 2026 15:14:04 -0800 Subject: [PATCH] Add bigcursor module stub, rename combatlog to logsessions, bump session timer to 60min - New bigcursor module skeleton with build integration and mutex - Rename combatlog module to logsessions (directory, files, build options, imports, console prefixes, mutex name, DLL variant, docs) - Increase log session continuation threshold from 30 to 60 minutes - Update DLL_README log sessions section --- DLL_README.md | 21 +++++--- RELEASING.md | 20 +++++++- build.zig | 34 +++++++------ src/bigcursor/bigcursor.zig | 51 +++++++++++++++++++ src/{combatlog => logsessions}/RESEARCH.md | 0 .../logsessions.zig} | 50 +++++++++--------- src/{combatlog => logsessions}/offsets.zig | 2 +- src/main.zig | 17 ++++--- src/transmogfix/transmogfix.zig | 10 ++-- 9 files changed, 141 insertions(+), 64 deletions(-) create mode 100644 src/bigcursor/bigcursor.zig rename src/{combatlog => logsessions}/RESEARCH.md (100%) rename src/{combatlog/combatlog.zig => logsessions/logsessions.zig} (91%) rename src/{combatlog => logsessions}/offsets.zig (98%) diff --git a/DLL_README.md b/DLL_README.md index 232482c..fe35ca0 100644 --- a/DLL_README.md +++ b/DLL_README.md @@ -105,9 +105,9 @@ No configuration needed, install and forget. --- -### Combat Log Sessions +### Log Sessions -Organizes combat, raw combat, and chat logs into per-character directories with timestamped filenames: +Organizes the combat, raw combat, and chat logs into per-character directories with timestamped filenames: ``` Logs\\\WoWChatLog_YYYYMMDD_HHMMSS.txt @@ -115,11 +115,8 @@ Logs\\\WoWCombatLog_YYYYMMDD_HHMMSS.txt Logs\\\WoWRawCombatLog_YYYYMMDD_HHMMSS.txt (superwow only) ``` -Each new game session begins with a marker line (`COMBATLOG_SESSION` or `CHAT_SESSION`) identifying the character and realm. If a log file for the same character was written to within the last 30 minutes, the session continues into the same file instead of creating a new one. - -Like any normal log use, logging must be enabled in-game for files to appear: -- **Combat log**: `/combatlog` in chat, or `LoggingCombat(1)` from a macro/addon -- **Chat log**: `/chatlog` in chat, or `LoggingChat(1)` from a macro/addon +Every character login begins with a marker line (`COMBATLOG_SESSION` or `CHAT_SESSION`) identifying the character and realm. +If a log file for the same character was written to within the last 60 minutes, the same logfile will be used instead of creating a new one. Lua API for addon developers: @@ -128,7 +125,7 @@ Lua API for addon developers: No other configuration needed, install and forget. -**DLL:** `combatlog.dll` +**DLL:** `logsessions.dll` --- @@ -140,6 +137,14 @@ Fixes duplicate floating heal numbers caused by SuperWoW 1.5. Only relevant if y --- +### Big Cursor + +Increases the hardware cursor render size for improved visibility. No configuration needed, install and forget. + +**DLL:** `bigcursor.dll` + +--- + ## Why No Source Code? This project is distributed as pre-built DLLs only. The source code is not and will not be made publicly available. diff --git a/RELEASING.md b/RELEASING.md index 25b4495..2d995f4 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -57,7 +57,7 @@ want: # Example: only transmogfix + customassets + healtextfix zig build -Doptimize=ReleaseSmall \ -Dscreenshot=false -Dinteract=false -Doutline=false \ - -Dworldmarkers=false -Dframecrash=false -Dcombatlog=false \ + -Dworldmarkers=false -Dframecrash=false -Dlogsessions=false \ -Dminimapicons=false \ -Dtransmogfix=true -Dcustomassets=true -Dhealtextfix=true ``` @@ -100,7 +100,8 @@ git push origin main ## 3. Write the release notes -Use this template — fill in the sections that apply, delete the rest: +Use this template - fill in the sections that apply, delete the rest. +Use `-` (not em dash) anywhere a dash would be used: ```markdown ## What's New @@ -143,8 +144,23 @@ tea release create \ --asset zig-out/variants/healtextfix.dll ``` +## 5. Hide source archives + +Codeberg attaches empty source tar/zip by default. Hide them via API: + +```sh +curl -s -X PATCH \ + -H "Authorization: token " \ + -H "Content-Type: application/json" \ + -d '{"hide_archive_links":true}' \ + "https://codeberg.org/api/v1/repos/MarcelineVQ/WeirdUtils/releases/" +``` + +Get the release ID from `tea release list --repo MarcelineVQ/WeirdUtils --output json`. + ## Checklist - [ ] Built with `ReleaseSmall` (both default and `all-variants`) - [ ] Remote README updated (if `DLL_README.md` changed) - [ ] Release created and DLLs uploaded via `tea` +- [ ] Source archives hidden diff --git a/build.zig b/build.zig index 4be757d..d8dcdaf 100644 --- a/build.zig +++ b/build.zig @@ -14,11 +14,12 @@ pub fn build(b: *std.Build) void { const enable_outline = b.option(bool, "outline", "Enable outline module") orelse true; const enable_worldmarkers = b.option(bool, "worldmarkers", "Enable world markers module") orelse true; const enable_framecrash = b.option(bool, "framecrash", "Enable framecrash fix") orelse false; - const enable_combatlog = b.option(bool, "combatlog", "Enable combat log freshness") orelse true; + const enable_logsessions = b.option(bool, "logsessions", "Enable log session rotation") orelse true; const enable_minimapicons = b.option(bool, "minimapicons", "Enable custom minimap icons") orelse true; const enable_transmogfix = b.option(bool, "transmogfix", "Enable transmog update coalescing") orelse true; const enable_customassets = b.option(bool, "customassets", "Enable loose file loading & permissive patch glob") orelse true; const enable_healtextfix = b.option(bool, "healtextfix", "Enable SuperWoW heal text fix") orelse true; + const enable_bigcursor = b.option(bool, "bigcursor", "Enable big cursor module") orelse true; // Create build options module const build_options = b.addOptions(); @@ -27,11 +28,12 @@ pub fn build(b: *std.Build) void { build_options.addOption(bool, "enable_outline", enable_outline); build_options.addOption(bool, "enable_worldmarkers", enable_worldmarkers); build_options.addOption(bool, "enable_framecrash", enable_framecrash); - build_options.addOption(bool, "enable_combatlog", enable_combatlog); + build_options.addOption(bool, "enable_logsessions", enable_logsessions); build_options.addOption(bool, "enable_minimapicons", enable_minimapicons); build_options.addOption(bool, "enable_transmogfix", enable_transmogfix); build_options.addOption(bool, "enable_customassets", enable_customassets); build_options.addOption(bool, "enable_healtextfix", enable_healtextfix); + build_options.addOption(bool, "enable_bigcursor", enable_bigcursor); const build_options_module = build_options.createModule(); const zhook_dep = b.dependency("zhook", .{ @@ -60,19 +62,20 @@ pub fn build(b: *std.Build) void { const build_all_step = b.step("all-variants", "Build all DLL variants"); // Helper to create a single-module build - const Variant = struct { name: []const u8, screenshot: bool, interact: bool, outline: bool, worldmarkers: bool, framecrash: bool, combatlog: bool, minimapicons: bool, transmogfix: bool, customassets: bool, healtextfix: bool }; + const Variant = struct { name: []const u8, screenshot: bool, interact: bool, outline: bool, worldmarkers: bool, framecrash: bool, logsessions: bool, minimapicons: bool, transmogfix: bool, customassets: bool, healtextfix: bool, bigcursor: bool }; inline for (&[_]Variant{ - .{ .name = "full", .screenshot = true, .interact = true, .outline = true, .worldmarkers = true, .framecrash = true, .combatlog = true, .minimapicons = true, .transmogfix = true, .customassets = true, .healtextfix = true }, - .{ .name = "screenshot", .screenshot = true, .interact = false, .outline = false, .worldmarkers = false, .framecrash = true, .combatlog = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "interact", .screenshot = false, .interact = true, .outline = false, .worldmarkers = false, .framecrash = true, .combatlog = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "outline", .screenshot = false, .interact = false, .outline = true, .worldmarkers = false, .framecrash = true, .combatlog = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "worldmarkers", .screenshot = false, .interact = false, .outline = false, .worldmarkers = true, .framecrash = true, .combatlog = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "framecrash", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = true, .combatlog = false, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "combatlog", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .combatlog = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "minimapicons", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = true, .combatlog = false, .minimapicons = true, .transmogfix = false, .customassets = false, .healtextfix = false }, - .{ .name = "transmogfix", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .combatlog = false, .minimapicons = false, .transmogfix = true, .customassets = false, .healtextfix = false }, - .{ .name = "customassets", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .combatlog = false, .minimapicons = false, .transmogfix = false, .customassets = true, .healtextfix = false }, - .{ .name = "healtextfix", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .combatlog = false, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = true }, + .{ .name = "full", .screenshot = true, .interact = true, .outline = true, .worldmarkers = true, .framecrash = true, .logsessions = true, .minimapicons = true, .transmogfix = true, .customassets = true, .healtextfix = true, .bigcursor = true }, + .{ .name = "screenshot", .screenshot = true, .interact = false, .outline = false, .worldmarkers = false, .framecrash = true, .logsessions = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "interact", .screenshot = false, .interact = true, .outline = false, .worldmarkers = false, .framecrash = true, .logsessions = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "outline", .screenshot = false, .interact = false, .outline = true, .worldmarkers = false, .framecrash = true, .logsessions = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "worldmarkers", .screenshot = false, .interact = false, .outline = false, .worldmarkers = true, .framecrash = true, .logsessions = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "framecrash", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = true, .logsessions = false, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "logsessions", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .logsessions = true, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "minimapicons", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = true, .logsessions = false, .minimapicons = true, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "transmogfix", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .logsessions = false, .minimapicons = false, .transmogfix = true, .customassets = false, .healtextfix = false, .bigcursor = false }, + .{ .name = "customassets", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .logsessions = false, .minimapicons = false, .transmogfix = false, .customassets = true, .healtextfix = false, .bigcursor = false }, + .{ .name = "healtextfix", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .logsessions = false, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = true, .bigcursor = false }, + .{ .name = "bigcursor", .screenshot = false, .interact = false, .outline = false, .worldmarkers = false, .framecrash = false, .logsessions = false, .minimapicons = false, .transmogfix = false, .customassets = false, .healtextfix = false, .bigcursor = true }, }) |variant| { const opts = b.addOptions(); opts.addOption(bool, "enable_screenshot", variant.screenshot); @@ -80,11 +83,12 @@ pub fn build(b: *std.Build) void { opts.addOption(bool, "enable_outline", variant.outline); opts.addOption(bool, "enable_worldmarkers", variant.worldmarkers); opts.addOption(bool, "enable_framecrash", variant.framecrash); - opts.addOption(bool, "enable_combatlog", variant.combatlog); + opts.addOption(bool, "enable_logsessions", variant.logsessions); opts.addOption(bool, "enable_minimapicons", variant.minimapicons); opts.addOption(bool, "enable_transmogfix", variant.transmogfix); opts.addOption(bool, "enable_customassets", variant.customassets); opts.addOption(bool, "enable_healtextfix", variant.healtextfix); + opts.addOption(bool, "enable_bigcursor", variant.bigcursor); const variant_lib = b.addLibrary(.{ .name = variant.name, diff --git a/src/bigcursor/bigcursor.zig b/src/bigcursor/bigcursor.zig new file mode 100644 index 0000000..7d7e690 --- /dev/null +++ b/src/bigcursor/bigcursor.zig @@ -0,0 +1,51 @@ +//! Big cursor module. +//! +//! Increases the hardware cursor render size for improved visibility. +//! +//! TODO: Research cursor rendering pipeline and hook implementation. + +const std = @import("std"); +const con = @import("../console.zig"); + +const WINAPI = std.builtin.CallingConvention.winapi; +extern "kernel32" fn CreateMutexA(lpMutexAttributes: ?*anyopaque, bInitialOwner: i32, lpName: [*:0]const u8) callconv(WINAPI) ?*anyopaque; +extern "kernel32" fn ReleaseMutex(hMutex: *anyopaque) callconv(WINAPI) i32; +extern "kernel32" fn CloseHandle(hObject: *anyopaque) callconv(WINAPI) i32; +extern "kernel32" fn GetLastError() callconv(WINAPI) u32; +extern "kernel32" fn GetCurrentProcessId() callconv(WINAPI) u32; +const ERROR_ALREADY_EXISTS: u32 = 183; + +var g_mutex: ?*anyopaque = null; +var g_is_hook_owner: bool = false; + +pub fn installHooks() void { + con.print("[bigcursor] Module loaded (stub)\n"); + + // Multi-DLL safety: only one instance per process should hook + var mutex_name_buf: [64]u8 = undefined; + const mutex_name = std.fmt.bufPrint(&mutex_name_buf, "Local\\WeirdUtils_BigcursorHook_{d}", .{GetCurrentProcessId()}) catch return; + mutex_name_buf[mutex_name.len] = 0; + + g_mutex = CreateMutexA(null, 1, @ptrCast(mutex_name_buf[0..mutex_name.len :0])); + if (g_mutex == null) return; + + if (GetLastError() == ERROR_ALREADY_EXISTS) { + _ = CloseHandle(g_mutex.?); + g_mutex = null; + g_is_hook_owner = false; + con.print("[bigcursor] Another DLL owns hooks (mutex taken), skipping\n"); + return; + } + g_is_hook_owner = true; +} + +pub fn removeHooks() void { + if (g_is_hook_owner) { + if (g_mutex) |m| { + _ = ReleaseMutex(m); + _ = CloseHandle(m); + g_mutex = null; + } + } + g_is_hook_owner = false; +} diff --git a/src/combatlog/RESEARCH.md b/src/logsessions/RESEARCH.md similarity index 100% rename from src/combatlog/RESEARCH.md rename to src/logsessions/RESEARCH.md diff --git a/src/combatlog/combatlog.zig b/src/logsessions/logsessions.zig similarity index 91% rename from src/combatlog/combatlog.zig rename to src/logsessions/logsessions.zig index 911dcce..a955178 100644 --- a/src/combatlog/combatlog.zig +++ b/src/logsessions/logsessions.zig @@ -1,4 +1,4 @@ -//! Combat log session rotation with per-character directories. +//! Log session rotation with per-character directories. //! //! Redirects combat log, raw combat log, and chat log to per-character //! directories: `Logs\\\__.txt`. @@ -6,7 +6,7 @@ //! Features: //! - Early path setup: hooks HandleCharacterSelection to resolve character/realm //! from the select screen data before world loading begins -//! - Session continuation: reuses files modified < 30 min ago +//! - Session continuation: reuses files modified < 60 min ago //! - Session marker: writes `COMBATLOG_SESSION: ` on first combat write //! //! All DLL-side — no Lua addon needed. @@ -184,7 +184,7 @@ fn setupSessionDir(realm: []const u8, char_name: []const u8) bool { g_dir_path[dir_path.len] = 0; g_dir_path_len = dir_path.len; - con.fmt("[combatlog] dir: {s}\n", .{g_dir_path[0..g_dir_path_len]}); + con.fmt("[logsessions] dir: {s}\n", .{g_dir_path[0..g_dir_path_len]}); return true; } @@ -193,7 +193,7 @@ fn setupSessionDir(realm: []const u8, char_name: []const u8) bool { // ============================================================================= /// Scan directory for files matching `_*.txt`, return the newest if -/// modified within 30 minutes. Writes full path into result_buf, returns length. +/// modified within 60 minutes. Writes full path into result_buf, returns length. fn findRecentFile(prefix: []const u8, result_buf: *[260]u8) ?usize { if (g_dir_path_len == 0) return null; @@ -235,7 +235,7 @@ fn findRecentFile(prefix: []const u8, result_buf: *[260]u8) ?usize { var current_ft: FILETIME = undefined; GetSystemTimeAsFileTime(¤t_ft); const current: u64 = @bitCast(current_ft); - const threshold: u64 = 30 * 60 * 10_000_000; // 30 minutes + const threshold: u64 = 60 * 60 * 10_000_000; // 60 minutes if (current > newest_time and (current - newest_time) < threshold) { // Build full path: dir + filename @@ -252,9 +252,9 @@ fn findRecentFile(prefix: []const u8, result_buf: *[260]u8) ?usize { /// Resolve a log file path: reuse recent file or generate new timestamped name. fn resolveLogPath(prefix: []const u8, result_buf: *[260]u8) usize { - // Try to reuse a recent file (modified < 30 min ago) + // Try to reuse a recent file (modified < 60 min ago) if (findRecentFile(prefix, result_buf)) |len| { - con.fmt("[combatlog] reusing: {s}\n", .{result_buf[0..len]}); + con.fmt("[logsessions] reusing: {s}\n", .{result_buf[0..len]}); return len; } @@ -273,7 +273,7 @@ fn resolveLogPath(prefix: []const u8, result_buf: *[260]u8) usize { st.wSecond, }) catch return 0; result_buf[path.len] = 0; - con.fmt("[combatlog] new: {s}\n", .{path}); + con.fmt("[logsessions] new: {s}\n", .{path}); return path.len; } @@ -288,7 +288,7 @@ fn configureSession(char_span: []const u8, realm_span: []const u8) void { g_session_char_len = sanitizeName(char_span, &g_session_char); g_session_realm_len = sanitizeName(realm_span, &g_session_realm); - con.fmt("[combatlog] session: {s} on {s}\n", .{ + con.fmt("[logsessions] session: {s} on {s}\n", .{ g_session_char[0..g_session_char_len], g_session_realm[0..g_session_realm_len], }); @@ -298,7 +298,7 @@ fn configureSession(char_span: []const u8, realm_span: []const u8) void { g_session_realm[0..g_session_realm_len], g_session_char[0..g_session_char_len], )) { - con.print("[combatlog] setup: failed to create directories\n"); + con.print("[logsessions] setup: failed to create directories\n"); return; } @@ -342,7 +342,7 @@ fn enterWorldDetour() callconv(sc) void { if (char_name != null and realm_name != null) { configureSession(std.mem.span(char_name.?), std.mem.span(realm_name.?)); } else { - con.print("[combatlog] enter world: char/realm not available\n"); + con.print("[logsessions] enter world: char/realm not available\n"); } } @@ -376,18 +376,18 @@ fn initLogDetour(file_path: u32, flags: u32, handle_out: u32) callconv(sc) u32 { // Redirect based on path suffix if (g_combat_path_len > 0 and std.mem.endsWith(u8, path_span, "WoWCombatLog.txt")) { - con.fmt("[combatlog] redirect: {s} -> {s}\n", .{ path_span, g_combat_path[0..g_combat_path_len] }); + con.fmt("[logsessions] redirect: {s} -> {s}\n", .{ path_span, g_combat_path[0..g_combat_path_len] }); return init_log_hook.callOriginal(.{ @intFromPtr(&g_combat_path), flags, handle_out }); } if (g_raw_combat_path_len > 0 and std.mem.endsWith(u8, path_span, "WoWRawCombatLog.txt")) { g_raw_combat_handle_addr = handle_out; // capture SuperWoW's handle address - con.fmt("[combatlog] redirect: {s} -> {s}\n", .{ path_span, g_raw_combat_path[0..g_raw_combat_path_len] }); + con.fmt("[logsessions] redirect: {s} -> {s}\n", .{ path_span, g_raw_combat_path[0..g_raw_combat_path_len] }); return init_log_hook.callOriginal(.{ @intFromPtr(&g_raw_combat_path), flags, handle_out }); } if (g_chat_path_len > 0 and std.mem.endsWith(u8, path_span, "WoWChatLog.txt")) { - con.fmt("[combatlog] redirect: {s} -> {s}\n", .{ path_span, g_chat_path[0..g_chat_path_len] }); + con.fmt("[logsessions] redirect: {s} -> {s}\n", .{ path_span, g_chat_path[0..g_chat_path_len] }); return init_log_hook.callOriginal(.{ @intFromPtr(&g_chat_path), flags, handle_out }); } @@ -448,7 +448,7 @@ fn writeSessionMarker(handle: u32, fmt_str: [*:0]const u8) void { @intFromPtr(&marker_ptr), }); - con.fmt("[combatlog] marker: {s}\n", .{marker_str}); + con.fmt("[logsessions] marker: {s}\n", .{marker_str}); } // ============================================================================= @@ -459,7 +459,7 @@ fn writeSessionMarker(handle: u32, fmt_str: [*:0]const u8) void { /// Called from logoutDetour/shutdownDetour in main.zig. pub fn onShutdown() void { if (g_paths_configured) { - con.print("[combatlog] session reset\n"); + con.print("[logsessions] session reset\n"); } g_paths_configured = false; g_combat_marker_written = false; @@ -505,11 +505,11 @@ pub fn luaGetChatLogPath(L: lua.State) callconv(.c) u32 { // ============================================================================= pub fn installHooks() void { - con.print("[combatlog] Module loaded\n"); + con.print("[logsessions] Module loaded\n"); // Multi-DLL safety: only one instance per process should hook var mutex_name_buf: [64]u8 = undefined; - const mutex_name = std.fmt.bufPrint(&mutex_name_buf, "Local\\WeirdUtils_CombatlogHook_{d}", .{GetCurrentProcessId()}) catch return; + const mutex_name = std.fmt.bufPrint(&mutex_name_buf, "Local\\WeirdUtils_LogSessionsHook_{d}", .{GetCurrentProcessId()}) catch return; mutex_name_buf[mutex_name.len] = 0; g_mutex = CreateMutexA(null, 1, @ptrCast(mutex_name_buf[0..mutex_name.len :0])); @@ -519,7 +519,7 @@ pub fn installHooks() void { _ = CloseHandle(g_mutex.?); g_mutex = null; g_is_hook_owner = false; - con.print("[combatlog] Another DLL owns hooks (mutex taken), skipping\n"); + con.print("[logsessions] Another DLL owns hooks (mutex taken), skipping\n"); return; } g_is_hook_owner = true; @@ -527,21 +527,21 @@ pub fn installHooks() void { // Hook HandleCharacterSelection — sets up paths when player clicks Enter World, // before the world loading sequence calls InitializeLogBuffer. if (enter_world_hook.attach(o.FN_HANDLE_CHAR_SELECT, &enterWorldDetour) != .ok) { - con.print("[combatlog] FAILED to hook HandleCharacterSelection!\n"); + con.print("[logsessions] FAILED to hook HandleCharacterSelection!\n"); } else { - con.print("[combatlog] hooked HandleCharacterSelection OK\n"); + con.print("[logsessions] hooked HandleCharacterSelection OK\n"); } if (init_log_hook.attach(o.FN_INIT_LOG_BUFFER, &initLogDetour) != .ok) { - con.print("[combatlog] FAILED to hook InitializeLogBuffer!\n"); + con.print("[logsessions] FAILED to hook InitializeLogBuffer!\n"); } else { - con.print("[combatlog] hooked InitializeLogBuffer OK\n"); + con.print("[logsessions] hooked InitializeLogBuffer OK\n"); } if (write_log_hook.attach(o.FN_WRITE_FMT_LOG_MSG, &writeLogDetour) != .ok) { - con.print("[combatlog] FAILED to hook WriteFormattedLogMessage!\n"); + con.print("[logsessions] FAILED to hook WriteFormattedLogMessage!\n"); } else { - con.print("[combatlog] hooked WriteFormattedLogMessage OK\n"); + con.print("[logsessions] hooked WriteFormattedLogMessage OK\n"); } } diff --git a/src/combatlog/offsets.zig b/src/logsessions/offsets.zig similarity index 98% rename from src/combatlog/offsets.zig rename to src/logsessions/offsets.zig index faa51f0..3671fd6 100644 --- a/src/combatlog/offsets.zig +++ b/src/logsessions/offsets.zig @@ -1,4 +1,4 @@ -//! Address constants for combat log session rotation. +//! Address constants for log session rotation. // ============================================================================= // Combat log path and state diff --git a/src/main.zig b/src/main.zig index 52b57c7..1913ec7 100644 --- a/src/main.zig +++ b/src/main.zig @@ -9,11 +9,12 @@ const build_opts = struct { const outline = @import("build_options").enable_outline; const worldmarkers = @import("build_options").enable_worldmarkers; const framecrash = @import("build_options").enable_framecrash; - const combatlog = @import("build_options").enable_combatlog; + const logsessions = @import("build_options").enable_logsessions; const minimapicons = @import("build_options").enable_minimapicons; const transmogfix = @import("build_options").enable_transmogfix; const customassets = @import("build_options").enable_customassets; const healtextfix = @import("build_options").enable_healtextfix; + const bigcursor = @import("build_options").enable_bigcursor; }; // Conditional module imports @@ -22,11 +23,12 @@ const interact = if (build_opts.interact) @import("interact/interact.zig") else const outline = if (build_opts.outline) @import("outline/api.zig") else struct {}; const markers = if (build_opts.worldmarkers) @import("markers/markers.zig") else struct {}; const framecrash = if (build_opts.framecrash) @import("framecrash/framecrash.zig") else struct {}; -const combatlog = if (build_opts.combatlog) @import("combatlog/combatlog.zig") else struct {}; +const logsessions = if (build_opts.logsessions) @import("logsessions/logsessions.zig") else struct {}; const minimapicons = if (build_opts.minimapicons) @import("minimapicons/minimapicons.zig") else struct {}; const transmogfix = if (build_opts.transmogfix) @import("transmogfix/transmogfix.zig") else struct {}; const customassets = if (build_opts.customassets) @import("customassets/customassets.zig") else struct {}; const healtextfix = if (build_opts.healtextfix) @import("healtextfix/healtextfix.zig") else struct {}; +const bigcursor = if (build_opts.bigcursor) @import("bigcursor/bigcursor.zig") else struct {}; const WINAPI = std.builtin.CallingConvention.winapi; const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} }; @@ -108,9 +110,9 @@ fn registerLuaFunctions() void { if (build_opts.outline) { registerFunction("OutlineCommand", @intFromPtr(&outline.outlineCommand)); } - if (build_opts.combatlog) { - registerFunction("GetCombatLogPath", @intFromPtr(&combatlog.luaGetCombatLogPath)); - registerFunction("GetChatLogPath", @intFromPtr(&combatlog.luaGetChatLogPath)); + if (build_opts.logsessions) { + registerFunction("GetCombatLogPath", @intFromPtr(&logsessions.luaGetCombatLogPath)); + registerFunction("GetChatLogPath", @intFromPtr(&logsessions.luaGetChatLogPath)); } if (build_opts.worldmarkers and markers.isActive()) { // User-facing functions stay global @@ -795,7 +797,7 @@ fn logoutDetour() callconv(sc) void { // Reset per-session state — only on real logout/disconnect, not /reload. if (build_opts.worldmarkers) markers.onShutdown(); - if (build_opts.combatlog) combatlog.onShutdown(); + if (build_opts.logsessions) logsessions.onShutdown(); // Clean up world objects BEFORE game teardown — modules with // remove_on_shutdown must destroy while game systems are alive. @@ -836,10 +838,11 @@ const ModuleHooks = struct { const modules = [_]ModuleHooks{ if (build_opts.customassets) .{ .install = customassets.installHooks, .remove = customassets.removeHooks } else .{}, if (build_opts.framecrash) .{ .install = framecrash.installHooks, .remove = framecrash.removeHooks } else .{}, - if (build_opts.combatlog) .{ .install = combatlog.installHooks, .remove = combatlog.removeHooks } else .{}, + if (build_opts.logsessions) .{ .install = logsessions.installHooks, .remove = logsessions.removeHooks } else .{}, if (build_opts.transmogfix) .{ .install = transmogfix.installHooks, .remove = transmogfix.removeHooks } else .{}, if (build_opts.minimapicons) .{ .install = minimapicons.installHooks, .remove = minimapicons.removeHooks } else .{}, if (build_opts.healtextfix) .{ .install = healtextfix.installHooks, .remove = healtextfix.removeHooks } else .{}, + if (build_opts.bigcursor) .{ .install = bigcursor.installHooks, .remove = bigcursor.removeHooks } else .{}, if (build_opts.worldmarkers) .{ .install = markers.installHooks, .remove = markers.removeHooks } else .{}, if (build_opts.interact) .{ .install = interact.installHooks, .remove = interact.removeHooks } else .{}, if (build_opts.outline) .{ .remove = outline.cleanup } else .{}, diff --git a/src/transmogfix/transmogfix.zig b/src/transmogfix/transmogfix.zig index e37c533..ffb8baa 100644 --- a/src/transmogfix/transmogfix.zig +++ b/src/transmogfix/transmogfix.zig @@ -70,8 +70,7 @@ fn unitGUID(unit_id: [*:0]const u8) u64 { [hi] "={edx}" (hi), : [_] "{ecx}" (unit_id), [func] "r" (@as(u32, ADDR_UnitGUID)), - : .{ .memory = true, .cc = true } - ); + : .{ .memory = true, .cc = true }); return @as(u64, hi) << 32 | lo; } @@ -86,8 +85,7 @@ fn getObjectByGUID(guid: u64) u32 { : [lo] "r" (lo), [hi] "r" (hi), [func] "r" (@as(u32, ADDR_GetObjectByGUID)), - : .{ .ecx = true, .edx = true, .memory = true, .cc = true } - ); + : .{ .ecx = true, .edx = true, .memory = true, .cc = true }); } fn updateInventoryAlertStates() void { @@ -765,7 +763,6 @@ fn hookRefreshVisualAppearance(unit: u32, event_data: u32, extra_data: u32, forc // ============================================================================= fn hookSceneEnd(device: u32) callconv(tc) void { - if (g_enabled and (g_local_pending_count > 0 or g_other_pending_count > 0)) { processTimeouts(GetTickCount()); } @@ -782,7 +779,8 @@ pub fn installHooks() void { // Multi-DLL safety: only one instance per process should hook var mutex_name_buf: [64]u8 = undefined; - const mutex_name = std.fmt.bufPrint(&mutex_name_buf, "Local\\WeirdUtils_TransmogCoalesceHook_{d}", .{GetCurrentProcessId()}) catch return; + // muted name scheme not quite the same because this dll exists in the wild and we want to match it + const mutex_name = std.fmt.bufPrint(&mutex_name_buf, "Local\\TransmogCoalesceHook_{d}", .{GetCurrentProcessId()}) catch return; mutex_name_buf[mutex_name.len] = 0; g_mutex = CreateMutexA(null, 1, @ptrCast(mutex_name_buf[0..mutex_name.len :0]));