GTA Builder Форум

GTA Vice City => Программирование => Тема начата: xanser от Декабрь 13, 2013, 01:51:39 pm

Название: Альтернатива скриптингу
Отправлено: xanser от Декабрь 13, 2013, 01:51:39 pm
Решил поделиться своим подходом. Я не люблю скриптить, поэтому решил вычистить под ноль все скрипты и использовать опкоды непосредственно в с++. В будущем надеюсь заменить опкоды на функции, насколько возможно.
Это запуск игры без сриптов, если можно так сказать, где определены координаты игрока и расставлено оружие средствами с++:

(http://s6.postimg.org/rym9yljwh/scr002.jpg)

Вот мой 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.  
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Декабрь 13, 2013, 02:06:28 pm
Это SCM Hook называется?
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Декабрь 13, 2013, 02:12:34 pm
Ну вроде как, просто он применялся для частного случая использования опкодов, но можно и полностью все на нем написать. У меня такая задача возникла, чтобы легко менять параметры опкодов, например считывая расположения оружия и припаркованных авто из файла
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Декабрь 13, 2013, 02:32:41 pm
Можно еще прототипами объявлять функции и методы классов и писать вообще как говориться на голом C++. Но сложность в другом, надо объявлять много и правильно, а там не мало всего.
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Декабрь 13, 2013, 02:41:12 pm
Что-то мне кажется CLEO так и написан, завернут в asi-шку и считывает опкоды из внешних файлов, подставляя в таком формате. Но там все происходит по правилам скриптинга, а тут можно перемешивать со своим с++ кодом любой сложности. Я стараюсь частично заменять некоторые опкоды напрямую указателями на адреса, но действительно это еще копать и копать. Пока как затычки для аналогичных функций.
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Декабрь 13, 2013, 02:44:35 pm
CLEO это и есть плагин asi, его принцип прост, он подменяет какие-то скриптовые функции игры на свои + внедряет свой набор кодов. Сделан по принципу замен, авторы реверсили не которые функции gta vc.
Название: Re: Альтернатива скриптингу
Отправлено: mike43842 от Декабрь 13, 2013, 04:55:43 pm
Круто!___))
Название: Re: Альтернатива скриптингу
Отправлено: graveman от Декабрь 16, 2013, 12:40:38 pm
Многообещающий подход, c++ намного удобней и понятней.
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Декабрь 20, 2013, 07:41:07 pm
Цитировать
Многообещающий подход

Что ты под этим подразумеваешь ?
Название: Re: Альтернатива скриптингу
Отправлено: graveman от Декабрь 23, 2013, 11:44:35 am
Цитировать
Многообещающий подход

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

(http://s6.postimg.org/55hctdpj5/scr000.jpg) (http://s6.postimg.org/j0fnbujy9/scr001.jpg) (http://s6.postimg.org/lj1ccj5oh/scr002.jpg) (http://s6.postimg.org/e4c0k5jsx/scr004.jpg)

Теперь самое важное, чему я не придал значения раньше. У 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. }
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Февраль 11, 2014, 04:21:28 pm
Цитировать
раздал прохожим что-то в руки и т.д

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

