Автор Тема: Альтернатива скриптингу  (Прочитано 13564 раз)

Оффлайн xanser

  • Главный Модератор
  • Постоялец
  • *****
  • Сообщений: 598
  • Репутация: +92/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
Альтернатива скриптингу
« : Декабрь 13, 2013, 01:51:39 pm »
Решил поделиться своим подходом. Я не люблю скриптить, поэтому решил вычистить под ноль все скрипты и использовать опкоды непосредственно в с++. В будущем надеюсь заменить опкоды на функции, насколько возможно.
Это запуск игры без сриптов, если можно так сказать, где определены координаты игрока и расставлено оружие средствами с++:



Вот мой main.scm, здесь осталось только создание игрока, потому что я не смог это перенести в плагин:

Код: C++
  1. DEFINE VERSION VICE 1.5
  2.  
  3. 0002: jump гг_HEAD
  4. DEFINE MEMORY 34329
  5.  
  6. :_HEAD
  7. 0002: jump гг_MAIN
  8. DEFINE MISSIONS 0
  9.  
  10. :_MAIN
  11.  
  12. 016A: fade 0 0 ms
  13. 0053: $PLAYER_CHAR = create_player #NULL at 0.0 0.0 0.0
  14. 01F5: $PLAYER_ACTOR = create_emulated_actor_from_player $PLAYER_CHAR
  15. 0001: wait 0 ms
  16. 016A: fade 1 (back) 1000 ms
  17.  
  18. :_WAIT
  19. 0001: wait 10000 ms
  20. 0002: jump гг_WAIT
  21.  

После этого у нас создан указатель на игрока. Со всем остальным мы можем работать в плагине.
Подключаем к своему проекту исходники спидометра Spookie, в частности GameScripting.cpp и GameScripting.h. Там уже есть примеры опкодов, я определил свои для минимально необходимого запуска игры:

Код: C++
  1. const SCRIPT_COMMAND set_camera                         = { 0x03CB, "fff" };            // x, y, z
  2. const SCRIPT_COMMAND refresh_game_renderer              = { 0x04E4, "ff" };             // x,y
  3. const SCRIPT_COMMAND set_player_angle                   = { 0x0171, "vf" };             // PLAYER_CHAR pointer, angle
  4. const SCRIPT_COMMAND set_camera_behind_player           = { 0x0373, "" };               //
  5. const SCRIPT_COMMAND set_current_time                   = { 0x00C0, "ii" };             // Hours, Minutes
  6. const SCRIPT_COMMAND create_weapon_pickup               = { 0x032B, "iiifffv" };        // id, type, ammo, x, y, z, pickup pointer
  7.  

Адрес в фигурных скобках это и есть опкод, дальше идет форматная строка типов параметров опкода, думаю из примеров легко понять как их ставить.
Ну и теперь можно скриптить что угодно в своем плагине, используя весь функционал с++, чтение настроек из файлов, классы, массивы и т.д.
Вот пример начала игры с расставленными пикапами оружия, добавьте к этому припаркованные авто, плотность траффика, локации банд и прочее и получите полноценную игру.
Единственный открытый вопрос - это как писать миссии при таком подходе и работать с сэйвами, но для глобальных модов, где обычно используется чистый мэйн это неактуально. Можно придумать свой механизм управления миссиями средствами с++.

