三国群英2吧 关注:44,038贴子:999,885
  • 4回复贴,共1

【修改】修复华斩倒飞问题

取消只看楼主收藏回复

一楼


IP属地:美国1楼2021-07-14 14:41回复
    UE打开EXE,修改:
    从:
    21A5F: 0F AF 45 10 99
    21A70: 0F AF 45 10 99
    21A81: 0F AF 45 10 99
    改为:
    21A5F: F7 6D 10 90 90
    21A70: F7 6D 10 90 90
    21A81: F7 6D 10 90 90


    IP属地:美国2楼2021-07-14 14:42
    回复
      原理:
      华斩的飞行轨迹实际上有两种:当武将之间的距离大于或等于1200px=12.5格时,飞行轨迹是一个参数方程
      x = x0 + (x1 - x0) * t/T
      y = y0 + rsin(t/T*π)
      其中T为总用时,t为参数,r是一个常数,第2、3道剑气的r为200,第4、5道剑气的r为400. 这种情况下,剑气从我将出发,一开一合后飞向敌将,永远不会倒飞。
      另一种情况下,当武将之间的距离小于12.5格时,剑气会从武将的左右两侧产生,其中第2、3道剑气离武将200px,第4、5道剑气离武将400px;剑气以匀速直线飞向敌将。
      这种情况下多数并不会倒飞。然而,因为系统函数ApproachObjectTowards()(即SYSCALL 0x19)的实现有问题,有的情况下,剑气的速度会反向。这是因为该函数按如下公式计算x方向的速度:
      v_x = v * dx / sqrt(dx^2 + dy^2)
      其中dx、dy为剑气和目标武将之间的x、y坐标差。
      我们知道,在EXE中,坐标是以高16位为整数部分,低16位为小数部分的;当dx=1200时,内存中实际储存的是1200 << 16 = 0x 4B0 0000. 而速度v固定为30. 因此
      v * dx = 30 * 0x4B0 0000 = 0x8CA0 0000 > 0x7FFF FFFF = 2147483647 = 2^31 - 1
      发生了数值越界。
      这样,两个正数相乘,就会得到一个负数,导致速度的方向反了,引起华斩倒飞。
      因此,华斩倒飞是很容易复现的:只需要保证双方武将之间的距离刚好在12格时(准确地说是11.375-12.5格之间),打出华斩,则必定倒飞。


      IP属地:美国4楼2021-07-14 14:58
      回复
        修改方法:
        x86汇编允许乘法的结果用两个32位寄存器储存;当乘数之一在eax中时,使用单操作数(而非双操作数)版本的imul指令,即可使得结果被储存在EDX:EAX中。
        IMUL SRC
        (EDX,EAX)←(EAX)*(SRC)
        同时,除法指令idiv也是使用EDX:EAX来储存被除数的:
        IDIV SRC
        (EAX) ← (EDX,EAX) / (SRC)
        (EDX) ← (EDX,EAX) % (SRC)
        因此我们只需要把原来代码中的
        mov eax, [ebp-18]
        imul eax, [ebp+10]
        cdq
        idiv [ebp-14]
        改为
        mov eax, [ebp-18]
        imul [ebp+10]
        idiv [ebp-14]
        即可解决越界问题。此时,imul得到的结果,会被扩充至EDX:EAX,合计64位,不会发生越界,也不需要使用cdq扩充到EDX里,直接接上下面的idiv指令即可。
        实际修改时,把imul eax, [ebp+10]; cdq这两条指令改成imul [ebp+10]即可,剩下的用nop填充。
        对于y和z方向上的速度,也依样画葫芦照此修改。
        这样就解决了越界问题,华斩也就不会倒飞了。


        IP属地:美国5楼2021-07-14 15:05
        回复
          以上


          IP属地:美国6楼2021-07-14 15:06
          回复