经过大量的反复试验,以及来自许多不同来源和人们的帮助的拼图的零碎碎片,我想在我认为能够回答的范围内回答我自己的问题。我希望这可以帮助遇到这个问题的其他人。
问题 1:sin/cos 值往往是什么样的,我希望在什么时候通过与相机/坐标相关的子程序看到它们(无论是在堆栈上,还是在 FPU/XMM 寄存器中,等等)?我认为这些应该接近我在内存或子程序中涉足的地方,但我不太确定我在寻找什么。
这些值将是相机俯仰(垂直运动)和偏航(水平运动)的正弦和余弦。它们可能驻留在相机俯仰/偏航地址的附近内存中的某个位置,或者在子程序中计算俯仰/偏航时的寄存器中。游戏可以以度数或弧度表示俯仰和偏航。
音高的例子:
Range in degrees: -89 to 89 (Example of a clamped range, to avoid flipping)
Same range in radians: -1.55334 to 1.55334
偏航的例子:
Range in degrees: -180 to 180 (Equaling 360 degrees total)
Same range in radians: -3.14159 to 3.14159
如果您正在反转的游戏将其值存储为度数,取决于您计划如何计算正弦/余弦,您可能需要将度数转换为弧度。由于我使用的是 Lua,所以它的度数到弧度函数是math.rad(). 所以, math.rad(180) 会给我们一个从 180 度到 3.14159 弧度的转换。
有了这个值,我们现在可以使用 Lua 的math.cos()和math.sin()函数了。假设我们正在寻找相机在 63 度时偏航的 sin 和 cos。我们将在内存、堆栈或寄存器中查找的值分别为 0.4539(余弦或math.cos(63))和 0.891007(正弦或math.sin(63))。
从公式的角度来看,以下是我们如何设置变量以在 Lua 中为我们提供相机偏航的 sin 和 cos,前提是我们知道该值的存储地址:
--Read and store value from camera yaw memory address
local camYaw = readFloat("[cameraBase+1D0]")
--Convert yaw to radians, then calculate cosine
local camYawCos = math.cos(math.rad(camYaw))
--Convert yaw to radians, then calculate sine
local camYawSin = math.sin(math.rad(camYaw))
请记住,如果您正在反转的游戏已经将其值存储为弧度,则您不必担心将度数转换为弧度的步骤!
上面的公式允许您自己计算值,然后在内存、堆栈或寄存器中查找它们,从而帮助您找出特定值所在的位置。
问题2:是否有通过逆向识别游戏坐标系的通用方法?
目前我对此仍然不确定。一旦发现 XYZ 俯仰/偏航,您可以通过查看计算的行为来弄清楚它,但这并不是我想知道的答案。如果/当我弄清楚这一点时,我会更新这个答案。
问题 3:如果我知道游戏中使用的坐标系,以及 XYZ 和 Pitch/Yaw 摄像机值,是否有公式方法可以计算正弦/余弦,然后使用速度修改器成功实现自由摄像机? 如果我无法在游戏中找到要在我的脚本中使用的 sin/cos。
问题 4:我对我在试图理解与 sin/cos 相关的计算时查找的三角函数/计算函数只有一个粗略的理解。给定一个左手和右手坐标系,Z 向上,连同 XYZ、俯仰/偏航数据和速度修改器,有人可能会引导我完成必要的计算,以便在两个坐标系中进行向前工作,无论在哪里用户指向鼠标?例如,在任何给定时间,sin/cos 值究竟由什么组成,它们如何/为什么重要,以及为什么要添加/sub/mul 以适当修改 XYZ 等?
我将把这两个与我最终创建的脚本联系在一起。
首先,信用到期的信用。我使用SunBeam 的刺客信条:起源脚本作为初始模板。此外,我发现对这篇文章做出贡献的优秀个人的例子在整个过程中都非常有启发性——以及GuidedHacking在这里的答案,以及我最初发布查询的DMGregory 的答案。最后,这种巨大的工作由弗朗斯鲍马游戏相机上的反转是任何人都希望在讨论这个话题精彩的参考。
现在,在左手坐标系中,您需要插入此脚本的只是相机的 XYZ 坐标,以及相机的俯仰和偏航。您可以将速度修改器更改为您想要的任何内容。我有一些键可以让相机移动得越来越快,而且我还实现了扫射,所以你可以在旋转时对角移动。
这是一个 Lua 脚本,创建用于在Cheat Engine 中运行。脚本的顶部使用 Cheat Engine 函数分配内存来存储速度修饰符值。我已经对所有内容进行了大量评论,因此如果需要,您应该会发现将其转换为您选择的高级语言相对容易!
globalalloc(speedModifier,8) --Allocate 8 bytes memory
speedModifier:
dd (float)2 --Store a float of 2
{$lua} --Tells Cheat Engine to treat everything beneath as Lua
[ENABLE] --Everything beneath this happens when this script is enabled
function checkKeys(timer) --Check keys for input (check on a timer)
--Speed modifier value, read from memory location we allocated earlier
local speed = readFloat("speedModifier")
--Camera coordinates stored in variables
local camx = readFloat("[camBase]+1A0") -- Camera X
local camy = readFloat("[camBase]+1A8") -- Camera Y
local camz = readFloat("[camBase]+1A4") -- Camera Z
--Mouse rotation in radians
--Use math.rad() to convert from degrees if necessary
local rotv = math.rad(readFloat("[camBase]+1D0")) -- Vertical (Pitch)
local roth = math.rad(readFloat("[camBase]+1D4")) -- Horizontal (Yaw)
--Sine and Cosine of Rotation Values
local sinh = math.sin(roth) -- Sine of Horizontal (Yaw)
local cosh = math.cos(roth) -- Cosine of Horizontal (Yaw)
local sinv = math.sin(rotv) -- Sine of Vertical (Pitch)
local cosv = math.cos(rotv) -- Cosine of Vertical (Pitch)
--Hotkey Setup
--[[
Button Mappings:
Y - Forward
G - Left
H - Backward
J - Right
T - Down
U - Up
C - Speed Up
Alt - Slow Down
--Key combinations for strafing are also defined
--Keys are oriented to where mouse is pointing
]]
--Forward
if isKeyPressed(VK_Y) then
writeFloat("[camBase]+1A0", camx + (cosh * speed))
writeFloat("[camBase]+1A8", camy + (sinv * speed))
writeFloat("[camBase]+1A4", camz + (sinh * speed))
end
--Left
if isKeyPressed(VK_G) then
writeFloat("[camBase]+1A0", camx + (math.cos(roth - math.rad(90)) * speed))
writeFloat("[camBase]+1A4", camz + (math.sin(roth - math.rad(90)) * speed))
end
--Back
if isKeyPressed(VK_H) then
writeFloat("[camBase]+1A0", camx - (cosh * speed))
writeFloat("[camBase]+1A8", camy - (sinv * speed))
writeFloat("[camBase]+1A4", camz - (sinh * speed))
end
--Right
if isKeyPressed(VK_J) then
writeFloat("[camBase]+1A0", camx - (math.cos(roth - math.rad(90)) * speed))
writeFloat("[camBase]+1A4", camz - (math.sin(roth - math.rad(90)) * speed))
end
--Forward/Right
if isKeyPressed(VK_Y) and isKeyPressed(VK_J) then
writeFloat("[camBase]+1A0", camx + (math.cos(roth + math.rad(45)) * speed))
writeFloat("[camBase]+1A8", camy + (sinv * speed))
writeFloat("[camBase]+1A4", camz + (math.sin(roth + math.rad(45)) * speed))
end
--Forward/Left
if isKeyPressed(VK_Y) and isKeyPressed(VK_G) then
writeFloat("[camBase]+1A0", camx + (math.cos(roth - math.rad(45)) * speed))
writeFloat("[camBase]+1A8", camy + (sinv * speed))
writeFloat("[camBase]+1A4", camz + (math.sin(roth - math.rad(45)) * speed))
end
--Back/Left
if isKeyPressed(VK_H) and isKeyPressed(VK_J) then
writeFloat("[camBase]+1A0", camx - (math.cos(roth - math.rad(45)) * speed))
writeFloat("[camBase]+1A8", camy - (sinv * speed))
writeFloat("[camBase]+1A4", camz - (math.sin(roth - math.rad(45)) * speed))
end
--Back/Right
if isKeyPressed(VK_H) and isKeyPressed(VK_G) then
writeFloat("[camBase]+1A0", camx - (math.cos(roth + math.rad(45)) * speed))
writeFloat("[camBase]+1A8", camy - (sinv * speed))
writeFloat("[camBase]+1A4", camz - (math.sin(roth + math.rad(45)) * speed))
end
--Up
if isKeyPressed(VK_U) then
writeFloat("[camBase]+1A8", camy + (speed * 0.5))
end
--Down
if isKeyPressed(VK_T) then
writeFloat("[camBase]+1A8", camy - (speed * 0.5))
end
--Speed Modifiers
if isKeyPressed(VK_C) then --If C is pressed, increase speed; max of 100
if (speed < 100) then
writeFloat("speedModifier", speed + 1)
end
elseif isKeyPressed(VK_MENU) then --If Alt is pressed, slow way down
writeFloat("speedModifier", .3)
else --If nothing is pressed, normal speed
writeFloat("speedModifier", 2)
end
end
t=createTimer(nil)
timer_setInterval(t, 10)
timer_onTimer(t, checkKeys)
timer_setEnabled(t, true)
[DISABLE] --Everything beneath this happens when the script is disabled
timer_setEnabled(t, false)