Author Topic: Перемещение персонажа по контрольным точкам в 3Д играх с видом от 3го лица  (Read 4942 times)

0 Members and 1 Guest are viewing this topic.

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Code: (clickermann) [Select]
//Скрипт осуществляет перемещение персонажа (стрелки вперед и поворот вправо-влево) по контрольным точкам в 3Д игре с видом от 3го лица
//координатная сетка: слева -X, cправа +X, сверху -Y, снизу +Y
//адреса в памяти программы тип hex; X,Y - координаты тип float
//$_Sx,$_Sy - координаты камеры от 3го лица
//$_Ax,$_Ay - текущие координаты персонажа
//$_Bx,$_By - координаты текущей контрольной точки

#ps2_keyboard
// отключить NumLock (Кликер с включенным глючит)
#include "float.cms"     //подключение процедуры переводящей hex 4 байта во float 4 байта
#include "azimut.cms"    //вызятие азимута
wait(1)
$_ms1g =  1.02 * 6684 / 360   //поворот  (1.02 - поправочный коэф; 6684 - время в мс за которое персонаж повернется на 360 градусов)

EXECUTE("pid.exe") //получение PID игры и запись в Find_PID.ini(привязка по названию окна)
WAIT(2)
$_pid = INT(INIREAD("Find_PID.ini", "pid"))
$_addr = readmem($_pid, 0x102D19F0, 4) //не базовый адрес, но некоторое время начальный адрес здесь храниться
$_addrX = $_addr + 0x000003E0          //Х координаты перса в HEX
$_addrY = $_addr + 0x000003E4          //y
$_addrXs = $_addr + 0x00000950         //х координаты камеры от 3-го лица
$_addrYs = $_addr + 0x00000954         //у

$_a025 = RND(200,220)   //время минимально возможной задержки
$_a1 = RND(1000,1100)