Код: C++
  1. #include "stdafx.h"
  2. #include "GameScripting.h"
  3.  
  4. bool NewGame = true;
  5.  
  6. DWORD   *dwPlayerChar   = (DWORD *) 0x821288;
  7. DWORD   *dwPlayerActor  = (DWORD *) 0x82128C;
  8. DWORD   *dwPlayer       = (DWORD *) 0x94AD28;
  9.  
  10. //--------------------------------------------------------------------------------
  11. //
  12. void TestPlayer()
  13. {
  14.         if (*dwPlayer)
  15.         {
  16.                 if (NewGame)    // Опкоды при старте игры
  17.                 {      
  18.                         NewGame = false;       
  19.  
  20.                         BYTE  *bPlayerBlock = (BYTE*)(*dwPlayer);                      
  21.                         float *X = (float*)(bPlayerBlock+0x34);
  22.                         float *Y = (float*)(bPlayerBlock+0x38);
  23.                         float *Z = (float*)(bPlayerBlock+0x3C);
  24.                        
  25.                         *X = 155.0f;    *Y = -510.0f;   *Z = 13.0f;
  26.  
  27.                         ScriptCommand(&set_camera, *X, *Y, *Z);
  28.                         ScriptCommand(&refresh_game_renderer,*X, *Y);
  29.                         ScriptCommand(&set_player_angle,dwPlayerChar, 230.0f);
  30.                         ScriptCommand(&set_camera_behind_player);
  31.                         ScriptCommand(&set_current_time,10,0);
  32.                         for (int i=0;i<10;i++)  
  33.                         {
  34.                                 DWORD generated;
  35.                                 ScriptCommand(&create_weapon_pickup,274+i,2,100,*X+8-i*0.1f,*Y-2*i,*Z,&generated);
  36.                         }
  37.                 }
  38.                 // Тут любые опкоды игрового процесса, выполняющиеся в цикле по времени
  39.         }
  40.         else NewGame = true;
  41. };
  42.  
  43. //--------------------------------------------------------------------------------
  44. //
  45. BOOL APIENTRY DllMain( HMODULE hModule,
  46.                        DWORD  ul_reason_for_call,
  47.                        LPVOID lpReserved
  48.                      )
  49. {
  50.     switch (ul_reason_for_call)
  51.     {
  52.     case DLL_PROCESS_ATTACH:
  53.                
  54.         SetTimer(0,0, 10, (TIMERPROC)TestPlayer);
  55.  
  56.         break;
  57.     case DLL_THREAD_ATTACH:
  58.     case DLL_THREAD_DETACH:
  59.     case DLL_PROCESS_DETACH:
  60.         break;
  61.     }
  62.     return TRUE;
  63. }
  64.  
« Последнее редактирование: Декабрь 13, 2013, 02:11:34 pm от xanser »

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 521
  • Репутация: +34/-0
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #1 : Декабрь 13, 2013, 02:06:28 pm »
Это SCM Hook называется?

Оффлайн xanser

  • Главный Модератор
  • Постоялец
  • *****
  • Сообщений: 598
  • Репутация: +92/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #2 : Декабрь 13, 2013, 02:12:34 pm »
Ну вроде как, просто он применялся для частного случая использования опкодов, но можно и полностью все на нем написать. У меня такая задача возникла, чтобы легко менять параметры опкодов, например считывая расположения оружия и припаркованных авто из файла

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 521
  • Репутация: +34/-0
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #3 : Декабрь 13, 2013, 02:32:41 pm »
Можно еще прототипами объявлять функции и методы классов и писать вообще как говориться на голом C++. Но сложность в другом, надо объявлять много и правильно, а там не мало всего.

Оффлайн xanser

  • Главный Модератор
  • Постоялец
  • *****
  • Сообщений: 598
  • Репутация: +92/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #4 : Декабрь 13, 2013, 02:41:12 pm »
Что-то мне кажется CLEO так и написан, завернут в asi-шку и считывает опкоды из внешних файлов, подставляя в таком формате. Но там все происходит по правилам скриптинга, а тут можно перемешивать со своим с++ кодом любой сложности. Я стараюсь частично заменять некоторые опкоды напрямую указателями на адреса, но действительно это еще копать и копать. Пока как затычки для аналогичных функций.

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 521
  • Репутация: +34/-0
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #5 : Декабрь 13, 2013, 02:44:35 pm »
CLEO это и есть плагин asi, его принцип прост, он подменяет какие-то скриптовые функции игры на свои + внедряет свой набор кодов. Сделан по принципу замен, авторы реверсили не которые функции gta vc.

Оффлайн mike43842

  • Прохожий
  • *
  • Сообщений: 110
  • Репутация: +1/-0
    • mike43842
    • Просмотр профиля
    • lol
