Use hook.cc.* aliases and migrate remaining hook.fastcall calls
Replace all local calling convention declarations (const fc/tc/sc) with hook.cc.fastcall/thiscall/stdcall from zhook. Migrate remaining 17 hook.fastcall() inline asm call sites to hook.call() with typed function pointers.
This commit is contained in:
+3
-5
@@ -16,8 +16,6 @@ const hook = @import("zhook");
|
||||
const con = @import("console.zig");
|
||||
const build_options = @import("build_options");
|
||||
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
|
||||
// Build option convenience aliases
|
||||
const build_opts = struct {
|
||||
@@ -300,9 +298,9 @@ pub fn findEmbeddedFile(path: [*:0]const u8) ?*const FileEntry {
|
||||
// DLL-embedded addon to register them in the game's addon hash table.
|
||||
// =============================================================================
|
||||
|
||||
var setup_addons_hook: hook.Detour(fn (u32) callconv(fc) void) = .{};
|
||||
var setup_addons_hook: hook.Detour(fn (u32) callconv(hook.cc.fastcall) void) = .{};
|
||||
|
||||
fn setupAddonsDetour(mgr_ptr: u32) callconv(fc) void {
|
||||
fn setupAddonsDetour(mgr_ptr: u32) callconv(hook.cc.fastcall) void {
|
||||
setup_addons_hook.callOriginal(.{mgr_ptr});
|
||||
|
||||
inline for (embed_modules) |mod| {
|
||||
@@ -343,7 +341,7 @@ fn hideAddonFromList(name: [*:0]const u8) void {
|
||||
}
|
||||
|
||||
fn callLoadAddonTOC(addon_name: [*:0]const u8) void {
|
||||
hook.call(fn ([*:0]const u8) callconv(fc) void, 0x0051c9b0, .{addon_name});
|
||||
hook.call(fn ([*:0]const u8) callconv(hook.cc.fastcall) void, 0x0051c9b0, .{addon_name});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
+17
-22
@@ -13,9 +13,6 @@ const con = @import("../console.zig");
|
||||
const mod_mutex = @import("../mutex.zig");
|
||||
|
||||
const WINAPI = std.builtin.CallingConvention.winapi;
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
|
||||
pub const module_name: [*:0]const u8 = "bigcursor";
|
||||
|
||||
@@ -172,21 +169,19 @@ const IconInfo = extern struct {
|
||||
const CVAR_LOOKUP: usize = 0x0063DEC0;
|
||||
|
||||
// RegisterCVar: __fastcall(ECX=name, EDX=help, stack: unk1, default, callback, category, unk2, unk3)
|
||||
const RegisterCVarFn = *const fn ([*:0]const u8, u32, u32, [*:0]const u8, u32, u32, u32, u32) callconv(fc) u32;
|
||||
const RegisterCVarFn = *const fn ([*:0]const u8, u32, u32, [*:0]const u8, u32, u32, u32, u32) callconv(hook.cc.fastcall) u32;
|
||||
const registerCVar: RegisterCVarFn = @ptrFromInt(0x0063DB90);
|
||||
|
||||
const CVAR_NAME = "cursorScale";
|
||||
|
||||
/// Read CVar integer value (tenths: 15 = 1.5x). Returns f32 scale.
|
||||
fn readCVarScaleInit() f32 {
|
||||
const cvar_ptr = hook.fastcall(u32, CVAR_LOOKUP, @intFromPtr(@as([*:0]const u8, CVAR_NAME)), @as(u32, 0));
|
||||
const cvar_ptr = hook.call(fn ([*:0]const u8) callconv(hook.cc.fastcall) u32, CVAR_LOOKUP, .{CVAR_NAME});
|
||||
if (cvar_ptr == 0) return g_scale_f;
|
||||
// CVar struct: integer value at offset +40 bytes (10 pointer-sized fields)
|
||||
const val = hook.readMem(i32, cvar_ptr + 40);
|
||||
if (val >= 10 and val <= 40) {
|
||||
return @as(f32, @floatFromInt(val)) / 10.0;
|
||||
}
|
||||
return g_scale_f;
|
||||
const clamped = std.math.clamp(val, 5, 40);
|
||||
return @as(f32, @floatFromInt(clamped)) / 10.0;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -277,17 +272,17 @@ const D3DSURFACE_DESC = extern struct {
|
||||
};
|
||||
|
||||
fn surfaceGetDesc(surface: *anyopaque, desc: *D3DSURFACE_DESC) i32 {
|
||||
const f: *const fn (*anyopaque, *D3DSURFACE_DESC) callconv(sc) i32 = @ptrFromInt(vtbl(surface)[SVT_GetDesc]);
|
||||
const f: *const fn (*anyopaque, *D3DSURFACE_DESC) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vtbl(surface)[SVT_GetDesc]);
|
||||
return f(surface, desc);
|
||||
}
|
||||
|
||||
fn surfaceLockRect(surface: *anyopaque, locked: *D3DLOCKED_RECT, rect: ?*anyopaque, flags: u32) i32 {
|
||||
const f: *const fn (*anyopaque, *D3DLOCKED_RECT, ?*anyopaque, u32) callconv(sc) i32 = @ptrFromInt(vtbl(surface)[SVT_LockRect]);
|
||||
const f: *const fn (*anyopaque, *D3DLOCKED_RECT, ?*anyopaque, u32) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vtbl(surface)[SVT_LockRect]);
|
||||
return f(surface, locked, rect, flags);
|
||||
}
|
||||
|
||||
fn surfaceUnlockRect(surface: *anyopaque) i32 {
|
||||
const f: *const fn (*anyopaque) callconv(sc) i32 = @ptrFromInt(vtbl(surface)[SVT_UnlockRect]);
|
||||
const f: *const fn (*anyopaque) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vtbl(surface)[SVT_UnlockRect]);
|
||||
return f(surface);
|
||||
}
|
||||
|
||||
@@ -468,8 +463,8 @@ fn cacheClear() void {
|
||||
// Hook: IDirect3DDevice9::SetCursorProperties (VT slot 10)
|
||||
// =============================================================================
|
||||
|
||||
fn hkSetCursorProperties(device: *anyopaque, x_hotspot: u32, y_hotspot: u32, cursor_surface: *anyopaque) callconv(sc) i32 {
|
||||
const origFn: *const fn (*anyopaque, u32, u32, *anyopaque) callconv(sc) i32 =
|
||||
fn hkSetCursorProperties(device: *anyopaque, x_hotspot: u32, y_hotspot: u32, cursor_surface: *anyopaque) callconv(hook.cc.stdcall) i32 {
|
||||
const origFn: *const fn (*anyopaque, u32, u32, *anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(orig_set_cursor_props);
|
||||
|
||||
if (g_scale_f <= 1.0) return origFn(device, x_hotspot, y_hotspot, cursor_surface);
|
||||
@@ -532,8 +527,8 @@ fn hkSetCursorProperties(device: *anyopaque, x_hotspot: u32, y_hotspot: u32, cur
|
||||
// Hook: IDirect3DDevice9::ShowCursor (VT slot 12)
|
||||
// =============================================================================
|
||||
|
||||
fn hkShowCursor(device: *anyopaque, bShow: i32) callconv(sc) i32 {
|
||||
const origFn: *const fn (*anyopaque, i32) callconv(sc) i32 =
|
||||
fn hkShowCursor(device: *anyopaque, bShow: i32) callconv(hook.cc.stdcall) i32 {
|
||||
const origFn: *const fn (*anyopaque, i32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(orig_show_cursor);
|
||||
|
||||
g_cursor_visible = bShow != 0;
|
||||
@@ -557,19 +552,19 @@ fn hkShowCursor(device: *anyopaque, bShow: i32) callconv(sc) i32 {
|
||||
// =============================================================================
|
||||
|
||||
fn luaPushNumber(L_ptr: usize, n: f64) void {
|
||||
hook.call(fn (usize, f64) callconv(tc) void, 0x6F3810, .{ L_ptr, n });
|
||||
hook.call(fn (usize, f64) callconv(hook.cc.thiscall) void, 0x6F3810, .{ L_ptr, n });
|
||||
}
|
||||
|
||||
pub fn luaSetCursorScale(L: *anyopaque) callconv(.c) u32 {
|
||||
const L_ptr = @intFromPtr(L);
|
||||
const nargs = hook.fastcall(i32, 0x6F3070, L_ptr, @as(u32, 0)); // lua_gettop
|
||||
const nargs = hook.call(fn (usize) callconv(hook.cc.fastcall) i32, 0x6F3070, .{L_ptr}); // lua_gettop
|
||||
if (nargs < 1) return 0;
|
||||
|
||||
const val: f32 = @floatCast(hook.fastcall(f64, 0x6F3620, L_ptr, @as(i32, 1))); // lua_tonumber
|
||||
if (val < 1.0 or val > 4.0) return 0;
|
||||
const val: f32 = @floatCast(hook.call(fn (usize, i32) callconv(hook.cc.fastcall) f64, 0x6F3620, .{ L_ptr, 1 })); // lua_tonumber
|
||||
const clamped = std.math.clamp(val, 0.5, 4.0);
|
||||
|
||||
if (val != g_scale_f) {
|
||||
g_scale_f = val;
|
||||
if (clamped != g_scale_f) {
|
||||
g_scale_f = clamped;
|
||||
cacheClear();
|
||||
g_hcursor = null;
|
||||
logFmt("[bigcursor] scale set to {d:.2}\n", .{g_scale_f});
|
||||
|
||||
@@ -24,8 +24,6 @@ const hook = @import("zhook");
|
||||
const con = @import("../console.zig");
|
||||
|
||||
const WINAPI = std.builtin.CallingConvention.winapi;
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
|
||||
extern "kernel32" fn IsBadReadPtr(lp: ?*const anyopaque, ucb: usize) callconv(WINAPI) i32;
|
||||
extern "kernel32" fn CreateMutexA(lpMutexAttributes: ?*anyopaque, bInitialOwner: i32, lpName: [*:0]const u8) callconv(WINAPI) ?*anyopaque;
|
||||
@@ -94,7 +92,7 @@ const G_PARENT_FRAME_TYPE_ID: usize = 0x00cf0c10;
|
||||
|
||||
const CLEANUP_TARGET: usize = 0x767720;
|
||||
|
||||
const CleanupFn = fn (u32) callconv(tc) void;
|
||||
const CleanupFn = fn (u32) callconv(hook.cc.thiscall) void;
|
||||
var cleanup_hook: hook.Detour(CleanupFn) = .{};
|
||||
|
||||
// =============================================================================
|
||||
@@ -111,7 +109,7 @@ var cleanup_hook: hook.Detour(CleanupFn) = .{};
|
||||
|
||||
const DESTROY_UI_TARGET: usize = 0x7645a0;
|
||||
|
||||
const DestroyUIFn = fn (u32, u32) callconv(tc) u32;
|
||||
const DestroyUIFn = fn (u32, u32) callconv(hook.cc.thiscall) u32;
|
||||
var destroy_ui_hook: hook.Detour(DestroyUIFn) = .{};
|
||||
|
||||
// =============================================================================
|
||||
@@ -125,7 +123,7 @@ var destroy_ui_hook: hook.Detour(DestroyUIFn) = .{};
|
||||
|
||||
const PROCESS_UI_TARGET: usize = 0x772ec0;
|
||||
|
||||
const ProcessUIFn = fn (u32, u32) callconv(tc) u32;
|
||||
const ProcessUIFn = fn (u32, u32) callconv(hook.cc.thiscall) u32;
|
||||
var process_ui_hook: hook.Detour(ProcessUIFn) = .{};
|
||||
|
||||
// =============================================================================
|
||||
@@ -143,7 +141,7 @@ var process_ui_hook: hook.Detour(ProcessUIFn) = .{};
|
||||
|
||||
const PAUSE_ANIM_TARGET: usize = 0x767ee0;
|
||||
|
||||
const PauseAnimFn = fn (u32, u32, u32) callconv(tc) void;
|
||||
const PauseAnimFn = fn (u32, u32, u32) callconv(hook.cc.thiscall) void;
|
||||
var pause_anim_hook: hook.Detour(PauseAnimFn) = .{};
|
||||
|
||||
// =============================================================================
|
||||
@@ -162,7 +160,7 @@ var pause_anim_hook: hook.Detour(PauseAnimFn) = .{};
|
||||
|
||||
const SET_ANIM_TARGET: usize = 0x767c70;
|
||||
|
||||
const SetAnimFn = fn (u32, u32, u32, u32, u32, u32, u32) callconv(tc) void;
|
||||
const SetAnimFn = fn (u32, u32, u32, u32, u32, u32, u32) callconv(hook.cc.thiscall) void;
|
||||
var set_anim_hook: hook.Detour(SetAnimFn) = .{};
|
||||
|
||||
// =============================================================================
|
||||
@@ -286,7 +284,7 @@ fn fmtStaleInfo(relativeTo: u32) struct { name: []const u8, saw_destroy: bool }
|
||||
|
||||
/// Detour for cleanup_linked_list_structures. Runs before the original to
|
||||
/// walk the dying frame's dependency list and destroy referencing anchors.
|
||||
fn cleanupDetour(frame: u32) callconv(tc) void {
|
||||
fn cleanupDetour(frame: u32) callconv(hook.cc.thiscall) void {
|
||||
recordDestruction(frame);
|
||||
cleanupReverseDependencies(frame);
|
||||
cleanup_hook.callOriginal(.{frame});
|
||||
@@ -296,7 +294,7 @@ fn cleanupDetour(frame: u32) callconv(tc) void {
|
||||
/// called from cleanupGraphicsResources during UI teardown/reload. The original
|
||||
/// frees frames without walking the dependency list, leaving stale anchors.
|
||||
/// Signature: void* __thiscall destroyUIElement(void* this, byte free_flag)
|
||||
fn destroyUIDetour(frame: u32, free_flag: u32) callconv(tc) u32 {
|
||||
fn destroyUIDetour(frame: u32, free_flag: u32) callconv(hook.cc.thiscall) u32 {
|
||||
recordDestruction(frame);
|
||||
if (IsBadReadPtr(@ptrFromInt(frame + 0x24), 4) == 0) {
|
||||
recordDestruction(frame + 0x24);
|
||||
@@ -307,7 +305,7 @@ fn destroyUIDetour(frame: u32, free_flag: u32) callconv(tc) u32 {
|
||||
}
|
||||
|
||||
/// Detour for ProcessUIUpdateEvent - third destruction path, called via vtable.
|
||||
fn processUIDetour(frame: u32, free_flag: u32) callconv(tc) u32 {
|
||||
fn processUIDetour(frame: u32, free_flag: u32) callconv(hook.cc.thiscall) u32 {
|
||||
recordDestruction(frame);
|
||||
if (IsBadReadPtr(@ptrFromInt(frame + 0x24), 4) == 0) {
|
||||
recordDestruction(frame + 0x24);
|
||||
@@ -321,7 +319,7 @@ fn processUIDetour(frame: u32, free_flag: u32) callconv(tc) u32 {
|
||||
/// This tells us whether a stale relativeTo was ever registered through the
|
||||
/// normal dependency tracking system.
|
||||
/// Signature: void __thiscall PauseAnimationGroup(ECX=relativeTo_frame, owner_frame, bitmask)
|
||||
fn pauseAnimDetour(relativeTo_frame: u32, owner_frame: u32, bitmask: u32) callconv(tc) void {
|
||||
fn pauseAnimDetour(relativeTo_frame: u32, owner_frame: u32, bitmask: u32) callconv(hook.cc.thiscall) void {
|
||||
// Silently record - queried later by vtable hooks via logRegistrationStatus()
|
||||
recordRegistration(relativeTo_frame, owner_frame, bitmask);
|
||||
|
||||
@@ -330,7 +328,7 @@ fn pauseAnimDetour(relativeTo_frame: u32, owner_frame: u32, bitmask: u32) callco
|
||||
|
||||
/// Detour for SetAnimationOrder - validates relativeTo param before anchor creation.
|
||||
/// Float params (xOfs, yOfs) are passed as raw u32 bit patterns on the stack.
|
||||
fn setAnimOrderDetour(frame: u32, point_enum: u32, relativeTo: u32, rel_point: u32, x_ofs: u32, y_ofs: u32, param_6: u32) callconv(tc) void {
|
||||
fn setAnimOrderDetour(frame: u32, point_enum: u32, relativeTo: u32, rel_point: u32, x_ofs: u32, y_ofs: u32, param_6: u32) callconv(hook.cc.thiscall) void {
|
||||
var fixed_relativeTo = relativeTo;
|
||||
|
||||
// Validate relativeTo BEFORE the original creates the anchor.
|
||||
@@ -481,7 +479,7 @@ fn getLiveUIParent() u32 {
|
||||
const type_id = readAligned(G_PARENT_FRAME_TYPE_ID);
|
||||
if (type_id == 0) return 0;
|
||||
|
||||
const cframe_base = hook.fastcall(u32, GET_FRAME_FROM_LUA, @intFromPtr(@as([*:0]const u8, "UIParent")), type_id);
|
||||
const cframe_base = hook.call(fn ([*:0]const u8, u32) callconv(hook.cc.fastcall) u32, GET_FRAME_FROM_LUA, .{ "UIParent", type_id });
|
||||
if (cframe_base == 0) return 0;
|
||||
|
||||
// Validate the returned pointer
|
||||
@@ -549,8 +547,8 @@ fn isRelativeToValid(relativeTo: u32) bool {
|
||||
|
||||
/// Hook for vtable[3] GetRelativeTo. Validates the stored pointer.
|
||||
/// If stale, NULLs anchor+0x0C and returns 0 (safe "no relativeTo" path).
|
||||
fn getRelativeToHook(this: u32) callconv(tc) u32 {
|
||||
const orig: *const fn (u32) callconv(tc) u32 = @ptrFromInt(orig_get_relative_to);
|
||||
fn getRelativeToHook(this: u32) callconv(hook.cc.thiscall) u32 {
|
||||
const orig: *const fn (u32) callconv(hook.cc.thiscall) u32 = @ptrFromInt(orig_get_relative_to);
|
||||
const result = orig(this);
|
||||
|
||||
if (result == 0) return 0;
|
||||
@@ -573,14 +571,14 @@ fn getRelativeToHook(this: u32) callconv(tc) u32 {
|
||||
/// Hook for vtable[1] GetWidth. Checks anchor+0x0C before calling original.
|
||||
/// Returns sentinel if relativeTo is NULL or dangling.
|
||||
/// Signature: f32 __thiscall GetWidth(this, u32 param) - callee cleans 1 stack arg.
|
||||
fn getWidthHook(this: u32, param: u32) callconv(tc) f32 {
|
||||
fn getWidthHook(this: u32, param: u32) callconv(hook.cc.thiscall) f32 {
|
||||
const relativeTo: u32 = readAligned(this + 0x0C);
|
||||
if (!isRelativeToValid(relativeTo)) {
|
||||
if (relativeTo != 0) {
|
||||
// Try to substitute live UIParent instead of NULLing
|
||||
if (tryFixStaleRelativeTo(this, relativeTo)) {
|
||||
// Fixed - call original with the healed pointer
|
||||
const orig: *const fn (u32, u32) callconv(tc) f32 = @ptrFromInt(orig_get_width);
|
||||
const orig: *const fn (u32, u32) callconv(hook.cc.thiscall) f32 = @ptrFromInt(orig_get_width);
|
||||
return orig(this, param);
|
||||
}
|
||||
const field: *align(1) u32 = @ptrFromInt(this + 0x0C);
|
||||
@@ -589,19 +587,19 @@ fn getWidthHook(this: u32, param: u32) callconv(tc) f32 {
|
||||
return @as(*align(1) const f32, @ptrFromInt(SENTINEL_ADDR)).*;
|
||||
}
|
||||
|
||||
const orig: *const fn (u32, u32) callconv(tc) f32 = @ptrFromInt(orig_get_width);
|
||||
const orig: *const fn (u32, u32) callconv(hook.cc.thiscall) f32 = @ptrFromInt(orig_get_width);
|
||||
return orig(this, param);
|
||||
}
|
||||
|
||||
/// Hook for vtable[2] GetHeight. Same pattern as GetWidth.
|
||||
/// Signature: f32 __thiscall GetHeight(this, u32 param) - callee cleans 1 stack arg.
|
||||
fn getHeightHook(this: u32, param: u32) callconv(tc) f32 {
|
||||
fn getHeightHook(this: u32, param: u32) callconv(hook.cc.thiscall) f32 {
|
||||
const relativeTo: u32 = readAligned(this + 0x0C);
|
||||
if (!isRelativeToValid(relativeTo)) {
|
||||
if (relativeTo != 0) {
|
||||
// Try to substitute live UIParent instead of NULLing
|
||||
if (tryFixStaleRelativeTo(this, relativeTo)) {
|
||||
const orig: *const fn (u32, u32) callconv(tc) f32 = @ptrFromInt(orig_get_height);
|
||||
const orig: *const fn (u32, u32) callconv(hook.cc.thiscall) f32 = @ptrFromInt(orig_get_height);
|
||||
return orig(this, param);
|
||||
}
|
||||
const field: *align(1) u32 = @ptrFromInt(this + 0x0C);
|
||||
@@ -610,7 +608,7 @@ fn getHeightHook(this: u32, param: u32) callconv(tc) f32 {
|
||||
return @as(*align(1) const f32, @ptrFromInt(SENTINEL_ADDR)).*;
|
||||
}
|
||||
|
||||
const orig: *const fn (u32, u32) callconv(tc) f32 = @ptrFromInt(orig_get_height);
|
||||
const orig: *const fn (u32, u32) callconv(hook.cc.thiscall) f32 = @ptrFromInt(orig_get_height);
|
||||
return orig(this, param);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,8 +55,6 @@ const C3Vector = struct {
|
||||
// Calling Conventions
|
||||
// =============================================================================
|
||||
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
|
||||
// =============================================================================
|
||||
// Game API
|
||||
@@ -65,7 +63,7 @@ const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
fn getObjectPointer(guid: u64) u32 {
|
||||
const lo: u32 = @truncate(guid);
|
||||
const hi: u32 = @truncate(guid >> 32);
|
||||
return hook.call(fn (u32, u32) callconv(sc) u32, Offsets.FUN_GET_OBJECT_POINTER, .{ lo, hi });
|
||||
return hook.call(fn (u32, u32) callconv(hook.cc.stdcall) u32, Offsets.FUN_GET_OBJECT_POINTER, .{ lo, hi });
|
||||
}
|
||||
|
||||
fn isInWorld() bool {
|
||||
@@ -106,11 +104,11 @@ fn isUnitSkinnable(unit: u32) bool {
|
||||
fn setTarget(guid: u64) void {
|
||||
const lo: u32 = @truncate(guid);
|
||||
const hi: u32 = @truncate(guid >> 32);
|
||||
hook.call(fn (u32, u32) callconv(sc) void, Offsets.FUN_SET_TARGET, .{ lo, hi });
|
||||
hook.call(fn (u32, u32) callconv(hook.cc.stdcall) void, Offsets.FUN_SET_TARGET, .{ lo, hi });
|
||||
}
|
||||
|
||||
fn rightClickInteract(pointer: u32, autoloot: i32, fun_ptr: usize) void {
|
||||
hook.call(fn (u32, i32) callconv(tc) void, fun_ptr, .{ pointer, autoloot });
|
||||
hook.call(fn (u32, i32) callconv(hook.cc.thiscall) void, fun_ptr, .{ pointer, autoloot });
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -134,15 +132,15 @@ fn isBlacklisted(id: u32) bool {
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Lua helpers (hook.fastcall to avoid broken callconv(fc) codegen)
|
||||
// Lua helpers
|
||||
// =============================================================================
|
||||
|
||||
fn luaIsNumber(L: *anyopaque, idx: i32) bool {
|
||||
return hook.fastcall(u32, Offsets.LUA_ISNUMBER, @intFromPtr(L), idx) != 0;
|
||||
return hook.call(fn (usize, i32) callconv(hook.cc.fastcall) u32, Offsets.LUA_ISNUMBER, .{ @intFromPtr(L), idx }) != 0;
|
||||
}
|
||||
|
||||
fn luaToNumber(L: *anyopaque, idx: i32) f64 {
|
||||
return hook.fastcall(f64, Offsets.LUA_TONUMBER, @intFromPtr(L), idx);
|
||||
return hook.call(fn (usize, i32) callconv(hook.cc.fastcall) f64, Offsets.LUA_TONUMBER, .{ @intFromPtr(L), idx });
|
||||
}
|
||||
|
||||
fn luaPrintError(L: *anyopaque, msg: [*:0]const u8) void {
|
||||
@@ -364,10 +362,10 @@ pub fn lootAllCorpses(_: *anyopaque) callconv(.c) u32 {
|
||||
// Per-frame hook for processing the loot queue.
|
||||
// =============================================================================
|
||||
|
||||
const SceneEndFn = fn (u32) callconv(tc) void;
|
||||
const SceneEndFn = fn (u32) callconv(hook.cc.thiscall) void;
|
||||
var scene_end_hook: hook.Detour(SceneEndFn) = .{};
|
||||
|
||||
fn hookSceneEnd(device: u32) callconv(tc) void {
|
||||
fn hookSceneEnd(device: u32) callconv(hook.cc.thiscall) void {
|
||||
if (loot_active) {
|
||||
processLootQueue();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ const con = @import("../console.zig");
|
||||
const lua = @import("../lua.zig");
|
||||
const o = @import("offsets.zig");
|
||||
|
||||
const sc = std.builtin.CallingConvention{ .x86_stdcall = .{} };
|
||||
const WINAPI = std.builtin.CallingConvention.winapi;
|
||||
|
||||
// =============================================================================
|
||||
@@ -334,12 +333,12 @@ fn configureSession(char_span: []const u8, realm_span: []const u8) void {
|
||||
// HandleCharacterSelection hook - set up paths before world loading
|
||||
// =============================================================================
|
||||
|
||||
var enter_world_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var enter_world_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
/// Fires when the player clicks Enter World on the character select screen.
|
||||
/// Character name and realm are available from the select screen data.
|
||||
/// Sets up paths BEFORE the world loading sequence calls InitializeLogBuffer.
|
||||
fn enterWorldDetour() callconv(sc) void {
|
||||
fn enterWorldDetour() callconv(hook.cc.stdcall) void {
|
||||
asm volatile ("" ::: .{ .esi = true, .edi = true, .ebx = true });
|
||||
|
||||
if (!g_paths_configured) {
|
||||
@@ -373,9 +372,9 @@ fn restorePathPointers() void {
|
||||
// InitializeLogBuffer hook - lazy setup + path redirect
|
||||
// =============================================================================
|
||||
|
||||
var init_log_hook: hook.Detour(fn (u32, u32, u32) callconv(sc) u32) = .{};
|
||||
var init_log_hook: hook.Detour(fn (u32, u32, u32) callconv(hook.cc.stdcall) u32) = .{};
|
||||
|
||||
fn initLogDetour(file_path: u32, flags: u32, handle_out: u32) callconv(sc) u32 {
|
||||
fn initLogDetour(file_path: u32, flags: u32, handle_out: u32) callconv(hook.cc.stdcall) u32 {
|
||||
asm volatile ("" ::: .{ .esi = true, .edi = true, .ebx = true });
|
||||
|
||||
const path_ptr: [*:0]const u8 = @ptrFromInt(file_path);
|
||||
@@ -405,9 +404,9 @@ fn initLogDetour(file_path: u32, flags: u32, handle_out: u32) callconv(sc) u32 {
|
||||
// WriteFormattedLogMessage hook - inject session markers on first write per log
|
||||
// =============================================================================
|
||||
|
||||
var write_log_hook: hook.Detour(fn (u32, u32, u32) callconv(sc) void) = .{};
|
||||
var write_log_hook: hook.Detour(fn (u32, u32, u32) callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
fn writeLogDetour(handle: u32, fmt: u32, va_list: u32) callconv(sc) void {
|
||||
fn writeLogDetour(handle: u32, fmt: u32, va_list: u32) callconv(hook.cc.stdcall) void {
|
||||
asm volatile ("" ::: .{ .esi = true, .edi = true, .ebx = true });
|
||||
|
||||
if (g_session_char_len > 0) {
|
||||
|
||||
+26
-27
@@ -1,22 +1,22 @@
|
||||
//! WoW 1.12.1 Lua C API wrappers (all __fastcall, L in ECX)
|
||||
|
||||
const std = @import("std");
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const hook = @import("zhook");
|
||||
|
||||
pub const State = *anyopaque;
|
||||
|
||||
pub fn getContext() State {
|
||||
const f: *const fn () callconv(fc) State = @ptrFromInt(0x7040D0);
|
||||
const f: *const fn () callconv(hook.cc.fastcall) State = @ptrFromInt(0x7040D0);
|
||||
return f();
|
||||
}
|
||||
|
||||
pub fn gettop(L: State) i32 {
|
||||
const f: *const fn (State) callconv(fc) i32 = @ptrFromInt(0x6F3070);
|
||||
const f: *const fn (State) callconv(hook.cc.fastcall) i32 = @ptrFromInt(0x6F3070);
|
||||
return f(L);
|
||||
}
|
||||
|
||||
pub fn settop(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3080);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3080);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
@@ -25,42 +25,42 @@ pub fn pop(L: State, n: i32) void {
|
||||
}
|
||||
|
||||
pub fn pushvalue(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3350);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3350);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn remove(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F30D0);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F30D0);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn insert(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F31A0);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F31A0);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn typeOf(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3400);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) i32 = @ptrFromInt(0x6F3400);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn typeName(L: State, tp: i32) [*:0]const u8 {
|
||||
const f: *const fn (State, i32) callconv(fc) [*:0]const u8 = @ptrFromInt(0x6F3480);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) [*:0]const u8 = @ptrFromInt(0x6F3480);
|
||||
return f(L, tp);
|
||||
}
|
||||
|
||||
pub fn isnumber(L: State, index: i32) bool {
|
||||
const f: *const fn (State, i32) callconv(fc) u32 = @ptrFromInt(0x6F34D0);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) u32 = @ptrFromInt(0x6F34D0);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
|
||||
pub fn isstring(L: State, index: i32) bool {
|
||||
const f: *const fn (State, i32) callconv(fc) u32 = @ptrFromInt(0x6F3510);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) u32 = @ptrFromInt(0x6F3510);
|
||||
return f(L, index) != 0;
|
||||
}
|
||||
|
||||
pub fn pushnil(L: State) void {
|
||||
const f: *const fn (State) callconv(fc) void = @ptrFromInt(0x6F37F0);
|
||||
const f: *const fn (State) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F37F0);
|
||||
f(L);
|
||||
}
|
||||
|
||||
@@ -72,63 +72,62 @@ pub fn pushnumber(L: State, n: f64) void {
|
||||
}
|
||||
|
||||
pub fn pushstring(L: State, s: [*:0]const u8) void {
|
||||
const f: *const fn (State, [*:0]const u8) callconv(fc) void = @ptrFromInt(0x6F3890);
|
||||
const f: *const fn (State, [*:0]const u8) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3890);
|
||||
f(L, s);
|
||||
}
|
||||
|
||||
pub fn pushboolean(L: State, b: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F39F0);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F39F0);
|
||||
f(L, b);
|
||||
}
|
||||
|
||||
pub fn pushcclosure(L: State, func: usize, n: i32) void {
|
||||
const f: *const fn (State, usize, i32) callconv(fc) void = @ptrFromInt(0x6F3920);
|
||||
const f: *const fn (State, usize, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3920);
|
||||
@call(.never_tail, f, .{ L, func, n });
|
||||
}
|
||||
|
||||
pub fn tonumber(L: State, index: i32) f64 {
|
||||
const f: *const fn (State, i32) callconv(fc) f64 = @ptrFromInt(0x6F3620);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) f64 = @ptrFromInt(0x6F3620);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn tostring(L: State, index: i32) ?[*:0]const u8 {
|
||||
const f: *const fn (State, i32) callconv(fc) ?[*:0]const u8 = @ptrFromInt(0x6F3690);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) ?[*:0]const u8 = @ptrFromInt(0x6F3690);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn toboolean(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3660);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) i32 = @ptrFromInt(0x6F3660);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn newtable(L: State) void {
|
||||
const f: *const fn (State) callconv(fc) void = @ptrFromInt(0x6F3C90);
|
||||
const f: *const fn (State) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3C90);
|
||||
f(L);
|
||||
}
|
||||
|
||||
pub fn settable(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3E20);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3E20);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn gettable(L: State, index: i32) void {
|
||||
const f: *const fn (State, i32) callconv(fc) void = @ptrFromInt(0x6F3A40);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F3A40);
|
||||
f(L, index);
|
||||
}
|
||||
|
||||
pub fn next(L: State, index: i32) i32 {
|
||||
const f: *const fn (State, i32) callconv(fc) i32 = @ptrFromInt(0x6F4450);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) i32 = @ptrFromInt(0x6F4450);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
pub fn pcall(L: State, nargs: i32, nresults: i32, errfunc: i32) i32 {
|
||||
const f: *const fn (State, i32, i32, i32) callconv(fc) i32 = @ptrFromInt(0x6F41A0);
|
||||
const f: *const fn (State, i32, i32, i32) callconv(hook.cc.fastcall) i32 = @ptrFromInt(0x6F41A0);
|
||||
return @call(.never_tail, f, .{ L, nargs, nresults, errfunc });
|
||||
}
|
||||
|
||||
pub fn luaError(L: State, msg: [*:0]const u8) void {
|
||||
const hook = @import("zhook");
|
||||
hook.call(fn (*anyopaque, [*:0]const u8) callconv(.c) void, 0x6F4940, .{ L, msg });
|
||||
hook.call(fn (*anyopaque, [*:0]const u8) callconv(hook.cc.cdecl) void, 0x6F4940, .{ L, msg });
|
||||
}
|
||||
|
||||
pub const LuaReg = extern struct {
|
||||
@@ -137,11 +136,11 @@ pub const LuaReg = extern struct {
|
||||
};
|
||||
|
||||
pub fn openlib(L: State, libname: ?[*:0]const u8, funcs: [*]const LuaReg, nup: i32) void {
|
||||
const f: *const fn (State, ?[*:0]const u8, [*]const LuaReg, i32) callconv(fc) void = @ptrFromInt(0x6F4DC0);
|
||||
const f: *const fn (State, ?[*:0]const u8, [*]const LuaReg, i32) callconv(hook.cc.fastcall) void = @ptrFromInt(0x6F4DC0);
|
||||
@call(.never_tail, f, .{ L, libname, funcs, nup });
|
||||
}
|
||||
|
||||
pub fn checknumber(L: State, index: i32) f64 {
|
||||
const f: *const fn (State, i32) callconv(fc) f64 = @ptrFromInt(0x6F4C80);
|
||||
const f: *const fn (State, i32) callconv(hook.cc.fastcall) f64 = @ptrFromInt(0x6F4C80);
|
||||
return f(L, index);
|
||||
}
|
||||
|
||||
+33
-36
@@ -33,16 +33,14 @@ const bigcursor = if (build_opts.bigcursor) @import("bigcursor/bigcursor.zig") e
|
||||
const dpslog = if (build_opts.dpslog) @import("dpslog/dpslog.zig") else struct {};
|
||||
|
||||
const WINAPI = std.builtin.CallingConvention.winapi;
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
|
||||
// =============================================================================
|
||||
// Lua Protection Bypass
|
||||
// =============================================================================
|
||||
|
||||
var protection_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var protection_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
fn luaProtectionDetour() callconv(sc) void {}
|
||||
fn luaProtectionDetour() callconv(hook.cc.stdcall) void {}
|
||||
|
||||
// =============================================================================
|
||||
// Lua C API wrappers (WoW 1.12.1 - all __fastcall, L in ECX)
|
||||
@@ -55,11 +53,11 @@ pub const lua = @import("lua.zig");
|
||||
// =============================================================================
|
||||
|
||||
fn registerFunction(name: [*:0]const u8, func_addr: usize) void {
|
||||
hook.fastcall(void, 0x704120, @intFromPtr(name), func_addr);
|
||||
hook.call(fn ([*:0]const u8, usize) callconv(hook.cc.fastcall) void, 0x704120, .{ name, func_addr });
|
||||
}
|
||||
|
||||
fn allocateGameBuffer(size: u32) ?[*]u8 {
|
||||
return hook.call(fn (u32, u32, u32, u32) callconv(sc) ?[*]u8, 0x6462E0, .{
|
||||
return hook.call(fn (u32, u32, u32, u32) callconv(hook.cc.stdcall) ?[*]u8, 0x6462E0, .{
|
||||
size, @intFromPtr(@as([*:0]const u8, "weirdutils")), 0, 0,
|
||||
});
|
||||
}
|
||||
@@ -122,7 +120,7 @@ const findEmbeddedFile = addons.findEmbeddedFile;
|
||||
// Hook: LoadFileWithTextureResourceFallback (0x648620)
|
||||
// =============================================================================
|
||||
|
||||
const LoadFileFn = fn (u32, [*:0]const u8, *?[*]u8, ?*u32, u32, u32, u32) callconv(sc) u32;
|
||||
const LoadFileFn = fn (u32, [*:0]const u8, *?[*]u8, ?*u32, u32, u32, u32) callconv(hook.cc.stdcall) u32;
|
||||
var file_hook: hook.Detour(LoadFileFn) = .{};
|
||||
|
||||
fn loadFileDetour(
|
||||
@@ -133,7 +131,7 @@ fn loadFileDetour(
|
||||
extra_alloc: u32,
|
||||
flags: u32,
|
||||
async_ptr: u32,
|
||||
) callconv(sc) u32 {
|
||||
) callconv(hook.cc.stdcall) u32 {
|
||||
if (findEmbeddedFile(path)) |entry| {
|
||||
const data_len: u32 = @intCast(entry.data.len);
|
||||
const total = data_len + extra_alloc;
|
||||
@@ -165,23 +163,22 @@ fn loadFileDetour(
|
||||
//
|
||||
// Fake context detection: type==0, handle(+0x04)==NULL, embedded_ptr(+0x30)!=0
|
||||
|
||||
const OpenFileFn = fn (u32, [*:0]const u8, u32, *u32) callconv(sc) u32;
|
||||
const OpenFileFn = fn (u32, [*:0]const u8, u32, *u32) callconv(hook.cc.stdcall) u32;
|
||||
var open_file_hook: hook.Detour(OpenFileFn) = .{};
|
||||
|
||||
const GetFileSizeFn = fn (u32, ?*u32) callconv(sc) u32;
|
||||
const GetFileSizeFn = fn (u32, ?*u32) callconv(hook.cc.stdcall) u32;
|
||||
var get_file_size_hook: hook.Detour(GetFileSizeFn) = .{};
|
||||
|
||||
const ReadFileFn = fn (u32, [*]u8, u32, ?*u32, u32, u32) callconv(sc) u32;
|
||||
const ReadFileFn = fn (u32, [*]u8, u32, ?*u32, u32, u32) callconv(hook.cc.stdcall) u32;
|
||||
var read_file_hook: hook.Detour(ReadFileFn) = .{};
|
||||
|
||||
const CleanupFileFn = fn (u32) callconv(sc) void;
|
||||
const CleanupFileFn = fn (u32) callconv(hook.cc.stdcall) void;
|
||||
var cleanup_file_handle_hook: hook.Detour(CleanupFileFn) = .{};
|
||||
|
||||
const ProcessAsyncFn = fn (u32) callconv(fc) void;
|
||||
const ProcessAsyncFn = fn (u32) callconv(hook.cc.fastcall) void;
|
||||
var process_async_hook: hook.Detour(ProcessAsyncFn) = .{};
|
||||
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
const LoadModelFn = fn (u32, u32, u32) callconv(tc) u32;
|
||||
const LoadModelFn = fn (u32, u32, u32) callconv(hook.cc.thiscall) u32;
|
||||
var model_load_hook: hook.Detour(LoadModelFn) = .{};
|
||||
|
||||
// Windows API imports for async handling
|
||||
@@ -199,17 +196,17 @@ fn isFakeFileContext(ctx_addr: u32) bool {
|
||||
|
||||
/// Call initializeFileContext (0x647290) - __thiscall(ECX=ctx, type)
|
||||
fn callInitFileContext(ctx: [*]u8, file_type: u32) void {
|
||||
hook.call(fn (u32, u32) callconv(tc) void, 0x647290, .{ @intFromPtr(ctx), file_type });
|
||||
hook.call(fn (u32, u32) callconv(hook.cc.thiscall) void, 0x647290, .{ @intFromPtr(ctx), file_type });
|
||||
}
|
||||
|
||||
/// Call cleanupFileContext (0x6472d0) - __thiscall(ECX=ctx)
|
||||
fn callCleanupFileContext(ctx: [*]u8) void {
|
||||
hook.call(fn (u32) callconv(tc) void, 0x6472d0, .{@intFromPtr(ctx)});
|
||||
hook.call(fn (u32) callconv(hook.cc.thiscall) void, 0x6472d0, .{@intFromPtr(ctx)});
|
||||
}
|
||||
|
||||
/// Free a buffer via FreeMemory/SMemFree (0x646430) - __stdcall(ptr, src, flags)
|
||||
fn freeGameBuffer(ptr: [*]u8) void {
|
||||
hook.call(fn (u32, u32, u32) callconv(sc) void, 0x646430, .{
|
||||
hook.call(fn (u32, u32, u32) callconv(hook.cc.stdcall) void, 0x646430, .{
|
||||
@intFromPtr(ptr), @intFromPtr(@as([*:0]const u8, "weirdutils")), 0xffffffff,
|
||||
});
|
||||
}
|
||||
@@ -221,7 +218,7 @@ fn openFileDetour(
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
handle_out: *u32,
|
||||
) callconv(sc) u32 {
|
||||
) callconv(hook.cc.stdcall) u32 {
|
||||
if (findEmbeddedFile(path)) |entry| {
|
||||
// Allocate and zero-fill 0x60-byte file context
|
||||
const ctx = allocateGameBuffer(0x60) orelse {
|
||||
@@ -259,7 +256,7 @@ fn openFileDetour(
|
||||
fn getFileSizeDetour(
|
||||
file_ctx: u32,
|
||||
high_size_out: ?*u32,
|
||||
) callconv(sc) u32 {
|
||||
) callconv(hook.cc.stdcall) u32 {
|
||||
if (isFakeFileContext(file_ctx)) {
|
||||
if (high_size_out) |h| h.* = 0;
|
||||
const size = hook.readMem(u32, file_ctx + 0x34);
|
||||
@@ -279,7 +276,7 @@ fn readFileDetour(
|
||||
bytes_read_out: ?*u32,
|
||||
async_ptr: u32,
|
||||
param6: u32,
|
||||
) callconv(sc) u32 {
|
||||
) callconv(hook.cc.stdcall) u32 {
|
||||
if (isFakeFileContext(ctx)) {
|
||||
const data_ptr = hook.readMem(u32, ctx + 0x30);
|
||||
const data_size = hook.readMem(u32, ctx + 0x34);
|
||||
@@ -308,7 +305,7 @@ fn readFileDetour(
|
||||
|
||||
// --- Hook 4: processAsyncFileOperation (0x647350) ---
|
||||
|
||||
fn processAsyncDetour(param1: u32) callconv(fc) void {
|
||||
fn processAsyncDetour(param1: u32) callconv(hook.cc.fastcall) void {
|
||||
const ctx_addr = hook.readMem(u32, param1 + 0x08);
|
||||
|
||||
if (isFakeFileContext(ctx_addr)) {
|
||||
@@ -360,7 +357,7 @@ fn processAsyncDetour(param1: u32) callconv(fc) void {
|
||||
|
||||
// --- Hook 6: CleanupFileHandleResources (0x648730) ---
|
||||
|
||||
fn cleanupFileHandleDetour(file_ctx: u32) callconv(sc) void {
|
||||
fn cleanupFileHandleDetour(file_ctx: u32) callconv(hook.cc.stdcall) void {
|
||||
const fake = isFakeFileContext(file_ctx);
|
||||
if (fake) {
|
||||
const path_ptr = hook.readMem(u32, file_ctx + 0x0C);
|
||||
@@ -381,7 +378,7 @@ fn cleanupFileHandleDetour(file_ctx: u32) callconv(sc) void {
|
||||
|
||||
// --- Hook 5: loadModelFromFileAsync (0x71d4e0) ---
|
||||
|
||||
fn loadModelAsyncDetour(model: u32, file_handle: u32, should_use_callback: u32) callconv(tc) u32 {
|
||||
fn loadModelAsyncDetour(model: u32, file_handle: u32, should_use_callback: u32) callconv(hook.cc.thiscall) u32 {
|
||||
|
||||
// file_handle IS the file context address directly (Ghidra shows pointer* but
|
||||
// the assembly pushes it directly to GetFileSizeFromHandle - no dereference)
|
||||
@@ -404,7 +401,7 @@ fn loadModelAsyncDetour(model: u32, file_handle: u32, should_use_callback: u32)
|
||||
|
||||
// Allocate buffer via setCullMode (0x71f9a0) - same as original path
|
||||
// setCullMode is __fastcall(ECX=size), returns buffer pointer
|
||||
const buffer_addr = hook.fastcall(u32, 0x71f9a0, data_size, 0);
|
||||
const buffer_addr = hook.call(fn (u32) callconv(hook.cc.fastcall) u32, 0x71f9a0, .{data_size});
|
||||
if (buffer_addr == 0) {
|
||||
con.print("[file] setCullMode alloc failed\n");
|
||||
return 0;
|
||||
@@ -445,7 +442,7 @@ fn loadModelAsyncDetour(model: u32, file_handle: u32, should_use_callback: u32)
|
||||
|
||||
// Call processLoadedModelData directly - __fastcall(ECX=model)
|
||||
con.fmt("[file] calling processLoadedModelData(0x{x})...\n", .{model});
|
||||
const result = hook.fastcall(u32, 0x71d640, model, 0);
|
||||
const result = hook.call(fn (u32) callconv(hook.cc.fastcall) u32, 0x71d640, .{model});
|
||||
con.print("[file] processLoadedModelData returned\n");
|
||||
con.fmt("[file] result=0x{x}\n", .{result});
|
||||
|
||||
@@ -473,10 +470,10 @@ fn loadModelAsyncDetour(model: u32, file_handle: u32, should_use_callback: u32)
|
||||
// files are invisible to preloadFileWithFlags, so LoadAddonRecursive skips
|
||||
// Bindings.xml (and SavedVariables) for our addons.
|
||||
|
||||
const CheckFileExistenceFn = fn (u32, u32, u32) callconv(fc) u32;
|
||||
const CheckFileExistenceFn = fn (u32, u32, u32) callconv(hook.cc.fastcall) u32;
|
||||
var cfe_hook: hook.Detour(CheckFileExistenceFn) = .{};
|
||||
|
||||
fn checkFileExistenceDetour(filename_ptr: u32, flags: u32, output_buffer_ptr: u32) callconv(fc) u32 {
|
||||
fn checkFileExistenceDetour(filename_ptr: u32, flags: u32, output_buffer_ptr: u32) callconv(hook.cc.fastcall) u32 {
|
||||
if (filename_ptr != 0) {
|
||||
// Embedded DLL files
|
||||
const path: [*:0]const u8 = @ptrFromInt(filename_ptr);
|
||||
@@ -516,9 +513,9 @@ fn removeFileHooks() void {
|
||||
// Hook: LoadScriptFunctions (0x490250)
|
||||
// =============================================================================
|
||||
|
||||
var lsf_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var lsf_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
fn loadScriptFunctionsDetour() callconv(sc) void {
|
||||
fn loadScriptFunctionsDetour() callconv(hook.cc.stdcall) void {
|
||||
lsf_hook.callOriginal(.{});
|
||||
registerLuaFunctions();
|
||||
}
|
||||
@@ -528,9 +525,9 @@ fn loadScriptFunctionsDetour() callconv(sc) void {
|
||||
// Hook: GameEngine_MainInitialize (0x46a400)
|
||||
// =============================================================================
|
||||
|
||||
var engine_init_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var engine_init_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
fn engineInitDetour() callconv(sc) void {
|
||||
fn engineInitDetour() callconv(hook.cc.stdcall) void {
|
||||
engine_init_hook.callOriginal(.{});
|
||||
|
||||
if (build_opts.screenshot) {
|
||||
@@ -552,9 +549,9 @@ fn engineInitDetour() callconv(sc) void {
|
||||
// Fires on real character logout/disconnect only - NOT on /reload or map change.
|
||||
// =============================================================================
|
||||
|
||||
var logout_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var logout_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
fn logoutDetour() callconv(sc) void {
|
||||
fn logoutDetour() callconv(hook.cc.stdcall) void {
|
||||
con.print("[weirdutils] World_HandleLogoutCleanup -- player logout\n");
|
||||
|
||||
// Reset per-session state - only on real logout/disconnect, not /reload.
|
||||
@@ -580,7 +577,7 @@ fn logoutDetour() callconv(sc) void {
|
||||
// Hook: CGGameUI_Shutdown (0x490BD0)
|
||||
// =============================================================================
|
||||
|
||||
var shutdown_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var shutdown_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
|
||||
// =============================================================================
|
||||
// Module lifecycle - single table drives install, shutdown, and uninstall.
|
||||
@@ -615,7 +612,7 @@ const modules = [_]ModuleHooks{
|
||||
if (build_opts.screenshot) .{ .name = screenshot.module_name, .remove = screenshot.removeHook, .is_active = screenshot.isActive } else .{},
|
||||
};
|
||||
|
||||
fn shutdownDetour() callconv(sc) void {
|
||||
fn shutdownDetour() callconv(hook.cc.stdcall) void {
|
||||
con.print("[weirdutils] CGGameUI_Shutdown\n");
|
||||
// Per-session resets and remove_on_shutdown cleanup live in logoutDetour
|
||||
// (World_HandleLogoutCleanup) - fires on real logout/disconnect only, not /reload.
|
||||
|
||||
+13
-15
@@ -114,9 +114,7 @@ const DespawningEntity = struct {
|
||||
};
|
||||
var despawning: [MAX_DESPAWNING]?DespawningEntity = .{null} ** MAX_DESPAWNING;
|
||||
|
||||
const fc = std.builtin.CallingConvention{ .x86_fastcall = .{} };
|
||||
const sc = std.builtin.CallingConvention{ .x86_stdcall = .{} };
|
||||
const tc = std.builtin.CallingConvention{ .x86_thiscall = .{} };
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// Permission check - leader or raid officer required
|
||||
@@ -125,7 +123,7 @@ const tc = std.builtin.CallingConvention{ .x86_thiscall = .{} };
|
||||
/// Get local player GUID via GetPlayerGUID (0x468550).
|
||||
/// __fastcall(), no params, returns u64 via EDX:EAX.
|
||||
fn getPlayerGUID() u64 {
|
||||
return hook.call(fn () callconv(fc) u64, o.FN_GET_PLAYER_GUID, .{});
|
||||
return hook.call(fn () callconv(hook.cc.fastcall) u64, o.FN_GET_PLAYER_GUID, .{});
|
||||
}
|
||||
|
||||
/// Look up a player name from the name cache by GUID.
|
||||
@@ -133,7 +131,7 @@ fn getPlayerGUID() u64 {
|
||||
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 result = hook.call(fn (u32, u32, u32, u32, u32, u32, u32) callconv(tc) u32, o.FN_NAME_CACHE_LOOKUP, .{
|
||||
const result = hook.call(fn (u32, u32, u32, u32, u32, u32, u32) callconv(hook.cc.thiscall) u32, o.FN_NAME_CACHE_LOOKUP, .{
|
||||
o.NAME_CACHE_OBJ, guid_lo, guid_hi, @intFromPtr(&name_buf), 0, 0, 0,
|
||||
});
|
||||
return if (result != 0) @ptrFromInt(result) else null;
|
||||
@@ -247,7 +245,7 @@ fn getCursorTerrainPosition() ?Vec3 {
|
||||
@as(*align(1) u32, @ptrFromInt(world_frame + o.WF_HIT_TERRAIN_Z)).* = 0;
|
||||
|
||||
// UpdateHitTest - __fastcall(ECX=worldFrame)
|
||||
hook.fastcall(void, o.FN_UPDATE_HIT_TEST, world_frame, 0);
|
||||
hook.call(fn (u32) callconv(hook.cc.fastcall) void, o.FN_UPDATE_HIT_TEST, .{world_frame});
|
||||
|
||||
const hit_type = hook.readMem(u32, world_frame + o.WF_HIT_TYPE);
|
||||
const x = hook.readMem(f32, world_frame + o.WF_HIT_TERRAIN_X);
|
||||
@@ -286,7 +284,7 @@ fn getCursorTerrainPosition() ?Vec3 {
|
||||
|
||||
/// CreateEntityInstance_WithAttachment - __fastcall, RET 0x14.
|
||||
fn createEntityInstance(path: [*:0]const u8, pos: *[3]f32, facing: f32, flags: u32, update_now: u32) ?*anyopaque {
|
||||
const result = hook.call(fn ([*:0]const u8, *[3]f32, f32, u32, u32, u32, u32) callconv(fc) u32, o.FN_CREATE_ENTITY_INSTANCE, .{
|
||||
const result = hook.call(fn ([*:0]const u8, *[3]f32, f32, u32, u32, u32, u32) callconv(hook.cc.fastcall) u32, o.FN_CREATE_ENTITY_INSTANCE, .{
|
||||
path, pos, facing, flags, update_now, 0, 0,
|
||||
});
|
||||
return if (result != 0) @ptrFromInt(result) else null;
|
||||
@@ -294,7 +292,7 @@ fn createEntityInstance(path: [*:0]const u8, pos: *[3]f32, facing: f32, flags: u
|
||||
|
||||
/// CleanupEntity_ProcessAttachments - __fastcall(ECX=entity), no stack params.
|
||||
fn cleanupEntity(obj: *anyopaque) void {
|
||||
hook.call(fn (*anyopaque) callconv(fc) void, o.FN_CLEANUP_ENTITY, .{obj});
|
||||
hook.call(fn (*anyopaque) callconv(hook.cc.fastcall) void, o.FN_CLEANUP_ENTITY, .{obj});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -308,7 +306,7 @@ fn playAnimation(entity: *anyopaque, anim_id: u32, queue: bool) void {
|
||||
const model = hook.readMem(u32, entity_addr + 0x88);
|
||||
if (model == 0 or model < 0x10000) return;
|
||||
|
||||
hook.call(fn (u32, u32, u32, i32, u32, u32, u32, u32) callconv(tc) void, o.FN_PLAY_BONE_ANIMATION, .{
|
||||
hook.call(fn (u32, u32, u32, i32, u32, u32, u32, u32) callconv(hook.cc.thiscall) void, o.FN_PLAY_BONE_ANIMATION, .{
|
||||
model, 0xFFFFFFFF, anim_id, -1, 0, @as(u32, @bitCast(@as(f32, 1.0))), 1, @intFromBool(queue),
|
||||
});
|
||||
}
|
||||
@@ -405,7 +403,7 @@ fn spawnEntity(index: usize, pos: Vec3) bool {
|
||||
|
||||
/// SetUnitPositionAndOrientation - __fastcall(ECX=positionData, EDX=pos), 1 stack param.
|
||||
fn setUnitPositionAndOrientation(entity: *anyopaque, pos: *[3]f32, facing: f32) void {
|
||||
hook.call(fn (*anyopaque, *[3]f32, f32) callconv(fc) void, 0x698e20, .{ entity, pos, facing });
|
||||
hook.call(fn (*anyopaque, *[3]f32, f32) callconv(hook.cc.fastcall) void, 0x698e20, .{ entity, pos, facing });
|
||||
}
|
||||
|
||||
/// Remove only the live entity for a marker slot (def untouched).
|
||||
@@ -517,7 +515,7 @@ pub fn luaClearWorldMarker(L: lua.State) callconv(.c) u32 {
|
||||
}
|
||||
|
||||
const nargs = lua.gettop(L);
|
||||
const lua_type: *const fn (lua.State, i32) callconv(fc) i32 = @ptrFromInt(0x6F3400);
|
||||
const lua_type: *const fn (lua.State, i32) callconv(hook.cc.fastcall) i32 = @ptrFromInt(0x6F3400);
|
||||
|
||||
if (nargs == 0 or lua_type(L, 1) == 0) {
|
||||
// No args or nil - clear all
|
||||
@@ -729,12 +727,12 @@ pub fn luaCanSetMarkers(L: lua.State) callconv(.c) u32 {
|
||||
// World teardown hook
|
||||
// =============================================================================
|
||||
|
||||
var world_cleanup_hook: hook.Detour(fn () callconv(sc) void) = .{};
|
||||
var world_update_hook: hook.Detour(fn (u32) callconv(fc) void) = .{};
|
||||
var world_cleanup_hook: hook.Detour(fn () callconv(hook.cc.stdcall) void) = .{};
|
||||
var world_update_hook: hook.Detour(fn (u32) callconv(hook.cc.fastcall) void) = .{};
|
||||
|
||||
/// OnWorldUpdate hook - per-frame tick while world is active.
|
||||
/// Drives animation state (Hold queue after Stand, despawn cleanup).
|
||||
fn worldUpdateDetour(frame: u32) callconv(fc) void {
|
||||
fn worldUpdateDetour(frame: u32) callconv(hook.cc.fastcall) void {
|
||||
tickAnimations();
|
||||
world_update_hook.callOriginal(.{frame});
|
||||
}
|
||||
@@ -744,7 +742,7 @@ fn worldUpdateDetour(frame: u32) callconv(fc) void {
|
||||
/// game's teardown runs - the same pattern every native caller uses (e.g.
|
||||
/// processCinematicExit, DestroyPathObjectIfPresent). This unlinks them from
|
||||
/// the WDOODADDEF hash table so the atexit handler never touches freed memory.
|
||||
fn worldCleanupDetour() callconv(sc) void {
|
||||
fn worldCleanupDetour() callconv(hook.cc.stdcall) void {
|
||||
con.print("[worldmarkers] >>> worldCleanupDetour FIRING <<<\n");
|
||||
destroyAllEntities();
|
||||
world_cleanup_hook.callOriginal(.{});
|
||||
|
||||
@@ -19,9 +19,6 @@ const lua = @import("../lua.zig");
|
||||
const con = @import("../console.zig");
|
||||
const mod_mutex = @import("../mutex.zig");
|
||||
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
|
||||
pub const module_name: [*:0]const u8 = "minimapicons";
|
||||
|
||||
@@ -248,7 +245,7 @@ const CStatus = extern struct {
|
||||
}
|
||||
|
||||
fn deinit(self: *CStatus) void {
|
||||
const f: *const fn (*CStatus) callconv(tc) void = @ptrFromInt(ADDR.CStatusDestructor);
|
||||
const f: *const fn (*CStatus) callconv(hook.cc.thiscall) void = @ptrFromInt(ADDR.CStatusDestructor);
|
||||
f(self);
|
||||
}
|
||||
};
|
||||
@@ -365,7 +362,7 @@ fn isValidPtr(addr: u32) bool {
|
||||
|
||||
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(sc) u32, ADDR.GetObjectByGUID, .{ guid_lo, guid_hi });
|
||||
return hook.call(fn (u32, u32) callconv(hook.cc.stdcall) u32, ADDR.GetObjectByGUID, .{ guid_lo, guid_hi });
|
||||
}
|
||||
|
||||
fn getObjectType(obj: u32) u32 {
|
||||
@@ -461,7 +458,7 @@ fn getSummonedByGUID(obj: u32) u64 {
|
||||
}
|
||||
|
||||
fn getActivePlayerGUID() u64 {
|
||||
return hook.call(fn () callconv(fc) u64, ADDR.ClntObjMgrGetActivePlayer, .{});
|
||||
return hook.call(fn () callconv(hook.cc.fastcall) u64, ADDR.ClntObjMgrGetActivePlayer, .{});
|
||||
}
|
||||
|
||||
fn getActivePlayerObject() u32 {
|
||||
@@ -473,7 +470,7 @@ fn getActivePlayerObject() u32 {
|
||||
/// UnitReaction: __thiscall(localPlayer_ECX, unit_stack) -> int (>=4 = friendly).
|
||||
fn unitReaction(local_player: u32, unit: u32) i32 {
|
||||
if (local_player == 0 or unit == 0) return 0;
|
||||
return hook.call(fn (u32, u32) callconv(tc) i32, ADDR.UnitReaction, .{ local_player, unit });
|
||||
return hook.call(fn (u32, u32) callconv(hook.cc.thiscall) i32, ADDR.UnitReaction, .{ local_player, unit });
|
||||
}
|
||||
|
||||
/// Check if a unit passes faction/friendliness filters.
|
||||
@@ -514,7 +511,7 @@ fn isUnitAllowed(obj: u32, local_player: u32) bool {
|
||||
/// CallSpellCastHandler: __fastcall(obj_ECX) -> char (bool via virtual dispatch).
|
||||
/// This is what IsValidInteractionTarget uses for type 0x21 (GO).
|
||||
fn isGoInteractable(obj: u32) bool {
|
||||
const result: u8 = @truncate(hook.call(fn (u32) callconv(fc) u32, ADDR.CallSpellCastHandler, .{obj}));
|
||||
const result: u8 = @truncate(hook.call(fn (u32) callconv(hook.cc.fastcall) u32, ADDR.CallSpellCastHandler, .{obj}));
|
||||
if (result == 0) {
|
||||
con.fmt("[minimapicons] GO 0x{x} rejected: not interactable (entry={d})\n", .{ obj, getObjectEntry(obj) });
|
||||
}
|
||||
@@ -549,7 +546,7 @@ fn getObjectPosition(obj: u32) ?C3Vector {
|
||||
if (!isValidPtr(get_pos_fn)) return null;
|
||||
var pos: C3Vector = undefined;
|
||||
// __thiscall(obj_ECX, &pos_stack) → C3Vector*
|
||||
_ = hook.call(fn (u32, *C3Vector) callconv(tc) u32, get_pos_fn, .{ obj, &pos });
|
||||
_ = hook.call(fn (u32, *C3Vector) callconv(hook.cc.thiscall) u32, get_pos_fn, .{ obj, &pos });
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -569,7 +566,7 @@ fn worldPosToMinimapCoords(
|
||||
// WorldPosToMinimapFrameCoords: __fastcall(out_ECX, edx, C3Vector cur, float radius,
|
||||
// float worldX, float worldY, float layoutScale, float unkScale)
|
||||
// EDX unused — use thiscall (ECX=this, rest on stack)
|
||||
_ = hook.call(fn (*C2Vector, f32, f32, f32, f32, f32, f32, f32, f32) callconv(tc) u32, ADDR.WorldPosToMinimapCoords, .{
|
||||
_ = hook.call(fn (*C2Vector, f32, f32, f32, f32, f32, f32, f32, f32) callconv(hook.cc.thiscall) u32, ADDR.WorldPosToMinimapCoords, .{
|
||||
out, cur.x, cur.y, cur.z, radius, world_x, world_y, layout_scale, unk_scale,
|
||||
});
|
||||
}
|
||||
@@ -583,7 +580,7 @@ fn getFrameUnkScale(info: u32) f32 {
|
||||
const fn_addr = hook.readMem(u32, vtable + 7 * 4);
|
||||
if (!isValidPtr(fn_addr)) return 1.0;
|
||||
// __thiscall(fsp_ECX) → f32 on FPU ST(0)
|
||||
return hook.call(fn (u32) callconv(tc) f32, fn_addr, .{fsp});
|
||||
return hook.call(fn (u32) callconv(hook.cc.thiscall) f32, fn_addr, .{fsp});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -621,7 +618,7 @@ fn loadTexture(path: [*:0]const u8) u32 {
|
||||
defer status.deinit();
|
||||
|
||||
// TextureCreate: __fastcall(filename_ECX, status_EDX, texFlags, unk1, unk2)
|
||||
const texture = hook.call(fn ([*:0]const u8, *CStatus, u32, u32, u32) callconv(fc) u32, ADDR.TextureCreate, .{
|
||||
const texture = hook.call(fn ([*:0]const u8, *CStatus, u32, u32, u32) callconv(hook.cc.fastcall) u32, ADDR.TextureCreate, .{
|
||||
path, &status, g_default_tex_flags, 0, 1,
|
||||
});
|
||||
|
||||
@@ -642,7 +639,7 @@ fn initTexFlags() u32 {
|
||||
var flags: u32 = 0;
|
||||
// CGxTexFlags constructor: __thiscall(this, filter=0, wrapU=0, wrapV=0,
|
||||
// forceMipTracking=0, generateMipMaps=0, renderTarget=0, maxAnisotropy=0, unknownFlag=1)
|
||||
hook.call(fn (*u32, u32, u32, u32, u32, u32, u32, u32, u32) callconv(tc) void, ADDR.CGxTexFlagsInit, .{
|
||||
hook.call(fn (*u32, u32, u32, u32, u32, u32, u32, u32, u32) callconv(hook.cc.thiscall) void, ADDR.CGxTexFlagsInit, .{
|
||||
&flags, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
});
|
||||
return flags;
|
||||
@@ -658,7 +655,7 @@ fn getGxTex(texture: u32) u32 {
|
||||
status.init();
|
||||
defer status.deinit();
|
||||
|
||||
const gx_tex = hook.call(fn (u32, u32, *CStatus) callconv(fc) u32, ADDR.TextureGetGxTex, .{
|
||||
const gx_tex = hook.call(fn (u32, u32, *CStatus) callconv(hook.cc.fastcall) u32, ADDR.TextureGetGxTex, .{
|
||||
texture, 1, &status,
|
||||
});
|
||||
|
||||
@@ -683,7 +680,7 @@ fn drawMinimapBlip(pos: C2Vector, scale: f32) void {
|
||||
|
||||
// GxPrimLockVertexPtrs(count=4, vertices, vertStride=12, normal, 0, color, 0,
|
||||
// null, 0, texCoords, 8, null, 0)
|
||||
hook.call(fn (u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32) callconv(fc) void, ADDR.GxPrimLockVertexPtrs, .{
|
||||
hook.call(fn (u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32) callconv(hook.cc.fastcall) void, ADDR.GxPrimLockVertexPtrs, .{
|
||||
4, // count (ECX)
|
||||
@intFromPtr(&vertices), // vertices (EDX)
|
||||
12, // vertStride
|
||||
@@ -700,7 +697,7 @@ fn drawMinimapBlip(pos: C2Vector, scale: f32) void {
|
||||
});
|
||||
|
||||
// GxPrimDrawElements(TriangleStrip=4, count=4, indices)
|
||||
const drawElements: *const fn (u32, u32, u32) callconv(fc) void = @ptrFromInt(ADDR.GxPrimDrawElements);
|
||||
const drawElements: *const fn (u32, u32, u32) callconv(hook.cc.fastcall) void = @ptrFromInt(ADDR.GxPrimDrawElements);
|
||||
drawElements(4, 4, ADDR.BlipVertIndices);
|
||||
|
||||
// GxPrimUnlockVertexPtrs()
|
||||
@@ -901,7 +898,7 @@ fn refreshActiveTrackingCache() void {
|
||||
// ObjectEnumProc: __fastcall(MINIMAPINFO* ECX, unused EDX, u64 guid on stack)
|
||||
// When guid is u64, MSVC fastcall skips EDX and puts the 8 bytes on stack.
|
||||
// In Zig fastcall with 4 u32 params: ECX=info, EDX=_edx, stack=guid_lo,guid_hi → RET 8.
|
||||
const EnumProcFn = fn (u32, u32, u32, u32) callconv(fc) i32;
|
||||
const EnumProcFn = fn (u32, u32, u32, u32) callconv(hook.cc.fastcall) i32;
|
||||
var enum_proc_hook: hook.Detour(EnumProcFn) = .{};
|
||||
|
||||
fn isInCity() bool {
|
||||
@@ -912,7 +909,7 @@ fn isInCity() bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn objectEnumProcDetour(info: u32, _edx: u32, guid_lo: u32, guid_hi: u32) callconv(fc) i32 {
|
||||
fn objectEnumProcDetour(info: u32, _edx: u32, guid_lo: u32, guid_hi: u32) callconv(hook.cc.fastcall) i32 {
|
||||
if (g_has_active_tracking and !(g_city_toggle and isInCity())) {
|
||||
if (checkObject(info, guid_lo, guid_hi)) {
|
||||
return 1; // Skip original — we draw our own icon
|
||||
@@ -923,10 +920,10 @@ fn objectEnumProcDetour(info: u32, _edx: u32, guid_lo: u32, guid_hi: u32) callco
|
||||
|
||||
// RenderObjectBlips: __thiscall(CGMinimapFrame* ECX, DNInfo* stack)
|
||||
// Hooked via fastcall with explicit EDX placeholder.
|
||||
const RenderBlipsFn = fn (u32, u32, u32) callconv(fc) void;
|
||||
const RenderBlipsFn = fn (u32, u32, u32) callconv(hook.cc.fastcall) void;
|
||||
var render_blips_hook: hook.Detour(RenderBlipsFn) = .{};
|
||||
|
||||
fn renderObjectBlipsDetour(thisptr: u32, _edx: u32, dn_info: u32) callconv(fc) void {
|
||||
fn renderObjectBlipsDetour(thisptr: u32, _edx: u32, dn_info: u32) callconv(hook.cc.fastcall) void {
|
||||
render_blips_hook.callOriginal(.{ thisptr, _edx, dn_info });
|
||||
|
||||
const count = g_blip_count;
|
||||
@@ -957,7 +954,7 @@ fn renderObjectBlipsDetour(thisptr: u32, _edx: u32, dn_info: u32) callconv(fc) v
|
||||
continue;
|
||||
}
|
||||
|
||||
const gxRsSet: *const fn (u32, u32) callconv(fc) void = @ptrFromInt(ADDR.GxRsSet);
|
||||
const gxRsSet: *const fn (u32, u32) callconv(hook.cc.fastcall) void = @ptrFromInt(ADDR.GxRsSet);
|
||||
gxRsSet(23, gx_tex);
|
||||
|
||||
// Draw all blips sharing this texture
|
||||
@@ -968,10 +965,10 @@ fn renderObjectBlipsDetour(thisptr: u32, _edx: u32, dn_info: u32) callconv(fc) v
|
||||
}
|
||||
|
||||
// ClntObjMgrEnumVisibleObjects: __fastcall(callback ECX, context EDX)
|
||||
const EnumVisFn = fn (u32, u32) callconv(fc) i32;
|
||||
const EnumVisFn = fn (u32, u32) callconv(hook.cc.fastcall) i32;
|
||||
var enum_vis_hook: hook.Detour(EnumVisFn) = .{};
|
||||
|
||||
fn enumVisibleObjectsDetour(callback: u32, context: u32) callconv(fc) i32 {
|
||||
fn enumVisibleObjectsDetour(callback: u32, context: u32) callconv(hook.cc.fastcall) i32 {
|
||||
// Clear tracked blips when the minimap's own callback is about to enumerate
|
||||
if (callback == ADDR.ObjectEnumProc) {
|
||||
g_blip_count = 0;
|
||||
@@ -1007,7 +1004,7 @@ fn luaStringToSlice(L: lua.State, idx: i32) ?[]const u8 {
|
||||
}
|
||||
|
||||
// SetObjectTypeBlip(typeName [, texturePath [, scale [, includeFilter [, excludeFilter]]]])
|
||||
pub fn luaSetObjectTypeBlip(L: lua.State) callconv(fc) i32 {
|
||||
pub fn luaSetObjectTypeBlip(L: lua.State) callconv(hook.cc.fastcall) i32 {
|
||||
defer refreshActiveTrackingCache();
|
||||
|
||||
if (!lua.isstring(L, 1)) {
|
||||
@@ -1130,7 +1127,7 @@ pub fn luaSetObjectTypeBlip(L: lua.State) callconv(fc) i32 {
|
||||
}
|
||||
|
||||
// SetMinimapCityToggle(enabled) — suppress NPC/GO tracking in capital cities
|
||||
pub fn luaSetCityToggle(L: lua.State) callconv(fc) i32 {
|
||||
pub fn luaSetCityToggle(L: lua.State) callconv(hook.cc.fastcall) i32 {
|
||||
g_city_toggle = lua.isnumber(L, 1) and lua.tonumber(L, 1) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-4
@@ -72,13 +72,13 @@ pub fn isEnabled() bool {
|
||||
/// OutlineCommand("on") → enable outlines
|
||||
/// OutlineCommand("off") → disable outlines
|
||||
pub fn outlineCommand(L: *anyopaque) callconv(.c) u32 {
|
||||
const nargs = hook.fastcall(i32, 0x6F3070, @intFromPtr(L), @as(u32, 0)); // lua_gettop
|
||||
const nargs = hook.call(fn (usize) callconv(hook.cc.fastcall) i32, 0x6F3070, .{@intFromPtr(L)}); // lua_gettop
|
||||
|
||||
if (nargs >= 1) {
|
||||
// Check if first arg is a string
|
||||
const is_str = hook.fastcall(u32, 0x6F3510, @intFromPtr(L), @as(u32, 1)); // lua_isstring
|
||||
const is_str = hook.call(fn (usize, u32) callconv(hook.cc.fastcall) u32, 0x6F3510, .{ @intFromPtr(L), 1 }); // lua_isstring
|
||||
if (is_str != 0) {
|
||||
const str_ptr = hook.fastcall(u32, 0x6F3690, @intFromPtr(L), @as(u32, 1)); // lua_tostring
|
||||
const str_ptr = hook.call(fn (usize, u32) callconv(hook.cc.fastcall) u32, 0x6F3690, .{ @intFromPtr(L), 1 }); // lua_tostring
|
||||
if (str_ptr != 0) {
|
||||
const s: [*:0]const u8 = @ptrFromInt(str_ptr);
|
||||
const span = @import("std").mem.span(s);
|
||||
@@ -92,7 +92,7 @@ pub fn outlineCommand(L: *anyopaque) callconv(.c) u32 {
|
||||
}
|
||||
|
||||
// Push current state as boolean
|
||||
hook.fastcall(void, 0x6F39F0, @intFromPtr(L), @as(u32, if (isEnabled()) 1 else 0)); // lua_pushboolean
|
||||
hook.call(fn (usize, u32) callconv(hook.cc.fastcall) void, 0x6F39F0, .{ @intFromPtr(L), @as(u32, if (isEnabled()) 1 else 0) }); // lua_pushboolean
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+43
-44
@@ -20,7 +20,6 @@ const tracker = @import("tracker.zig");
|
||||
const model_hook = @import("model_hook.zig");
|
||||
|
||||
const WINAPI = std.builtin.CallingConvention.winapi;
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
|
||||
// =============================================================================
|
||||
// Windows / D3D9 externs
|
||||
@@ -39,7 +38,7 @@ inline fn vt(obj: *anyopaque) [*]usize {
|
||||
|
||||
/// Call a COM method that takes only (self) and returns HRESULT.
|
||||
fn comCall0(obj: *anyopaque, idx: usize) i32 {
|
||||
const f: *const fn (*anyopaque) callconv(sc) i32 = @ptrFromInt(vt(obj)[idx]);
|
||||
const f: *const fn (*anyopaque) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vt(obj)[idx]);
|
||||
return f(obj);
|
||||
}
|
||||
|
||||
@@ -86,7 +85,7 @@ const D3DXAssembleShaderFn = *const fn (
|
||||
u32, // Flags
|
||||
*?*anyopaque, // ppShader (ID3DXBuffer**)
|
||||
*?*anyopaque, // ppErrorMsgs (ID3DXBuffer**)
|
||||
) callconv(sc) i32;
|
||||
) callconv(hook.cc.stdcall) i32;
|
||||
|
||||
// =============================================================================
|
||||
// Render target resources
|
||||
@@ -161,108 +160,108 @@ const QuadVertex = extern struct {
|
||||
// =============================================================================
|
||||
|
||||
fn deviceSetRS(dev: *anyopaque, state: u32, value: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, u32) callconv(sc) i32 = @ptrFromInt(vt(dev)[types.VT.SetRenderState]);
|
||||
const f: *const fn (*anyopaque, u32, u32) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vt(dev)[types.VT.SetRenderState]);
|
||||
_ = f(dev, state, value);
|
||||
}
|
||||
|
||||
fn deviceGetRS(dev: *anyopaque, state: u32) u32 {
|
||||
var val: u32 = 0;
|
||||
const f: *const fn (*anyopaque, u32, *u32) callconv(sc) i32 = @ptrFromInt(vt(dev)[types.VT.GetRenderState]);
|
||||
const f: *const fn (*anyopaque, u32, *u32) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vt(dev)[types.VT.GetRenderState]);
|
||||
_ = f(dev, state, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
fn deviceSetPtr(dev: *anyopaque, idx: usize, ptr: *anyopaque) void {
|
||||
const f: *const fn (*anyopaque, *anyopaque) callconv(sc) i32 = @ptrFromInt(vt(dev)[idx]);
|
||||
const f: *const fn (*anyopaque, *anyopaque) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vt(dev)[idx]);
|
||||
_ = f(dev, ptr);
|
||||
}
|
||||
|
||||
fn deviceGetPtr(dev: *anyopaque, idx: usize) ?*anyopaque {
|
||||
var ptr: ?*anyopaque = null;
|
||||
const f: *const fn (*anyopaque, *?*anyopaque) callconv(sc) i32 = @ptrFromInt(vt(dev)[idx]);
|
||||
const f: *const fn (*anyopaque, *?*anyopaque) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vt(dev)[idx]);
|
||||
_ = f(dev, &ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// Set a COM pointer, handling null via optional pointer (ABI-equivalent to passing 0).
|
||||
fn deviceSetPtrOrNull(dev: *anyopaque, idx: usize, ptr: ?*anyopaque) void {
|
||||
const f: *const fn (*anyopaque, ?*anyopaque) callconv(sc) i32 = @ptrFromInt(vt(dev)[idx]);
|
||||
const f: *const fn (*anyopaque, ?*anyopaque) callconv(hook.cc.stdcall) i32 = @ptrFromInt(vt(dev)[idx]);
|
||||
_ = @call(.never_tail, f, .{ dev, ptr });
|
||||
}
|
||||
|
||||
fn deviceSetPSConstF(dev: *anyopaque, start: u32, data: *const [4]f32) void {
|
||||
const f: *const fn (*anyopaque, u32, *const [4]f32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *const [4]f32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetPixelShaderConstantF]);
|
||||
_ = f(dev, start, data, 1);
|
||||
}
|
||||
|
||||
fn deviceGetPSConstF(dev: *anyopaque, start: u32, data: *[4]f32) void {
|
||||
const f: *const fn (*anyopaque, u32, *[4]f32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *[4]f32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetPixelShaderConstantF]);
|
||||
_ = f(dev, start, data, 1);
|
||||
}
|
||||
|
||||
fn deviceGetViewport(dev: *anyopaque, vp_out: *types.D3DVIEWPORT9) void {
|
||||
const f: *const fn (*anyopaque, *types.D3DVIEWPORT9) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, *types.D3DVIEWPORT9) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetViewport]);
|
||||
_ = f(dev, vp_out);
|
||||
}
|
||||
|
||||
fn deviceSetRenderTarget(dev: *anyopaque, idx: u32, surf: *anyopaque) void {
|
||||
const f: *const fn (*anyopaque, u32, *anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetRenderTarget]);
|
||||
_ = f(dev, idx, surf);
|
||||
}
|
||||
|
||||
fn deviceGetRenderTarget(dev: *anyopaque, idx: u32) ?*anyopaque {
|
||||
var surf: ?*anyopaque = null;
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetRenderTarget]);
|
||||
_ = f(dev, idx, &surf);
|
||||
return surf;
|
||||
}
|
||||
|
||||
fn deviceSetTexture(dev: *anyopaque, stage: u32, tex: ?*anyopaque) void {
|
||||
const f: *const fn (*anyopaque, u32, ?*anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, ?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetTexture]);
|
||||
_ = @call(.never_tail, f, .{ dev, stage, tex });
|
||||
}
|
||||
|
||||
fn deviceSetFVF(dev: *anyopaque, fvf: u32) void {
|
||||
const f: *const fn (*anyopaque, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetFVF]);
|
||||
_ = f(dev, fvf);
|
||||
}
|
||||
|
||||
fn deviceGetSamplerState(dev: *anyopaque, sampler: u32, state_type: u32) u32 {
|
||||
var val: u32 = 0;
|
||||
const f: *const fn (*anyopaque, u32, u32, *u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, u32, *u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetSamplerState]);
|
||||
_ = f(dev, sampler, state_type, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
fn deviceSetSamplerState(dev: *anyopaque, sampler: u32, state_type: u32, value: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, u32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, u32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetSamplerState]);
|
||||
_ = f(dev, sampler, state_type, value);
|
||||
}
|
||||
|
||||
fn deviceGetStreamSource(dev: *anyopaque, stream: u32, vb_out: *?*anyopaque, offset_out: *u32, stride_out: *u32) void {
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque, *u32, *u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque, *u32, *u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetStreamSource]);
|
||||
_ = f(dev, stream, vb_out, offset_out, stride_out);
|
||||
}
|
||||
|
||||
fn deviceSetStreamSource(dev: *anyopaque, stream: u32, vb: ?*anyopaque, offset: u32, stride: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, ?*anyopaque, u32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, ?*anyopaque, u32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetStreamSource]);
|
||||
_ = @call(.never_tail, f, .{ dev, stream, vb, offset, stride });
|
||||
}
|
||||
|
||||
fn deviceGetTexture(dev: *anyopaque, stage: u32) ?*anyopaque {
|
||||
var tex: ?*anyopaque = null;
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetTexture]);
|
||||
_ = f(dev, stage, &tex);
|
||||
return tex;
|
||||
@@ -270,38 +269,38 @@ fn deviceGetTexture(dev: *anyopaque, stage: u32) ?*anyopaque {
|
||||
|
||||
fn deviceGetIndices(dev: *anyopaque) ?*anyopaque {
|
||||
var ib: ?*anyopaque = null;
|
||||
const f: *const fn (*anyopaque, *?*anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetIndices]);
|
||||
_ = f(dev, &ib);
|
||||
return ib;
|
||||
}
|
||||
|
||||
fn deviceSetIndices(dev: *anyopaque, ib: ?*anyopaque) void {
|
||||
const f: *const fn (*anyopaque, ?*anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, ?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetIndices]);
|
||||
_ = @call(.never_tail, f, .{ dev, ib });
|
||||
}
|
||||
|
||||
fn deviceGetVSConstF(dev: *anyopaque, start: u32, data: [*][4]f32, count: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, [*][4]f32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, [*][4]f32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.GetVertexShaderConstantF]);
|
||||
_ = f(dev, start, data, count);
|
||||
}
|
||||
|
||||
fn deviceSetVSConstF(dev: *anyopaque, start: u32, data: [*]const [4]f32, count: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, [*]const [4]f32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, [*]const [4]f32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.SetVertexShaderConstantF]);
|
||||
_ = f(dev, start, data, count);
|
||||
}
|
||||
|
||||
fn deviceDrawPrimitiveUP(dev: *anyopaque, prim_type: u32, prim_count: u32, data: *const anyopaque, stride: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, u32, *const anyopaque, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, u32, *const anyopaque, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.DrawPrimitiveUP]);
|
||||
_ = f(dev, prim_type, prim_count, data, stride);
|
||||
}
|
||||
|
||||
fn deviceCreateTexture(dev: *anyopaque, w: u32, h: u32, levels: u32, usage: u32, fmt: u32, pool: u32, out: *?*anyopaque) i32 {
|
||||
const f: *const fn (*anyopaque, u32, u32, u32, u32, u32, u32, *?*anyopaque, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, u32, u32, u32, u32, u32, *?*anyopaque, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.CreateTexture]);
|
||||
return f(dev, w, h, levels, usage, fmt, pool, out, 0);
|
||||
}
|
||||
@@ -310,7 +309,7 @@ fn deviceCreateTexture(dev: *anyopaque, w: u32, h: u32, levels: u32, usage: u32,
|
||||
fn textureGetSurfaceLevel(tex: *anyopaque) ?*anyopaque {
|
||||
// IDirect3DTexture9::GetSurfaceLevel is vtable index 18
|
||||
var surf: ?*anyopaque = null;
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(tex)[18]);
|
||||
if (f(tex, 0, &surf) < 0) return null;
|
||||
return surf;
|
||||
@@ -318,7 +317,7 @@ fn textureGetSurfaceLevel(tex: *anyopaque) ?*anyopaque {
|
||||
|
||||
/// Clear the current render target to a colour.
|
||||
fn clearRenderTarget(dev: *anyopaque, color: u32) void {
|
||||
const f: *const fn (*anyopaque, u32, ?*anyopaque, u32, u32, f32, u32) callconv(sc) i32 =
|
||||
const f: *const fn (*anyopaque, u32, ?*anyopaque, u32, u32, f32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(dev)[types.VT.Clear]);
|
||||
_ = f(dev, 0, null, types.D3DCLEAR_TARGET, color, 1.0, 0);
|
||||
}
|
||||
@@ -618,10 +617,10 @@ fn assemblePS(device: *anyopaque, assemble: D3DXAssembleShaderFn, src: [*]const
|
||||
|
||||
// ID3DXBuffer::GetBufferPointer is vtable[3]
|
||||
const buf_ptr: *anyopaque = @ptrFromInt(
|
||||
@as(*const fn (*anyopaque) callconv(sc) usize, @ptrFromInt(vt(code.?)[3]))(code.?),
|
||||
@as(*const fn (*anyopaque) callconv(hook.cc.stdcall) usize, @ptrFromInt(vt(code.?)[3]))(code.?),
|
||||
);
|
||||
var ps_out: ?*anyopaque = null;
|
||||
const create: *const fn (*anyopaque, *anyopaque, *?*anyopaque) callconv(sc) i32 =
|
||||
const create: *const fn (*anyopaque, *anyopaque, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(device)[types.VT.CreatePixelShader]);
|
||||
if (create(device, buf_ptr, &ps_out) < 0) return null;
|
||||
return ps_out;
|
||||
@@ -657,7 +656,7 @@ fn buildFullscreenQuad(w: u32, h: u32) [4]QuadVertex {
|
||||
// EndScene hook
|
||||
// =============================================================================
|
||||
|
||||
fn hkEndScene(device: *anyopaque) callconv(sc) i32 {
|
||||
fn hkEndScene(device: *anyopaque) callconv(hook.cc.stdcall) i32 {
|
||||
// One-time: check if depth/stencil surface has stencil bits.
|
||||
if (need_force_reset) {
|
||||
need_force_reset = false;
|
||||
@@ -686,7 +685,7 @@ fn hkEndScene(device: *anyopaque) callconv(sc) i32 {
|
||||
frame_has_outlines = false;
|
||||
|
||||
// Call original EndScene
|
||||
const f: *const fn (*anyopaque) callconv(sc) i32 = @ptrFromInt(orig_endscene);
|
||||
const f: *const fn (*anyopaque) callconv(hook.cc.stdcall) i32 = @ptrFromInt(orig_endscene);
|
||||
return f(device);
|
||||
}
|
||||
|
||||
@@ -694,7 +693,7 @@ fn hkEndScene(device: *anyopaque) callconv(sc) i32 {
|
||||
// Reset hook - force D24S8 depth/stencil format, release resources
|
||||
// =============================================================================
|
||||
|
||||
fn hkReset(device: *anyopaque, pp: *types.D3DPRESENT_PARAMETERS) callconv(sc) i32 {
|
||||
fn hkReset(device: *anyopaque, pp: *types.D3DPRESENT_PARAMETERS) callconv(hook.cc.stdcall) i32 {
|
||||
if (pp.EnableAutoDepthStencil != 0) {
|
||||
const fmt = pp.AutoDepthStencilFormat;
|
||||
if (fmt != types.D3DFMT_D24S8 and fmt != types.D3DFMT_D24FS8 and
|
||||
@@ -709,7 +708,7 @@ fn hkReset(device: *anyopaque, pp: *types.D3DPRESENT_PARAMETERS) callconv(sc) i3
|
||||
releaseShaders();
|
||||
releaseResources();
|
||||
|
||||
const f: *const fn (*anyopaque, *types.D3DPRESENT_PARAMETERS) callconv(sc) i32 = @ptrFromInt(orig_reset);
|
||||
const f: *const fn (*anyopaque, *types.D3DPRESENT_PARAMETERS) callconv(hook.cc.stdcall) i32 = @ptrFromInt(orig_reset);
|
||||
return f(device, pp);
|
||||
}
|
||||
|
||||
@@ -732,8 +731,8 @@ fn hkDIP(
|
||||
num_verts: u32,
|
||||
start_idx: u32,
|
||||
prim_count: u32,
|
||||
) callconv(sc) i32 {
|
||||
const OrigDIP = *const fn (*anyopaque, u32, i32, u32, u32, u32, u32) callconv(sc) i32;
|
||||
) callconv(hook.cc.stdcall) i32 {
|
||||
const OrigDIP = *const fn (*anyopaque, u32, i32, u32, u32, u32, u32) callconv(hook.cc.stdcall) i32;
|
||||
const origFn: OrigDIP = @ptrFromInt(orig_dip);
|
||||
|
||||
// ---- Cache outline draws for EndScene replay ----
|
||||
@@ -885,7 +884,7 @@ fn runJfaPipeline(device: *anyopaque) void {
|
||||
|
||||
// Depth-stencil surface
|
||||
var saved_ds: ?*anyopaque = null;
|
||||
const getDS: *const fn (*anyopaque, *?*anyopaque) callconv(sc) i32 =
|
||||
const getDS: *const fn (*anyopaque, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(device)[types.VT.GetDepthStencilSurface]);
|
||||
_ = getDS(device, &saved_ds);
|
||||
|
||||
@@ -935,7 +934,7 @@ fn runJfaPipeline(device: *anyopaque) void {
|
||||
// =====================================================================
|
||||
|
||||
if (cached_draw_count > 0) {
|
||||
const origFn: *const fn (*anyopaque, u32, i32, u32, u32, u32, u32) callconv(sc) i32 =
|
||||
const origFn: *const fn (*anyopaque, u32, i32, u32, u32, u32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(orig_dip);
|
||||
|
||||
deviceSetRenderTarget(device, 0, rt_silhouette_surf.?);
|
||||
@@ -985,7 +984,7 @@ fn runJfaPipeline(device: *anyopaque) void {
|
||||
|
||||
// Clear stencil marks to avoid affecting next frame's rendering
|
||||
deviceSetRS(device, types.D3DRS.STENCILENABLE, 0);
|
||||
const clearFn: *const fn (*anyopaque, u32, ?*anyopaque, u32, u32, f32, u32) callconv(sc) i32 =
|
||||
const clearFn: *const fn (*anyopaque, u32, ?*anyopaque, u32, u32, f32, u32) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(device)[types.VT.Clear]);
|
||||
_ = clearFn(device, 0, null, types.D3DCLEAR_STENCIL, 0, 1.0, 0);
|
||||
}
|
||||
@@ -1177,28 +1176,28 @@ fn hasStencilBits(fmt: u32) bool {
|
||||
|
||||
fn forceD24S8IfNeeded(device: *anyopaque) void {
|
||||
var pDS: ?*anyopaque = null;
|
||||
const getDS: *const fn (*anyopaque, *?*anyopaque) callconv(sc) i32 =
|
||||
const getDS: *const fn (*anyopaque, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(device)[types.VT.GetDepthStencilSurface]);
|
||||
if (getDS(device, &pDS) < 0) return;
|
||||
const ds = pDS orelse return;
|
||||
defer comRelease(ds);
|
||||
|
||||
var desc: types.D3DSURFACE_DESC = .{};
|
||||
const getDesc: *const fn (*anyopaque, *types.D3DSURFACE_DESC) callconv(sc) i32 =
|
||||
const getDesc: *const fn (*anyopaque, *types.D3DSURFACE_DESC) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(ds)[12]);
|
||||
if (getDesc(ds, &desc) < 0) return;
|
||||
|
||||
if (hasStencilBits(desc.Format)) return;
|
||||
|
||||
var pSwap: ?*anyopaque = null;
|
||||
const getSC: *const fn (*anyopaque, u32, *?*anyopaque) callconv(sc) i32 =
|
||||
const getSC: *const fn (*anyopaque, u32, *?*anyopaque) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(device)[types.VT.GetSwapChain]);
|
||||
if (getSC(device, 0, &pSwap) < 0) return;
|
||||
const swap = pSwap orelse return;
|
||||
defer comRelease(swap);
|
||||
|
||||
var pp: types.D3DPRESENT_PARAMETERS = .{};
|
||||
const getPP: *const fn (*anyopaque, *types.D3DPRESENT_PARAMETERS) callconv(sc) i32 =
|
||||
const getPP: *const fn (*anyopaque, *types.D3DPRESENT_PARAMETERS) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(swap)[9]);
|
||||
if (getPP(swap, &pp) < 0) return;
|
||||
|
||||
@@ -1208,7 +1207,7 @@ fn forceD24S8IfNeeded(device: *anyopaque) void {
|
||||
releaseShaders();
|
||||
releaseResources();
|
||||
|
||||
const resetFn: *const fn (*anyopaque, *types.D3DPRESENT_PARAMETERS) callconv(sc) i32 =
|
||||
const resetFn: *const fn (*anyopaque, *types.D3DPRESENT_PARAMETERS) callconv(hook.cc.stdcall) i32 =
|
||||
@ptrFromInt(vt(device)[types.VT.Reset]);
|
||||
_ = resetFn(device, &pp);
|
||||
}
|
||||
|
||||
@@ -25,15 +25,14 @@ const wow = @import("wow.zig");
|
||||
// Calling convention constants
|
||||
// =============================================================================
|
||||
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
|
||||
// =============================================================================
|
||||
// Hook state
|
||||
// =============================================================================
|
||||
|
||||
const RenderDrawFn = fn (u32, u32, u32, u32, u32) callconv(tc) void;
|
||||
const ManageRenderFn = fn (u32, u32) callconv(tc) void;
|
||||
const DrawBatchFn = fn (u32) callconv(tc) void;
|
||||
const RenderDrawFn = fn (u32, u32, u32, u32, u32) callconv(hook.cc.thiscall) void;
|
||||
const ManageRenderFn = fn (u32, u32) callconv(hook.cc.thiscall) void;
|
||||
const DrawBatchFn = fn (u32) callconv(hook.cc.thiscall) void;
|
||||
|
||||
var render_draw_hook: hook.Detour(RenderDrawFn) = .{};
|
||||
var manage_render_hook: hook.Detour(ManageRenderFn) = .{};
|
||||
@@ -75,7 +74,7 @@ var reordered_indices: [MAX_REORDER]i32 = undefined;
|
||||
// through other players and gear (since those aren't in depth when stencil
|
||||
// is written). The outline composites on top of everything in EndScene.
|
||||
|
||||
fn renderDrawDetour(this: u32, view_matrix: u32, batch_data: u32, batch_indices: u32, batch_count: u32) callconv(tc) void {
|
||||
fn renderDrawDetour(this: u32, view_matrix: u32, batch_data: u32, batch_indices: u32, batch_count: u32) callconv(hook.cc.thiscall) void {
|
||||
// One-time: install D3D9 hooks now that the game is actively rendering.
|
||||
if (d3d9_deferred_pending) {
|
||||
d3d9_deferred_pending = false;
|
||||
@@ -147,7 +146,7 @@ fn renderDrawDetour(this: u32, view_matrix: u32, batch_data: u32, batch_indices:
|
||||
// __thiscall(model_ECX, addToList_stack)
|
||||
// Native thiscall detour - no thunk needed.
|
||||
|
||||
fn manageRenderDetour(model: u32, add_to_list: u32) callconv(tc) void {
|
||||
fn manageRenderDetour(model: u32, add_to_list: u32) callconv(hook.cc.thiscall) void {
|
||||
// Classify the model when it's being ADDED to the render list
|
||||
if (add_to_list == 1 and model != 0 and tracker.enabled and tracker.hasTargets()) {
|
||||
tracker.classifyModel(model);
|
||||
@@ -165,7 +164,7 @@ fn manageRenderDetour(model: u32, add_to_list: u32) callconv(tc) void {
|
||||
// wrong ret instructions for functions with ≤2 register params. The naked
|
||||
// function bridges fastcall → cdecl and calls the implementation function.
|
||||
|
||||
fn drawBatchProjDetour(ctx: u32) callconv(tc) void {
|
||||
fn drawBatchProjDetour(ctx: u32) callconv(hook.cc.thiscall) void {
|
||||
// Fast path: no tracking enabled or nothing tracked → just call original
|
||||
if (!tracker.enabled or !tracker.hasTargets()) {
|
||||
draw_batch_hook.callOriginal(.{ctx});
|
||||
|
||||
+3
-6
@@ -14,9 +14,6 @@ const types = @import("types.zig");
|
||||
// =============================================================================
|
||||
|
||||
const WINAPI = std.builtin.CallingConvention.winapi;
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
|
||||
extern "kernel32" fn IsBadReadPtr(
|
||||
lp: ?*const anyopaque,
|
||||
@@ -145,7 +142,7 @@ pub fn resolveModelOwner(model: u32) u32 {
|
||||
/// UnitGUID("player") / UnitGUID("target") → 64-bit GUID.
|
||||
/// __fastcall(unitIdStr_ECX) → EDX:EAX (u64).
|
||||
pub fn unitGUID(unit_id: [*:0]const u8) u64 {
|
||||
return hook.call(fn ([*:0]const u8) callconv(fc) u64, o.FN_UNIT_GUID, .{unit_id});
|
||||
return hook.call(fn ([*:0]const u8) callconv(hook.cc.fastcall) u64, o.FN_UNIT_GUID, .{unit_id});
|
||||
}
|
||||
|
||||
/// Resolve a GUID → object pointer via the object manager hash table.
|
||||
@@ -154,7 +151,7 @@ pub fn getObjectByGUID(guid: u64) u32 {
|
||||
if (guid == 0) return 0;
|
||||
const lo: u32 = @truncate(guid);
|
||||
const hi: u32 = @truncate(guid >> 32);
|
||||
return hook.call(fn (u32, u32) callconv(sc) u32, o.FN_GET_OBJECT_BY_GUID, .{ lo, hi });
|
||||
return hook.call(fn (u32, u32) callconv(hook.cc.stdcall) u32, o.FN_GET_OBJECT_BY_GUID, .{ lo, hi });
|
||||
}
|
||||
|
||||
/// Get the local player's object pointer.
|
||||
@@ -174,7 +171,7 @@ pub fn getTargetGUID() u64 {
|
||||
/// Reaction >= 4 means friendly.
|
||||
pub fn isUnitFriendly(unit: u32, local_player: u32) bool {
|
||||
if (unit == 0 or local_player == 0) return false;
|
||||
const reaction = hook.call(fn (u32, u32) callconv(tc) i32, o.FN_UNIT_REACTION, .{ local_player, unit });
|
||||
const reaction = hook.call(fn (u32, u32) callconv(hook.cc.thiscall) i32, o.FN_UNIT_REACTION, .{ local_player, unit });
|
||||
return reaction >= 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,23 +53,21 @@ const ERROR_ALREADY_EXISTS: u32 = 183;
|
||||
// State
|
||||
// =============================================================================
|
||||
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
|
||||
// CVar for compression level persistence (0–9, default 6)
|
||||
const CVAR_NAME = "screenshotQuality";
|
||||
const CVAR_LOOKUP: usize = 0x0063DEC0;
|
||||
const RegisterCVarFn = *const fn ([*:0]const u8, u32, u32, [*:0]const u8, u32, u32, u32, u32) callconv(fc) u32;
|
||||
const RegisterCVarFn = *const fn ([*:0]const u8, u32, u32, [*:0]const u8, u32, u32, u32, u32) callconv(hook.cc.fastcall) u32;
|
||||
const registerCVar: RegisterCVarFn = @ptrFromInt(0x0063DB90);
|
||||
|
||||
fn readCVarQuality() i32 {
|
||||
const cvar_ptr = hook.fastcall(u32, CVAR_LOOKUP, @intFromPtr(@as([*:0]const u8, CVAR_NAME)), @as(u32, 0));
|
||||
const cvar_ptr = hook.call(fn ([*:0]const u8) callconv(hook.cc.fastcall) u32, CVAR_LOOKUP, .{CVAR_NAME});
|
||||
if (cvar_ptr == 0) return 6;
|
||||
const val = hook.readMem(i32, cvar_ptr + 40);
|
||||
return std.math.clamp(val, 0, 9);
|
||||
}
|
||||
|
||||
const TgaWriteFn = fn (u32, u32) callconv(tc) i32;
|
||||
const TgaWriteFn = fn (u32, u32) callconv(hook.cc.thiscall) i32;
|
||||
var tga_hook: hook.Detour(TgaWriteFn) = .{};
|
||||
var screenshot_dir: [260]u8 = undefined;
|
||||
var screenshot_dir_len: usize = 0;
|
||||
@@ -153,7 +151,7 @@ fn callOriginal(self: u32, filename: u32) i32 {
|
||||
// Thunked from __fastcall(self_ECX, _EDX, filename_stack) → cdecl
|
||||
// =============================================================================
|
||||
|
||||
fn tgaWriteDetour(self: u32, filename: u32) callconv(tc) i32 {
|
||||
fn tgaWriteDetour(self: u32, filename: u32) callconv(hook.cc.thiscall) i32 {
|
||||
// CVar 0 = disabled, fall through to original TGA write
|
||||
const quality = readCVarQuality();
|
||||
if (quality == 0) return callOriginal(self, filename);
|
||||
|
||||
@@ -61,13 +61,13 @@ const DISPLAY_INFO_TABLE_PTR: usize = 0x00c0de90;
|
||||
// =============================================================================
|
||||
|
||||
fn unitGUID(unit_id: [*:0]const u8) u64 {
|
||||
return hook.call(fn ([*:0]const u8) callconv(fc) u64, ADDR_UnitGUID, .{unit_id});
|
||||
return hook.call(fn ([*:0]const u8) callconv(hook.cc.fastcall) u64, ADDR_UnitGUID, .{unit_id});
|
||||
}
|
||||
|
||||
fn getObjectByGUID(guid: u64) u32 {
|
||||
const lo: u32 = @truncate(guid);
|
||||
const hi: u32 = @truncate(guid >> 32);
|
||||
return hook.call(fn (u32, u32) callconv(sc) u32, ADDR_GetObjectByGUID, .{ lo, hi });
|
||||
return hook.call(fn (u32, u32) callconv(hook.cc.stdcall) u32, ADDR_GetObjectByGUID, .{ lo, hi });
|
||||
}
|
||||
|
||||
fn updateInventoryAlertStates() void {
|
||||
@@ -76,11 +76,11 @@ fn updateInventoryAlertStates() void {
|
||||
}
|
||||
|
||||
fn refreshAppearanceAndEquipment(unit: u32) void {
|
||||
hook.fastcall(void, ADDR_RefreshAppearance, unit, @as(u32, 0));
|
||||
hook.call(fn (u32) callconv(hook.cc.fastcall) void, ADDR_RefreshAppearance, .{unit});
|
||||
}
|
||||
|
||||
fn refreshEquipmentDisplay(unit: u32) void {
|
||||
hook.fastcall(void, ADDR_RefreshEquipmentDisplay, unit, @as(u32, 0));
|
||||
hook.call(fn (u32) callconv(hook.cc.fastcall) void, ADDR_RefreshEquipmentDisplay, .{unit});
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -153,12 +153,9 @@ pub fn isActive() bool {
|
||||
// Hooks
|
||||
// =============================================================================
|
||||
|
||||
const tc: std.builtin.CallingConvention = .{ .x86_thiscall = .{} };
|
||||
const fc: std.builtin.CallingConvention = .{ .x86_fastcall = .{} };
|
||||
const sc: std.builtin.CallingConvention = .{ .x86_stdcall = .{} };
|
||||
const SetBlockFn = fn (u32, u32, u32) callconv(tc) u32;
|
||||
const RefreshFn = fn (u32, u32, u32, u32) callconv(tc) void;
|
||||
const SceneEndFn = fn (u32) callconv(tc) void;
|
||||
const SetBlockFn = fn (u32, u32, u32) callconv(hook.cc.thiscall) u32;
|
||||
const RefreshFn = fn (u32, u32, u32, u32) callconv(hook.cc.thiscall) void;
|
||||
const SceneEndFn = fn (u32) callconv(hook.cc.thiscall) void;
|
||||
|
||||
var set_block_hook: hook.Detour(SetBlockFn) = .{};
|
||||
var refresh_hook: hook.Detour(RefreshFn) = .{};
|
||||
@@ -473,7 +470,7 @@ fn processTimeouts(now: u32) void {
|
||||
// Hook 1: SetBlock (0x6142E0)
|
||||
// =============================================================================
|
||||
|
||||
fn hookSetBlock(obj: u32, index: u32, value: u32) callconv(tc) u32 {
|
||||
fn hookSetBlock(obj: u32, index: u32, value: u32) callconv(hook.cc.thiscall) u32 {
|
||||
const val = value;
|
||||
|
||||
// VISIBLE_ITEM writes
|
||||
@@ -648,7 +645,7 @@ fn hookSetBlock(obj: u32, index: u32, value: u32) callconv(tc) u32 {
|
||||
// Hook 2: RefreshVisualAppearance (0x5fb880)
|
||||
// =============================================================================
|
||||
|
||||
fn hookRefreshVisualAppearance(unit: u32, event_data: u32, extra_data: u32, force_update: u32) callconv(tc) void {
|
||||
fn hookRefreshVisualAppearance(unit: u32, event_data: u32, extra_data: u32, force_update: u32) callconv(hook.cc.thiscall) void {
|
||||
if (!g_enabled or refresh_hook.inner.trampoline == 0) {
|
||||
if (refresh_hook.inner.trampoline != 0) {
|
||||
callOriginalRefresh(unit, event_data, extra_data, force_update);
|
||||
@@ -754,7 +751,7 @@ fn hookRefreshVisualAppearance(unit: u32, event_data: u32, extra_data: u32, forc
|
||||
// Hook 3: SceneEnd (0x5a17a0)
|
||||
// =============================================================================
|
||||
|
||||
fn hookSceneEnd(device: u32) callconv(tc) void {
|
||||
fn hookSceneEnd(device: u32) callconv(hook.cc.thiscall) void {
|
||||
if (g_enabled and (g_local_pending_count > 0 or g_other_pending_count > 0)) {
|
||||
processTimeouts(GetTickCount());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user