KEYDOWN(#TAB)    //что бы можно было стрелками управлять персонажем
waitms($_a025)
KEYUP(#TAB)
waitms($_a025)

KEYDOWN(#TAB)
waitms($_a025)
KEYUP(#TAB)
waitms($_a025)

KEYDOWN(#UP)        //сразу после загрузки (по адресу в памяти) координаты персонажа 0, после короткой пробежки сервер пересылает текущие координаты
waitms($_a025)
KEYUP(#UP)
waitms($_a01)

$_ks = TFCOUNT("loc.txt") + 1   
FOR($_loc = 1, $_loc < $_ks, 2) 
   $kl = 1
   $_Bx =  INT(TFREAD("loc.txt", $_loc))            //чтение координат текущей контрольной точки
   $_By =  INT(TFREAD("loc.txt", ($_loc + 1)))
   WHILE($kl = 1)
      $_Ax = readmem($_pid, $_addrX, 4)           //чтение координат текущей координаты перса
      int_to_Float($_Ax)
      $_Ax = int($float)
     
      $_Ay = readmem($_pid, $_addrY, 4)
      int_to_Float($_Ay)
      $_Ay = int($float)
     
      $_Sx = readmem($_pid, $_addrXs, 4)                  ////чтение координат камеры от 3го лица
      int_to_Float($_Sx)
      $_Sx = int($float)
     
      $_Sy = readmem($_pid, $_addrYs, 4)
      int_to_Float($_Sy)
      $_Sy = int($float)
     
      azimut($_Ax,$_Ay,$_Bx,$_By)  //взятие азимута с текущей координаты перса на текущую контрольную точку
      $_AzAB = $angle               
      $_Dab = $_Dt1t2              //дистанция до контрольной точки
     
      azimut($_Sx,$_Sy,$_Ax,$_Ay)  //взятие азимута с координаты камеры от 3го лица на текущуие координаты перса
      $_AzSA = $angle
     
      $_deltaAz = abs($_AzSA - $_AzAB)  //дельта между азимутами
     
      if (($_AzSA < $_AzAB) and ($_deltaAz < 180)  //какой поворот ближе туда и повернет навычесленный угол
         KEYDOWN(#RIGHT)
         waitms(int(($_deltaAz) * $_ms1g))
         KEYUP(#RIGHT)
      END_IF
      if (($_AzSA > $_AzAB) and ($_deltaAz < 180)
         KEYDOWN(#LEFT)
         waitms(int(($_deltaAz * $_ms1g))
         KEYUP(#LEFT)
      END_IF
      if (($_AzSA > $_AzAB) and ($_deltaAz >= 180)
         KEYDOWN(#RIGHT)
         waitms(int((360 - $_deltaAz) * $_ms1g))
         KEYUP(#RIGHT)
      END_IF
      if (($_AzSA < $_AzAB) and ($_deltaAz >= 180)
         KEYDOWN(#LEFT)
         waitms(int((360 - $_deltaAz) * $_ms1g))
         KEYUP(#LEFT)
      END_IF
     
      IF ($_Dab > 50)        //50 - минимальная дистанция до контрольной точки, после достижения которой можно получить новую
         KEYDOWN(#UP)
         waitms(int($_Dab / 0.14))  //(бег) 0.14 - скорость(точки в мс), при паспортной скорости перса в 129 (0.185-170?)
         KEYUP(#UP)
         $kl = 1
      else
         $kl = 0
      end_if
     
      waitms($_a1)
   END_CYC
END_CYC

halt

Vint - автор идеи с расчетом азимута (с геометрией у меня не очень процедуру переписал чтоб понятней было)

Code: (clickermann) [Select]
SUB(azimut,$t1x,$t1y,$t2x,$t2y) //=============================================

      $_Dt1t2 = DIST($t1x,$t1y,$t2x,$t2y)
      $_Dt1az = DIST($t1x,$t1y,$t1x,$t2y)
      $_Dt2az = DIST($t2x,$t2y,$t1x,$t2y)

      if ($_Dt1t2 = 0)   //на 0 делить нельзя, может кто предложит более изящную идею
$_Dt1t2 = 0,1
      end_if
      if ($_Dt1az = 0)
$_Dt1az = 0,1
      end_if

      $_DV = POW($_Dt1az, 2) + POW($_Dt1t2, 2) - POW($_Dt2az, 2)
      $_DN = 2 * $_Dt1t2 * $_Dt1az

      $beta = arccos($_DV / $_DN)

      if (($t1x > $t2x) and ($t1y > $t2y))
         $angle = 360 - $beta
       end_if
      if (($t1x <= $t2x) and ($t1y >= $t2y))
         $angle = $beta
       end_if
       if (($t1x < $t2x) and ($t1y < $t2y))
         $angle = 180 - $beta
       end_if
       if (($t1x > $t2x) and ($t1y < $t2y))
         $angle = 180 + $beta
       end_if
END_SUB


dramster - автор процедуры перевода HEX 4 байта во FLOAT 4 байта

Code: (clickermann) [Select]
    //перевод числа в двоичную строку $BIN  (строка выйдет длиной в 32бит)
    SUB(dec_to_BIN, $DEC)
       $BIN = ""
     
       IF($DEC > 0)   //если положительное
          WHILE($DEC > 0)
             $DEC = $DEC/2
             IF($DEC > int($DEC))
                $BIN = STRCONCAT("1", $BIN)
             else
                $BIN = STRCONCAT("0", $BIN)
             END_IF
             $DEC = int($DEC)
          END_CYC
          WHILE(STRLEN ($BIN) < 32)       //4 байта
             $BIN = STRCONCAT("0", $BIN)
          END_CYC
       ELSE               //если отрицательное
          $DEC = abs($DEC+1)
          WHILE($DEC > 0)
             $DEC = $DEC/2
             IF($DEC > int($DEC))
                $BIN = STRCONCAT("0", $BIN)
             else
                $BIN = STRCONCAT("1", $BIN)
             END_IF
             $DEC = int($DEC)
          END_CYC
          WHILE(STRLEN ($BIN) < 32)       //4 байта
             $BIN = STRCONCAT("1", $BIN)
          END_CYC
       END_IF
     
    END_SUB
     
     
    //перевод из двоичной строки в десятичное число $DEC
    SUB(bin_to_DEC, $BIN_str)
       $DEC = 0
       IF(ARRSIZE ($arr) = 0)
          $num_arr = 1
          FOR($i=0,$i<32)
             arrpush($arr, $num_arr)
             $num_arr = $num_arr*2
          END_CYC
       END_IF
     
       FOR($i=0,$i < STRLEN($BIN_str))
          $DEC = $DEC + ($arr[$i]*int(STRCUT($BIN_str, STRLEN($BIN_str)-$i, 1)))
       END_CYC
    END_SUB
     
    //перевод из целочисленного в дробное $float. целочисленное 4 байт -  long (Signed int) от -2147483648 до 2147483647
    SUB(int_to_Float, $int_in)
     
       dec_to_BIN($int_in)
     
       bin_to_DEC(STRCUT ($BIN,2, 8))
       $exp = $DEC   //экспонента в десятичном
     
       bin_to_DEC(STRCUT ($BIN,10, 32))
       $mant = $DEC   //мантиса в десятичном
     
       $float =  POW(-1,int(STRCUT ($BIN,1,1))) * pow(2,$exp-127) * (1+($mant/POW(2,23)))
     
    END_SUB
     
    ///////////////////////////////////////////////////////////////////////////////
    //основной код
     
   // int_to_Float(-979615744)
   // print($float)  //  -5000


Скрипт записывающий в файл loc.txt координаты контрольных точек

Code: (clickermann) [Select]
//ALT - запись X,Y координат контрольной точки
//ESC - выход
#name "loc"
#ps2_keyboard

$_sp = 0
$_pid = 0

THREAD(T1, 0)  //поток считывающий координаты из памяти процесса и записывающий их в файл loc.txt
   #include "float.cms"
   
   $_Ax = readmem($_pid, $_addrX, 4)
   $_Ay = readmem($_pid, $_addrY, 4)
   IF($_sp = 1)   
      int_to_Float($_Ax)
      TFWRITE("loc.txt", int($float))
     
      int_to_Float($_Ay)
      TFWRITE("loc.txt", int($float))
      $_sp = 0
   END_IF
   
   WAIT(1)
END_THREAD

THREAD(T2, 0)  //поток обрабатывающий нажатие клавиш
   IF(iskeydown(#ALT)=1)
      $_sp = 1
   END_IF
   IF(iskeydown(#esc)=1)
      halt
   END_IF
   
   waitms(200)
END_THREAD

EXECUTE("pid.exe") //получение PID и запись его в файл Find_PID.ini
WAIT(2)
$_pid = INT(INIREAD("Find_PID.ini", "pid"))
$_addr = readmem($_pid, 0x102D19F0, 4)
$_addrX = $_addr + 0x000003E0
$_addrY = $_addr + 0x000003E4

SETTHREAD (T1, 1)
SETTHREAD (T2, 1)
wait(600000)


Поиск Базового Адреса осуществлен в Cheat Engine. Средствами Кликера до БА добраться не смог, нашел адрес в памяти где указатель на начало структуры некоторое время храниться.
PID.exe сделан в AutoIT
« Last Edit: February 03, 2018, 12:51:09 AM by ya12 »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
вижу, что используешь одну из последних бет 4.13. а значит и не обязательно использовать сторонние утилиты для определения pid.
HGETPID (hwnd) - Функция. Возвращает pid идентификатор родительского процесса по hwnd дочернего окна.

и в место поворота перса с помощью кнопок и выдерживания какихто задержек с коэффициентами, попробуй использовать MOVER (rx, ry). он поворачивает камеру на нужный (рассчитанный) тебе угол, не зависимо от фпс и лагов в игре.



отличный подход, тоже всегда стараюсь не привязываться к неточным данным с картинки на экране, а читать нужное в памяти. жаль, что не всегда это возможно  :(.

Quote
$_addr = readmem($_pid, 0x102D19F0, 4) //не базовый адрес, но некоторое время начальный адрес здесь храниться
адрес на указатель меняется? и нужно каждый раз заново искать его? пробуй искать указатель на указатель, или указатель со смещением. если не как, то адрес в модуле. только кликер с модулями не работает, может помочь автоит.

по такому же принципу перемещения по контрольным точкам отлично работает езда на транспорте в 3д играх. если хорошо отладить, то даже лучше ездит чем в ручную  :D , и на высоких скоростях.






ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
MOVER (rx, ry) не подходит. У меня только 1 PS/2 порт на нем висит клава. Если не использовать PS/2 режим, через некоторое время защита с сервера выкинет.

PID по HWND прикручу, когда все части скрипта соберу вместе.

БА зависит от адреса загруженной DLL. Средствами кликера адрес загруженной DLL не получить. К тому же между БА и адресом структуры хранящей координаты находятся 2 смещения представляющие индексные массивы. У каждого персонажа свои смещения. Цифры не большие поэтому поиск выдает тысячи адресов. Ну и защита не спит. Бряки поставленные на адреса начинающиеся с 00 зачастую приводят к отключению от сервера.
До телепортации по адресу 102D19F0 лежит адрес начала структуры. После загрузки персонажа один раз получить содержимое адреса, а потом уже не важно.

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
БА зависит от адреса загруженной DLL. Средствами кликера адрес загруженной DLL не получить. К тому же между БА и адресом структуры хранящей координаты находятся 2 смещения представляющие индексные массивы. У каждого персонажа свои смещения. Цифры не большие поэтому поиск выдает тысячи адресов. Ну и защита не спит. Бряки поставленные на адреса начинающиеся с 00 зачастую приводят к отключению от сервера.
До телепортации по адресу 102D19F0 лежит адрес начала структуры. После загрузки персонажа один раз получить содержимое адреса, а потом уже не важно.
адрес загруженной dll это и есть модуль в памяти. зная имя модуля, находим его в памяти с помощью автоита, _MEMORYMODULEGETBASEADDRESS - библиотека RMemory.au3 во вложении. в модуле будет указатель, либо указатель на указатель, возможно со смещением.  Cheat Engine не использую, считаю что проще найти нужное в артмани, пока не подводила.

MOVER (rx, ry) не подходит. У меня только 1 PS/2 порт на нем висит клава. Если не использовать PS/2 режим, через некоторое время защита с сервера выкинет.
я хз, вроде MOVER (rx, ry) работает не зависимо от PS/2. даже если защита от кликов и нажатий в игре есть, MOVER (rx, ry) работает не зависимо от режима PS/2. другое дело если защита выкидывает из игры, ну тогда уж ничего не поделаешь.

James

  • Освоившийся
  • **
  • Posts: 45
    • View Profile
Ув. dramster, а не подскажешь оптимальные и быстрые пути поиска указателей на значения? Либо менее быстрые и оптимальные, но более простые для восприятия
Мне бы очень много где пригодилось чтение из памяти игры, чтобы получать значения не с экрана, а как есть и потом уже с ними работать. Если это делается с помощью той au3 библиотеки или Артмани, не подскажешь алгоритм работы? Я пробовал с CheatEgine, и, либо я мало старался, либо я тормоз и не совладал с этим
Спасибо!
« Last Edit: February 28, 2018, 04:27:28 PM by James »

dramster

  • Герой форума
  • *****
  • Posts: 1134
    • View Profile
в справке артмани все доступно расписано по поиску указателей (на примере игры "Warcraft 3"). справка отдельно есть на оффсайте, либо с прогой.

James

  • Освоившийся
  • **
  • Posts: 45
    • View Profile
Спасибо за ответы, ребят

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
Как я нашел БА в Cheat Engine 6.7 рус.

Возможно выбор настроек не оптимальный.
В Настройки - Параметры отладчика : Использовать VEH отладчик
                    - Дополнительно : Процедуры обращения к региону памяти
                                                : Чтение/Запись Памяти Процесса

Выбрать процесс и найти какой-нибудь изменяемый вручную параметр(типа HP,MP,внутри-игровых координат).

ПКМ:Найти инструкции обращающиеся по этому адресу.
Получаем начало структуры и смещение.

ПКМ:Найти указатель на этот адрес(начало структуры). Перед каждым поиском и отсевом выбирается куда сохранить результат.
Получили миллионы указателей.
Чем больше максимальный уровень смещений тем дольше искать(по умолчанию уровень 5).

Для отсева неправильных указателей нужно изменить адрес начала структуры(выбрать другого персонажа на этом аккаунте, перелогиниться, перезагрузить игру или компьютер).
После чего опять найти новый адрес структуры. В поиске указателей загрузить сохраненный результат и произвести отсев с новым адресом.
Повторять пока есть что отсеивать. Можно повторить отсев на разных компах, ОС.
В итоге от 0 до нескольких тысяч БА со смещениями. Я предпочитаю БА со смещением от загруженной в память DLL.
Если 0, то увеличивать уровень смещений, до тех пор пока время поиска не превысит разумные пределы.

James

  • Освоившийся
  • **
  • Posts: 45
    • View Profile
Как я нашел БА в Cheat Engine 6.7 рус.

Возможно выбор настроек не оптимальный.
В Настройки - Параметры отладчика : Использовать VEH отладчик
                    - Дополнительно : Процедуры обращения к региону памяти
                                                : Чтение/Запись Памяти Процесса

Выбрать процесс и найти какой-нибудь изменяемый вручную параметр(типа HP,MP,внутри-игровых координат).

ПКМ:Найти инструкции обращающиеся по этому адресу.
Получаем начало структуры и смещение.

ПКМ:Найти указатель на этот адрес(начало структуры). Перед каждым поиском и отсевом выбирается куда сохранить результат.
Получили миллионы указателей.
Чем больше максимальный уровень смещений тем дольше искать(по умолчанию уровень 5).

Для отсева неправильных указателей нужно изменить адрес начала структуры(выбрать другого персонажа на этом аккаунте, перелогиниться, перезагрузить игру или компьютер).
После чего опять найти новый адрес структуры. В поиске указателей загрузить сохраненный результат и произвести отсев с новым адресом.
Повторять пока есть что отсеивать. Можно повторить отсев на разных компах, ОС.
В итоге от 0 до нескольких тысяч БА со смещениями. Я предпочитаю БА со смещением от загруженной в память DLL.
Если 0, то увеличивать уровень смещений, до тех пор пока время поиска не превысит разумные пределы.
Спасибо, что не прошли мимо и все расписали) Эта информация будет несомненно полезной!

ya12

  • Активный участник
  • ***
  • Posts: 165
    • View Profile
На скрине красные стрелки - это мана. Зеленые - адрес где начинается таблица и смещение от него. Справа в записях видно что HP,MP,CP max и текущие идут подряд со смещение 4 байта. Дальше ищем указатели на это адрес в разделе сканирование указателей и т.д.

Если все найденные указатели БА после перезагрузки оказались ошибочными - придется пройти по цепочке в ручном режиме.
Там скорее всего адрес формируется из нескольких неизвестных (пример   mov [eax + edi*4 + 38],ecx ).
В примере еах - адрес от которого можно выйти к БА, а edi - смещения в таблице. Найти как формируется edi сложно, но возможно...