Fix marker placement over game objects with terrain-only re-raycast
When cursor hits an object (hitType=2), re-call WorldIntersectionTest with flags=0 to get terrain position behind it. Replaces the GUID-based unit position lookup which failed for GOs (no movement struct).
This commit is contained in:
+32
-22
@@ -231,9 +231,10 @@ fn resolveUnitPosition(unit_id: [*:0]const u8) ?Vec3 {
|
||||
}
|
||||
|
||||
/// Get the world position under the mouse cursor via UpdateHitTest.
|
||||
/// Accepts terrain, WMO, and object hits. For object hits (type 2), uses the
|
||||
/// object's unit position instead of the ray intersection point (which can
|
||||
/// land at the camera position due to how object raycasting works).
|
||||
/// For terrain/WMO hits (type 0), uses the intersection point directly.
|
||||
/// For object hits (type 2), re-raycasts with terrain-only flags (0) to get
|
||||
/// the terrain position behind the object, since object intersection coords
|
||||
/// are unreliable and GOs lack a movement struct for position lookup.
|
||||
fn getCursorTerrainPosition() ?Vec3 {
|
||||
const world_frame = hook.readMem(u32, o.PTR_WORLD_FRAME);
|
||||
if (world_frame == 0 or world_frame < 0x10000) return null;
|
||||
@@ -247,31 +248,40 @@ fn getCursorTerrainPosition() ?Vec3 {
|
||||
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);
|
||||
|
||||
if (hit_type == 2) {
|
||||
// Object hit — re-raycast with flags=0 (terrain/WMO only) to get the
|
||||
// terrain position behind the object.
|
||||
const ray_start: u32 = world_frame + o.WF_RAY_START;
|
||||
const ray_end: u32 = world_frame + o.WF_RAY_END;
|
||||
|
||||
// WorldIntersectionTest: __thiscall(ECX=worldFrame, rayStart*, rayEnd*, flags, hitResult*)
|
||||
// HitTestResult is 0x34 bytes; hit position Vec3 at +0x08.
|
||||
var result_buf = [_]u8{0} ** 0x34;
|
||||
const result_ptr = @intFromPtr(&result_buf);
|
||||
|
||||
_ = hook.call(
|
||||
fn (u32, u32, u32, u32, u32) callconv(hook.cc.thiscall) u32,
|
||||
o.FN_WORLD_INTERSECTION_TEST,
|
||||
.{ world_frame, ray_start, ray_end, @as(u32, 0), result_ptr },
|
||||
);
|
||||
|
||||
const tx = @as(*align(1) const f32, @ptrFromInt(result_ptr + 0x08)).*;
|
||||
const ty = @as(*align(1) const f32, @ptrFromInt(result_ptr + 0x0C)).*;
|
||||
const tz = @as(*align(1) const f32, @ptrFromInt(result_ptr + 0x10)).*;
|
||||
|
||||
log.fmt("hitTest: object hit, terrain re-raycast pos={d:.1},{d:.1},{d:.1}\n", .{ tx, ty, tz });
|
||||
|
||||
if (tx == 0 and ty == 0 and tz == 0) return null;
|
||||
return .{ .x = tx, .y = ty, .z = tz };
|
||||
}
|
||||
|
||||
const x = hook.readMem(f32, world_frame + o.WF_HIT_TERRAIN_X);
|
||||
const y = hook.readMem(f32, world_frame + o.WF_HIT_TERRAIN_Y);
|
||||
const z = hook.readMem(f32, world_frame + o.WF_HIT_TERRAIN_Z);
|
||||
|
||||
log.fmt("hitTest: type={d} pos={d:.1},{d:.1},{d:.1}\n", .{ hit_type, x, y, z });
|
||||
|
||||
if (hit_type == 2) {
|
||||
// Object hit — the intersection point is unreliable (can be at camera).
|
||||
// Look up the object's actual position via its GUID.
|
||||
const guid_lo = hook.readMem(u32, world_frame + o.WF_HIT_GUID);
|
||||
const guid_hi = hook.readMem(u32, world_frame + o.WF_HIT_GUID + 4);
|
||||
const guid: u64 = @as(u64, guid_hi) << 32 | guid_lo;
|
||||
if (guid != 0) {
|
||||
const obj = wow.getObjectByGUID(guid);
|
||||
if (obj != 0) {
|
||||
const pos = getUnitPosition(obj);
|
||||
if (pos.x != 0 or pos.y != 0 or pos.z != 0) {
|
||||
log.fmt("object hit, using unit pos: {d:.1},{d:.1},{d:.1}\n", .{ pos.x, pos.y, pos.z });
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Object hit but couldn't resolve position — fall through to raw coords
|
||||
}
|
||||
|
||||
if (x == 0 and y == 0 and z == 0) return null;
|
||||
|
||||
return .{ .x = x, .y = y, .z = z };
|
||||
|
||||
@@ -37,12 +37,15 @@ pub const FN_DECREMENT_REFCOUNT: usize = 0x007103a0;
|
||||
|
||||
pub const PTR_WORLD_FRAME: usize = 0x00B4B2BC;
|
||||
pub const FN_UPDATE_HIT_TEST: usize = 0x00481F00;
|
||||
pub const FN_WORLD_INTERSECTION_TEST: usize = 0x00480DF0;
|
||||
|
||||
pub const WF_HIT_TYPE: usize = 0x350;
|
||||
pub const WF_HIT_GUID: usize = 0x358;
|
||||
pub const WF_HIT_TERRAIN_X: usize = 0x360;
|
||||
pub const WF_HIT_TERRAIN_Y: usize = 0x364;
|
||||
pub const WF_HIT_TERRAIN_Z: usize = 0x368;
|
||||
pub const WF_RAY_START: usize = 0x370;
|
||||
pub const WF_RAY_END: usize = 0x37C;
|
||||
|
||||
// =============================================================================
|
||||
// Per-frame world update
|
||||
|
||||
Reference in New Issue
Block a user