Re: Альтернатива скриптингу
« Ответ #6 : Декабрь 13, 2013, 04:55:43 pm »
Круто!___))

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +3/-0
  • Its cool! Man
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #7 : Декабрь 16, 2013, 12:40:38 pm »
Многообещающий подход, c++ намного удобней и понятней.
« Последнее редактирование: Декабрь 16, 2013, 12:44:49 pm от graveman »

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 521
  • Репутация: +34/-0
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #8 : Декабрь 20, 2013, 07:41:07 pm »
Цитировать
Многообещающий подход

Что ты под этим подразумеваешь ?

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +3/-0
  • Its cool! Man
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #9 : Декабрь 23, 2013, 11:44:35 am »
Цитировать
Многообещающий подход

Что ты под этим подразумеваешь ?
Возможно, что на плюсах есть какие-то возможности, которых нет при применении опкодов.

Оффлайн xanser

  • Главный Модератор
  • Постоялец
  • *****
  • Сообщений: 598
  • Репутация: +92/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #10 : Февраль 11, 2014, 02:00:36 pm »
Пока не описаны все функции и методы, хочется вот еще о чем тут сказать. Можно получить доступ ко всем объектам игрового пространства, всему что летает, ездит и ходит. Захватив какого-то педа или машину вам скорее всего захочется что-то с ним сделать и пока основной вариант через опкоды, поэтому пишу здесь.  Я тут откопал интересный адресок 0x78F62C, с него начинается 250 блоков по 40 байт. Первый DWORD каждого блока это указатель на игровой объект. Первый блок скорее всего игрок, потом 10 блоков под что-то зарезервировано и начиная с 11-го по 250 идут "живые" объекты мира. Я сразу перешел по указателям и проверил id моделей по смещению +0x5C. Ну и для разминки я разблокировал коповские тачки, подсадил туда дополнительных копов, раздал прохожим что-то в руки и т.д. В общем полный контроль над городом.



Теперь самое важное, чему я не придал значения раньше. У spookie в GameScripting.cpp есть функции, позволяющие получить указатель на переменную, созданную опкодом, чтобы уже обращаться к ней как к объекту класса или структуры CPed, CVehicle.

Код: C++
  1. GameGetObject_t GameGetObject   = (GameGetObject_t)0x4BFF80;    // Offset for GetObjectPointer function in v1.0.
  2. GameGetVehicle_t GameGetVehicle = (GameGetVehicle_t)0x4BFFC0;   // Offset for GetVehiclePointer function in v1.0.
  3. GameGetActor_t GameGetActor     = (GameGetActor_t)0x4C0000;     // Offset for GetActorPointer function in v1.0.

Но еще важнее обратное - получить по найденному указателю его скриптовую переменную, чтобы применять к ней опкоды. Для этого в игре есть функции 0x4BFFE0 и 0x4C0020. Я описал их по аналогии в .h:

Код: C++
  1. typedef int (*GameGetRef_t)(DWORD *);

И в .cpp:

Код: C++
  1. GameGetRef_t GameGetVehicleRef = (GameGetRef_t)0x4BFFE0;       
  2. GameGetRef_t GameGetActorRef   = (GameGetRef_t)0x4C0020;

Ну и не вдаваясь в подробности, вот код, позволяющий вмешиваться в жизнь города:

Код: C++
  1. void TestGameObjects()
  2. {
  3.         for (int i=11;i<250;i++) // все живые объекты
  4.         {
  5.                 DWORD *GameObject = (DWORD *)((BYTE *)(0x78F62C)+i*40); // берем попавшийся объект
  6.                 if (*GameObject)
  7.                 {
  8.                         BYTE *ObjectBlock = (BYTE *)(*GameObject);
  9.                         DWORD *ObjectModelID = (DWORD *)(ObjectBlock+0x5C); // определяем id модели
  10.                         if (*ObjectModelID==156) // коповская тачка
  11.                         {
  12.                                 float *CopX = (float*)(ObjectBlock+0x34);
  13.                                 float *CopY = (float*)(ObjectBlock+0x38);
  14.  
  15.                                 if (sqrt((*fCoordX-*CopX)*(*fCoordX-*CopX)+(*fCoordY-*CopY)*(*fCoordY-*CopY))>100) // проверяем расстояние до игрока
  16.                                 {
  17.                                         BYTE *CopDoorStatus = ObjectBlock+0x230;
  18.                                         *CopDoorStatus=1; // открываем двери
  19.  
  20.                                         DWORD *CopDriver         = (DWORD *)(ObjectBlock+0x1A8);
  21.                                         DWORD *CopPassenger1 = (DWORD *)(ObjectBlock+0x1B0);
  22.                                         DWORD *CopPassenger2 = (DWORD *)(ObjectBlock+0x1B4);
  23.  
  24.                                         if ((*CopDriver)&&(!(*CopPassenger1))&&(!(*CopPassenger2))) // проверяем водителя и свободные места на заднем сиденье
  25.                                         {
  26.                                                 DWORD Police = GameGetVehicleRef((DWORD*)*GameObject); // получаем скиптовую переменную по указателю
  27.                                                 DWORD Cop = 0;
  28.                                                 ScriptCommand(&create_passenger_in_car, &Police, 6, 1, 1, &Cop); // подсаживаем нового копа
  29.                                                 ScriptCommand(&remove_references_to_actor, &Cop);
  30.                                                 ScriptCommand(&create_passenger_in_car, &Police, 6, 1, 2, &Cop); // подсаживаем нового копа
  31.                                                 ScriptCommand(&remove_references_to_actor, &Cop);
  32.                                                 ScriptCommand(&remove_references_to_car, &Police);
  33.                                         }
  34.                                 }
  35.                         }
  36.                         if ((*ObjectModelID>8)&&(*ObjectModelID<83)) // берем педа из трафика
  37.                         {
  38.                                 DWORD Ped = GameGetActorRef((DWORD*)*GameObject); // скриптовая переменная педа
  39.                                 ScriptCommand(&set_actor_armed_weapon_to, &Ped, 3);
  40.                                 ScriptCommand(&give_actor_weapon_ammo,    &Ped, 3, 1);
  41.                                 ScriptCommand(&set_actor_weapon_ammo_to,  &Ped, 3, 1);
  42.                                 ScriptCommand(&set_actor_anim,  &Ped, 29, 99999999);
  43.                                 ScriptCommand(&remove_references_to_actor,&Ped);
  44.                         }
  45.                 }
  46.         }
  47. }

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 521
  • Репутация: +34/-0
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #11 : Февраль 11, 2014, 04:21:28 pm »
Цитировать
раздал прохожим что-то в руки и т.д

Если ты про оружие, то это есть такой объект у них, как CWeaponSlot. Сейчас его просто называют CWeapon, так там есть патроны, патроны в обойме и другие методы для выстрелов, индекс.

Вот тут не много описан, в vcWeapon.h и vcWeapon.cpp. Стараюсь время уделять больше сайту, но иной раз и за финансов приходиться отвлекаться на другие вещи.

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +3/-0
  • Its cool! Man
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #12 : Март 18, 2014, 12:33:01 pm »
xanser, это круто просто. Жаль пока времени нет поковыряться.

Оффлайн xanser

  • Главный Модератор
  • Постоялец
  • *****
  • Сообщений: 598
  • Репутация: +92/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
Re: Альтернатива скриптингу
« Ответ #13 : Апрель 17, 2014, 07:59:45 am »
Я тут откопал интересный адресок 0x78F62C...

Странная особенность обнаружилась, если убрать папку Audio (когда звук вообще не нужен и чтобы быстрее грузилось), то эта область памяти оказывается пустой и где храняться объекты, я уже найти не смог, похожего участка уже нет. Очень странно...

Оффлайн Shagg_E

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 705
  • Репутация: +24/-4
  • Изобретательный Рукожопъ
    • Просмотр профиля
    • NewRockstar
Re: Альтернатива скриптингу
« Ответ #14 : Апрель 17, 2014, 06:30:39 pm »
А с остальными участками памяти как без Audio? Почему-то кажется, что из-за этого множество адресов сдвинутся