Вот тут (http://forum.gtabuilder.ru/index.php?topic=117.0) не много описан, в vcWeapon.h и vcWeapon.cpp. Стараюсь время уделять больше сайту, но иной раз и за финансов приходиться отвлекаться на другие вещи.
Название: Re: Альтернатива скриптингу
Отправлено: graveman от Март 18, 2014, 12:33:01 pm
xanser, это круто просто. Жаль пока времени нет поковыряться.
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Апрель 17, 2014, 07:59:45 am
Я тут откопал интересный адресок 0x78F62C...

Странная особенность обнаружилась, если убрать папку Audio (когда звук вообще не нужен и чтобы быстрее грузилось), то эта область памяти оказывается пустой и где храняться объекты, я уже найти не смог, похожего участка уже нет. Очень странно...
Название: Re: Альтернатива скриптингу
Отправлено: Shagg_E от Апрель 17, 2014, 06:30:39 pm
А с остальными участками памяти как без Audio? Почему-то кажется, что из-за этого множество адресов сдвинутся
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Апрель 17, 2014, 07:22:50 pm
Я предполагал, что адреса до 0xA10BA1 статические, точнее так и есть, сдвига не должно быть, просто тут какая-то особенность заполнения, какая связь со звуком пока не понятно. И куда девается этот участок, я его нигде больше не обнаружил.
Название: Re: Альтернатива скриптингу
Отправлено: былтаков от Апрель 17, 2014, 09:57:49 pm
удаление папки аудио - это самый легкий способ NO CD
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Июль 23, 2014, 05:28:32 pm
Можно еще прототипами объявлять функции и методы классов и писать вообще как говориться на голом C++. Но сложность в другом, надо объявлять много и правильно, а там не мало всего.

Пожалуй, это действительно наилучшая альтернатива скриптингу, и как оказалось, не так сложно объявлять свои функции, повторяющие хотя бы простые опкоды.
В заключение темы приведу пару упрощенных рабочих аналогов опкодов.

Опкод 02CE, вычисляющий z-координату поверхности под заданной точкой:
Код: C++
  1. //.h
  2. auto GroundZ = (float  (__cdecl*)(float x,float y,float z,BYTE))0x4D53A0;
  3.  
  4. //.cpp
  5. z = GroundZ(100.0, 100.0, 15.0, 0); // 0x4558D1 @@opcode_02CE: %4d% = ground_z %1d% %2d% %3d%

Опкоды 0213, 032B и др., создающие пикапы:
Код: C++
  1. //.h
  2. auto CreatePickup = (int (__cdecl*)(float x, float y, float z, int id, int type, int ammo, int, char, int))0x4418C0;
  3.  
  4. //.cpp
  5. CreatePickup(100.0, 100.0, 15.0, 280, 2, 500, 0, 0, 0); // 0x45B7D7 @@opcode_032B: %7d% = create_weapon_pickup %1t% %2d% ammo %3d% at %4d% %5d% %6d%

Связка опкодов 014B, 014C - парковка машин (с одновременным увеличением их лимита с 185 до 1000):
Код: C++
  1. //.h
  2. #pragma pack (push, 1)
  3. struct  CCarGenerator
  4. {
  5.         DWORD mi;
  6.         RwV3d pos;
  7.         DWORD angle;
  8.         WORD  color1;
  9.         WORD  color2;
  10.         BYTE  alarm;
  11.         BYTE  doorLock;
  12.         BYTE  field_1A;
  13.         BYTE  field_1B;
  14.         WORD  field_1C;
  15.         WORD  field_1E;
  16.         DWORD time;
  17.         DWORD ProcessedVehicleHandle;
  18.         WORD  field_28;
  19.         BYTE  field_2A;
  20.         BYTE  __padding;
  21. };
  22. #pragma pack (pop)
  23. CCarGenerator   *CarGenerator;
  24. auto AddParkedGenerator = (int (__cdecl*)(float x,float y,float z,float angle,int id,int color1,int color2,char alarm,char locked,char,int,int))0x5A6C10;
  25.  
  26. //.cpp
  27. DWORD *dwParkedCarLimit = (DWORD *) 0x5A6C16;
  28. DWORD *dwParkedCarCount = (DWORD *) 0x97F2A8;
  29. DWORD *dwCurrentTime = (DWORD *) 0x974B2C;
  30.  
  31. CarGenerator = new CCarGenerator[1000]; // original 185
  32. WriteDWORD(dwParkedCarLimit,1000); // original 185
  33. WriteDWORD((DWORD*)0x4537A9,(DWORD)CarGenerator);
  34. WriteDWORD((DWORD*)0x5A6C5F,(DWORD)CarGenerator);
  35. WriteDWORD((DWORD*)0x5A6CC3,(DWORD)CarGenerator);
  36. WriteDWORD((DWORD*)0x5A69DB,(DWORD)CarGenerator);
  37. WriteDWORD((DWORD*)0x5A6B16,(DWORD)CarGenerator);
  38. WriteDWORD((DWORD*)0x5A69E6,(DWORD)&CarGenerator->pos.x);
  39. WriteDWORD((DWORD*)0x5A6B22,(DWORD)&CarGenerator->pos.x);
  40. WriteDWORD((DWORD*)0x5A69F1,(DWORD)&CarGenerator->pos.y);
  41. WriteDWORD((DWORD*)0x5A6B2A,(DWORD)&CarGenerator->pos.y);
  42. WriteDWORD((DWORD*)0x5A69FC,(DWORD)&CarGenerator->pos.z);
  43. WriteDWORD((DWORD*)0x5A6B35,(DWORD)&CarGenerator->pos.z);
  44. WriteDWORD((DWORD*)0x5A6A07,(DWORD)&CarGenerator->angle);
  45. WriteDWORD((DWORD*)0x5A6B40,(DWORD)&CarGenerator->angle);
  46. WriteDWORD((DWORD*)0x5A6A14,(DWORD)&CarGenerator->color1);
  47. WriteDWORD((DWORD*)0x5A6B4C,(DWORD)&CarGenerator->color1);
  48. WriteDWORD((DWORD*)0x5A6A21,(DWORD)&CarGenerator->color2);
  49. WriteDWORD((DWORD*)0x5A6B5C,(DWORD)&CarGenerator->color2);
  50. WriteDWORD((DWORD*)0x5A6A2A,(DWORD)&CarGenerator->alarm);
  51. WriteDWORD((DWORD*)0x5A6B65,(DWORD)&CarGenerator->alarm);
  52. WriteDWORD((DWORD*)0x5A6A33,(DWORD)&CarGenerator->doorLock);
  53. WriteDWORD((DWORD*)0x5A6B6E,(DWORD)&CarGenerator->doorLock);
  54. WriteDWORD((DWORD*)0x5A6A3C,(DWORD)&CarGenerator->field_1A);
  55. WriteDWORD((DWORD*)0x5A6B77,(DWORD)&CarGenerator->field_1A);
  56. WriteDWORD((DWORD*)0x5A6A49,(DWORD)&CarGenerator->field_1C);
  57. WriteDWORD((DWORD*)0x5A6B85,(DWORD)&CarGenerator->field_1C);
  58. WriteDWORD((DWORD*)0x5A6A56,(DWORD)&CarGenerator->field_1E);
  59. WriteDWORD((DWORD*)0x5A6B95,(DWORD)&CarGenerator->field_1E);
  60. WriteDWORD((DWORD*)0x5A6A61,(DWORD)&CarGenerator->time);
  61. WriteDWORD((DWORD*)0x5A6BA1,(DWORD)&CarGenerator->time);
  62. WriteDWORD((DWORD*)0x5A6A6C,(DWORD)&CarGenerator->ProcessedVehicleHandle);
  63. WriteDWORD((DWORD*)0x5A6BAC,(DWORD)&CarGenerator->ProcessedVehicleHandle);
  64. WriteDWORD((DWORD*)0x5A6A79,(DWORD)&CarGenerator->field_28);
  65. WriteDWORD((DWORD*)0x5A6BB8,(DWORD)&CarGenerator->field_28);
  66. WriteDWORD((DWORD*)0x5A6A85,(DWORD)&CarGenerator->field_2A);
  67. WriteDWORD((DWORD*)0x5A6BC1,(DWORD)&CarGenerator->field_2A);
  68.  
  69. // 0x4536DE @@opcode_014B: %13d% = init_parked_car_generator %5t% %6d% %7d% %8d% alarm %9d% door_lock %10d% %11d% %12d% at %1d% %2d% %3d% angle %4d%
  70. AddParkedGenerator(100.0,100.0,15.0,90.0,162,-1,-1,1,0,0,0,0); // rhino
  71. // 0x45378A @@opcode_014C: set_parked_car_generator %1d% cars_to_generate_to %2d%
  72. CarGenerator[0].time = *dwCurrentTime+4;
  73. CarGenerator[0].field_28 = 0xFFFF;
  74. (*dwParkedCarCount)++;
  75.  
  76. // 0x4536DE @@opcode_014B: %13d% = init_parked_car_generator %5t% %6d% %7d% %8d% alarm %9d% door_lock %10d% %11d% %12d% at %1d% %2d% %3d% angle %4d%
  77. AddParkedGenerator(200.0,100.0,15.0,180.0,155,-1,-1,1,0,0,0,0); // hunter
  78. // 0x45378A @@opcode_014C: set_parked_car_generator %1d% cars_to_generate_to %2d%
  79. CarGenerator[1].time = *dwCurrentTime+4;
  80. CarGenerator[1].field_28 = 0xFFFF;
  81. (*dwParkedCarCount)++;
  82.  

Можно и в точности выписать опкод, например 01EC, увеличивающий массу машины:
Код: C++
  1. //.cpp
  2. void SetVehicleHeavy(CVehicle *Vehicle, bool Heavy)
  3. {
  4.         if (Heavy)
  5.         {
  6.                 Vehicle->field_11A = Vehicle->field_11A & 254 | 1;
  7.                 Vehicle->fMass = Vehicle->HandlingData->fMass * 3;
  8.                 Vehicle->fTurnMass = Vehicle->HandlingData->fTurnMass * 5;
  9.         }
  10.         else
  11.         {
  12.                 Vehicle->field_11A = Vehicle->field_11A & 254;
  13.                 Vehicle->fMass = Vehicle->HandlingData->fMass;
  14.                 Vehicle->fTurnMass = Vehicle->HandlingData->fTurnMass;
  15.         }
  16. }
  17.  
  18. //.cpp
  19. SetVehicleHeavy(PlayerPed->ped.m_pVehicle,1); // 0x453516 @@opcode_01EC: make_car %1d% very_heavy %2h%
  20.  
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Июль 23, 2014, 08:02:14 pm
Цитировать
Опкоды 0213, 032B и др., создающие пикапы:

И кроме того, можно сразу получить доступ к полям объектов, что существенно круто, например как:


Код: C++
  1.  
  2. CPed * myPed = new CPed;
  3. myPed->health = 100.0;
  4.  
  5.  

Название: Re: Альтернатива скриптингу
Отправлено: xanser от Июль 24, 2014, 05:40:43 am
Глядя на все это многообразие функций и классов, придуманных R*, с которыми думаю им было удобно работать, становится непонятным, зачем было оборачивать все это еще и в скрипты, ведь они намного "деревяннее" и не включают всего, почему бы напрямую не писать миссии. Или один разработчик сделал скриптовый движок, а второй скриптер писал на нем миссии, но наверняка он постоянно пинал первого, чтобы тот добавлял какие-то недостающие опкоды, под которые приходилось опять создавать новые функции. А пока второй скриптил миссии, первому приходилось напрямую программить геймплэй, типа копов, траффика и т.д. По сути они делали одно и то же разными путями и уверен, что main.scm был закончен в то же время, когда откомпилися последний раз gta-vc.exe. Ладно бы если R* выложила свой интрумент для скриптинга, чтобы мы могли писать аддоны, или сами бы раз в год выпускали дополнительный скриптовый контент, тогда был бы смысл. На мой взгляд вместо скриптов лучше бы писали dll-плагин с миссиями. А так лишняя трата времени, не люблю я скриптинг.
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Июль 24, 2014, 09:18:13 am
Не совсем так. Как раз миссии писать на C++ чистом, очень не благородное дело, там ты не каких вайтов не сделаешь, и лишишься массу удобств. Именно скриптовая система, это самая гибкая система. Имеет ряд значительных преимуществ и как правило теперь каждые разработчики игр, ее используют. Особое преимущество, что гигантский проект не нужно каждый раз перекомпелировать,в скриптах язык может быть абсолютно любой на вкус, а также появляется масса мощнейших возможностей.
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Июль 24, 2014, 01:24:43 pm
Но ведь скрипт это последовательность опкодов, а каждый опкод уже расписан в exe через какие-то функции, поля объектов и методы классов. Это то же самое, если завернуть не в опкоды, а в нормальные си-функции, половина из которых уже готовы в том же виде, что и опкод. Тогда не нужно придумывать кучу ненужных опкодов, описывающих присвоение значений, условные операторы, нечитаемые циклы и т.д. Тот же Wait можно посмотреть как описан через currentTime, так почему бы сразу не обращаться к функции через какой-нибудь Wait(1000); если он уже описан на си самими разработчиками при создании опкодов. Как может скрипт быть более гибким, чем тот си-код, который его описывает. Повторюсь, что гибкость могла бы быть, если бы скиптовать можно было дополнительно, но сами разработчики такого инструмента не предоставили.
Не знаю, чем плохо сразу писать миссию, грубо говоря так:

void MainThread()
{
    Wait(0);
    Player::CreatePlayerPed(x,y,z);
    Player::SetHealth(100);
    SetTime(12,0);
    SetWeather(5);
    SetTrafficDensity(100);
.......
}

При этом можно на ходу придумывать новые функции, а не ограничиваться набором опкодов, захотелось какой-нибудь:
void Player::GetTaxi()
{
    Wait(0);
    CVehicle *Taxi = FindRandomCar(x,y,z);
    if (Taxi)
        Player::SetAsPassenger(Taxi);
.......
}

По поводу компиляции, в exe это конечно заворачивать не нужно, я бы наоборот вынес оттуда многое, но что мешает сделать mission.dll как аналог main.scm
Я так понимаю, этот сайт к тому и подталкивает. Я например научился запускать игру без main.scm, но пока с некоторыми багами.
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Июль 24, 2014, 01:39:31 pm
Код: C++
  1.   Wait(0);
  2.     CVehicle *Taxi = FindRandomCar(x,y,z);
  3.     if (Taxi)
  4.         Player::SetAsPassenger(Taxi);

Вот именно, что не выйдет, приостановить поток. Если его приостановить, то полностью будет замирание типа как sleep. И самое печально, сохранения/загрузка игры, например в скриптовой машине, можно сохранить позиции скриптовых, потоков, состояние переменных и много масса рутиных вещей и затем это все загрузить.
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Июль 24, 2014, 01:48:51 pm
Ну да, ты прав, так в лоб конечно не получится, следующия по коду команда пойдет сразу же, но думаю можно придумать свою систему потоков через SetTimer(0,0, wait, (TIMERPROC)...), а внутри них незачем приостанавливать, просто проверять условия, и срабатывать "в холостую", ожидая проверки условия на следующем по таймеру запуске. Да думаю, все это решаемо при желании.
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Июль 24, 2014, 02:33:49 pm
Цитировать
SetTimer(0,0, wait, (TIMERPROC)...)

Лучше не надо SetTimer. Для этого уже есть сам игровой цикл игры, про который много раз в статях упоминал. Там можно все сверять с таймерами, но все будет геморно...
Название: Re: Альтернатива скриптингу
Отправлено: Jak łaska za praca от Июль 24, 2014, 02:48:14 pm
А кто думает про мою идею с входами и выходами.

Например у нас есть описана для своих целей сущность gamerules у неё есть вход MissionBigFail.
И автомобиль с выходом OnDeath по имененам мы можем активировать gamerules->MissionBigFail провалив миссию например.
Это хорошо тем что мы можем разделить миссии по файлам и переключаться между ними прошли миссию старый в помойку загружаем новый.
А также появляется побочная фишка которая может дать возможность сохранения миссий восстановив стадии сушностей.
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Июль 24, 2014, 02:53:57 pm
А может для тренировки мозгов сделать что-то вот такое, т.е. описать wait и систему условных операторов так, чтобы происходили прыжки "в холостую", пока каждый не отработает со своего места, потом прыжок на следующую за ним инструкцию. Что-то больше на асм уже похоже.

Код: C++
  1. --> void Thread()                            10 раз -->        100 раз -->     // остальные -->
  2. |   {                                                  |                  |    // wait-ы       |
  3. |   ........                                           |                  |                    |
  4. |           Wait(100);   // 10 x 10 ms              <--                   |                    |
  5. |   ........                                        -->                   |                    |
  6. |   ........                                           |                  |                    |
  7. |           Wait(1000);  // 100 x 10 ms                |               <--                     |
  8. |   ........                                           |               -->                     |
  9. |   ........                                           |                  |                   ..
  10. <-- }                                        <---------         <---------           <---------
  11.  
  12. SetTimer(0,0, 10, (TIMERPROC)Thread); // 10 ms
Название: Re: Альтернатива скриптингу
Отправлено: Jak łaska za praca от Июль 24, 2014, 03:11:24 pm
А моя идея с файликами *.ent пригодна для применения?
Название: Re: Альтернатива скриптингу
Отправлено: xanser от Июль 24, 2014, 03:17:17 pm
Цитировать
SetTimer(0,0, wait, (TIMERPROC)...)

Лучше не надо SetTimer. Для этого уже есть сам игровой цикл игры, про который много раз в статях упоминал...

Вот кстати вопрос о производительности. Я так понимаю, тут предлагается сделать инжект в пустую функцию в районе прорисовки hud-а, но если плагин большой и запускает в единицу времени кучу всяких функций, то все они будут грузить проц, а hud будет ждать, в то время как SetTimer как я понимаю будет работать в параллельном потоке, не задерживая прорисовку, а вклиниваясь, когда ему будет выделяться время.
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Июль 24, 2014, 03:34:13 pm
Разницы в этом нет, не что не загружается, так как HUD и прочии процедуры, все в главном игровом цикле обрабатывается. Более того, в таймере не выйдет делать Рендер сцен...
Название: Re: Альтернатива скриптингу
Отправлено: Jak łaska za praca от Июль 25, 2014, 06:01:24 pm
В Gta Vice City есть пункт в меню который ограничивает fps, если его выключить функция прорисовки HUD будет вызываться чаще?
Название: Re: Альтернатива скриптингу
Отправлено: Sektor от Июль 25, 2014, 09:21:55 pm
Цитировать
В Gta Vice City есть пункт в меню который ограничивает fps, если его выключить функция прорисовки HUD будет вызываться чаще?

Да, на всю существующую мощь железа.
Название: Re: Альтернатива скриптингу
Отправлено: Jak łaska za praca от Июль 26, 2014, 12:51:14 am
На частоту просчёта физики не влияет? Хотя наверно частота не меняется, появляется интерполяция.