GTA Builder Форум

GTA Vice City => Программирование => Тема начата: DK от Май 02, 2016, 09:49:53 pm

Название: Написание плагина. Настройка проекта
Отправлено: DK от Май 02, 2016, 09:49:53 pm
В этой статье я опишу создание плагина для GTA. Основное внимание уделю созданию и настройке проекта.
Я использую Visual Studio 2017. В открытом доступе есть Community версия этого продукта. Впрочем, найти Pro или Enterprise версию тоже не сложно.
Ах, да... Что требуется от вас:
-Наличие игры
-Умение писать код (если вы до этого не занимались скриптингом - возможно, лучше стоит начать с него)
-Базовые знания C/C++ (хотя, можно и без этого, как я в своё время  :P)
-Желание познавать и... время.


Напомню, что ASI-плагин - это динамическая библиотека с расширением .asi, которая подгружается (ASI-Loader'ом) и прикрепляется к процессу игры.
Итак, поехали.

Инструкция (https://github.com/DK22Pac/plugin-sdk/wiki)
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Май 03, 2016, 12:46:24 am
Класс! Скорее всего, как будет возможность - перейду с VS 2010 на 2015, ибо первый у меня глючит.

Хотелось бы туториал по вызову перед стартом игры окна с выбором одного из 3х пунктов.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Май 03, 2016, 10:55:49 am
Shaggy, для этого нужно использовать кастомный ASI-Loader (он загружает библиотеки при загрузке приложения).
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Май 03, 2016, 11:50:59 am
Это уже есть, и я даже реализовал(спс Sector-у и xanser-у) то, что мне нужно(подмена имен загружаемых файлов и пара мелочей), всё работает, однако через ini, а хотелось бы научиться создавать окно с выбором пункта, ибо в ini у меня всего лишь один пункт настройки(глупо создавать ini ради одной, пускай и самой важной настройки) и вообще - по многим причинам нужно именно окно, а не ini.
Нужно окно по типу такого (http://gta.nick7.com/programs/videomode/videomode-003.png).
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Май 03, 2016, 11:57:31 am
Shaggy, ты имеешь ввиду окно Windows или настройку как пункт в меню?
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Май 03, 2016, 11:58:03 am
Окно Windows (http://gta.nick7.com/programs/videomode/videomode-003.png)
Название: Re: Написание плагина. Настройка проекта
Отправлено: xanser от Май 03, 2016, 06:03:46 pm
А я бы хотел полноценное окно для самой игры. Мне кажется widescreen вайсу не подходит и приходится использовать олдскульный квадратный экран, да и удобно было бы следить за происходящим в системном трее.

DK можно уточнить? Раньше плагин подключался в виде функции в такой конструкции:
Код: C++
  1. BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
  2. {
  3.         switch (ul_reason_for_call)
  4.         {
  5.         case DLL_PROCESS_ATTACH:
  6.                 LoadViceCityPlugin();
  7.                 break;
  8.         case DLL_PROCESS_DETACH:
  9.                 break;
  10.         }
  11.         return TRUE;
  12. }

В твоем варианте это все уже не нужно и достаточно создать экземпляр класса, что автоматически вызовет конструктор и по пути все пропатчит?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Май 03, 2016, 07:03:38 pm
Shaggy, конкретно по этому не планировал делать туториал. Но можно глянуть, как это сделано в примерах RenderWare. Наверняка там MFC используется.
xanser, да. Так тоже можно. А если надо что-то сделать при детаче - нужно писать это в деструктор.
Код: C++
  1. class MyPlugin{
  2. public:
  3.     MyPlugin(){
  4.         // on attach
  5.     }
  6.  
  7.     ~MyPlugin(){
  8.         // on detach
  9.     }
  10. };
  11.  
  12. MyPlugin myPlugin; // создали экземпляр класса в глобальном пространстве (глобальный обьект)
Цитировать
Объявление функции в глобальной области видимости вводит глобальную функцию, а объявление переменной – глобальный объект. Глобальный объект существует на протяжении всего времени выполнения программы. Время жизни глобального объекта начинается с момента запуска программы и заканчивается с ее завершением.
Т.е. обьект будет создан при аттаче dll (будет вызван конструктор), а разрушен - при детаче (будет вызван деструктор).
Название: Re: Написание плагина. Настройка проекта
Отправлено: Sektor от Май 03, 2016, 09:25:47 pm
xanser, да потому-что объект будет создан, так сказать компилятором и уничтожен тоже, иначе говоря компилятор позаботиться обо всем сам, в данном случае.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Май 07, 2016, 02:36:19 pm
Вынесено в шапку.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 11, 2016, 10:36:17 am
Создал шаблон для Vice City.
Правда, там идёт привязка к несуществующему plugin_vc.
https://github.com/DK22Pac/plugin-sdk/tree/master/extra/VS%20templates
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Июнь 11, 2016, 11:05:15 am
Круто! Жаль, у меня 2010, но я постараюсь за лето на 2015 пересесть)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 19, 2016, 03:43:30 pm
Я уже пишу плагины для VC c новым sdk  :P
Код: C++
  1. #include <plugin_vc.h>
  2. #include <d3dx8.h>
  3. #include <game_vc\RenderWare.h>
  4.  
  5. using namespace plugin;
  6.  
  7. class DXFont {
  8. public:
  9.     static ID3DXFont *m_pD3DXFont;
  10.  
  11.     static void InitFont() {
  12.         HFONT hFont = CreateFont(48, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,
  13.             CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_SWISS, "arial");
  14.         if (FAILED(D3DXCreateFont(_RwD3DDevice, hFont, &m_pD3DXFont)))
  15.             Error("Failed to create D3DX font!");
  16.     }
  17.  
  18.     static void DestroyFont() {
  19.         if (m_pD3DXFont) {
  20.             m_pD3DXFont->Release();
  21.             m_pD3DXFont = NULL;
  22.         }
  23.     }
  24.  
  25.     static void Draw() {
  26.         if (m_pD3DXFont) {
  27.             RECT rect;
  28.             rect.left = 0;
  29.             rect.top = 0;
  30.             rect.bottom = RsGlobal.maximumHeight;
  31.             rect.right = RsGlobal.maximumWidth;
  32.             m_pD3DXFont->DrawTextA("D3DXFont example for GTA Vice City", -1, &rect, DT_CENTER|DT_VCENTER,
  33.                 D3DCOLOR_RGBA(255, 255, 0, 255));
  34.         }
  35.     }
  36.  
  37.     DXFont() {
  38.         m_pD3DXFont = NULL;
  39.         Events::drawingEvent += Draw;
  40.         Events::initRwEvent += InitFont;
  41.         Events::shutdownRwEvent += DestroyFont;
  42.         Events::d3dLostEvent += DestroyFont;
  43.         Events::d3dResetEvent += InitFont;
  44.     }
  45. } dxFont;
  46.  
  47. ID3DXFont *DXFont::m_pD3DXFont;
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Июнь 19, 2016, 05:34:21 pm
Шикарно! Таким макаром, наверное можно и стандартные тексты выдавать windows-шрифтами!
Жаль правда, что с rwd3d9 (http://gtaforums.com/topic/819551-rwd3d9-d3d9-extension-for-rw/) конфликтует: при активированном в global.ini UseD3D8to9=1 иногда на пару секунд происходит нечто:
(http://funkyimg.com/p/2daho.jpg) (http://funkyimg.com/view/2daho)
(http://funkyimg.com/p/2dahp.jpg) (http://funkyimg.com/view/2dahp)
Закономерностей не заметил - просто изредка на секунду-другую весь GUI слетает и творится ад. Небо же начинает сохранять "следы" динамических объектов(видно на скринах). Если выставить UseD3D8to9=0 - такого не наблюдается. Очевидно, идет какой-то конфликт из-за того, что оба плагина(Ultimate asi loader (https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases) с rwd3d9 и этот плагин с текстом) юзают какие-то функции dxd8
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 19, 2016, 10:40:15 pm
Наверное, для d3d8tod3d9 стоит использовать DX9 sdk.
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Июнь 19, 2016, 11:57:52 pm
А есть и такой?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 29, 2016, 09:48:42 am
Дмитрий, во-первых, хочу сказать спасибо за проделанную работу по plugin-sdk, во-вторых, хочу сказать, что есть большое желание освоить написание плагинов для GTA. Года два назад я начал было, но инфы по написанию плагинов очень мало, написал один простой плагин и на этом как-то изучение остановилось. При написании клео скриптов мне в своё время очень помогли исходники скриптов Дениса. По ним-то я и научился писать высокоуровневый код, а начинал с написания в меточном стиле. Так вот к чему это я всё - хорошо бы здесь написать несколько простых примеров для SA, например, как создавать транспорт с определённой моделью в определённых координатах, работу с транспортом и компонентами транспорта и т.д. Хорошо бы, как сделано здесь http://ru-script.3dn.ru/publ/gta_iv/gta_iv/obzor_klassa_vehicles/35-1-0-177 (http://ru-script.3dn.ru/publ/gta_iv/gta_iv/obzor_klassa_vehicles/35-1-0-177) - тот же код в примере клео скрипта. Заранее спасибо.

Кстати, плагин для VC не собирается. У меня отсутствует dxd8.h. Можно заменить строчку на dxd9.h или где взять dxd8.h 
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июль 30, 2016, 12:44:50 am
kenking, уже поправил это (зависимость от d3d8) в VC, скачай репозиторий заново, или удали зависимость вручную (нужно убрать обьявление _D3D_INCLUDE в настройках проекта plugin_vc):
(http://i.imgur.com/sDFJmi5.png)
Plugin-sdk для VC пока что малофункционален, там даже нет классов CPed и CVehicle.

По работе с компонентами я сделаю примеры.

А пока что - такое видео.
https://www.youtube.com/watch?v=PVfC7YSOEQs (https://www.youtube.com/watch?v=PVfC7YSOEQs)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 30, 2016, 10:27:08 am
Цитировать
или удали зависимость вручную (нужно убрать обьявление _D3D_INCLUDE в настройках проекта plugin_vc):
Удалил. Плагин VC собрался. А пример VC_DXFont не идёт. Там же #include <d3dx8.h>

Цитировать
уже поправил это (зависимость от d3d8) в VC, скачай репозиторий заново
Скачал и новую версию. Здесь плагин VC не собирается. Вот
(http://savepic.net/8279914m.png) (http://savepic.net/8279914.png)


За пример в видео спасибо, но я имел ввиду создание транспорта в определённых координатах, с загрузкой модели
00A5: 0@ = create_car #PONY at 0.0 0.0 0.0
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июль 30, 2016, 06:05:42 pm
Цитировать
А пример VC_DXFont не идёт. Там же #include <d3dx8.h>

Всё верно. Чтобы его собрать нужен DX8 SDK.
https://drive.google.com/uc?export=download&id=0B3pQzS44FafdajNJcy1Cb2haUkk (https://drive.google.com/uc?export=download&id=0B3pQzS44FafdajNJcy1Cb2haUkk)
Включи обратно _D3D_INCLUDE в проекте plugin_vc, и настрой пути в Configuration Properties > VC++ Directories > Include Directories
http://i.imgur.com/n3DzDfe.png (http://i.imgur.com/n3DzDfe.png)
Это же надо сделать и для проекта VC_DXFont, +изменить путь вот тут к своей папке
http://i.imgur.com/cmL3Qlb.png (http://i.imgur.com/cmL3Qlb.png)

Скачал и новую версию. Здесь плагин VC не собирается. ВотУже добавил эти файлы.

За пример в видео спасибо, но я имел ввиду создание транспорта в определённых координатах, с загрузкой моделиОпкод 00A5 вызывает функцию CCarCtrl::CreateCarForScript. Пока что её нету в sdk (класс CCarCtrl пока что добавлен только частично), но я добавлю.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 31, 2016, 08:04:23 am
Теперь при сборке VC_DXFont выходит:
1>------ Перестроение всех файлов начато: проект: VC_DXFont, Конфигурация: Release Win32 ------
1>  Main.cpp
1>Main.obj : error LNK2001: неразрешенный внешний символ ""struct IDirect3DDevice8 * & _RwD3DDevice" (?_RwD3DDevice@@3AAPAUIDirect3DDevice8@@A)"
1>D:\Games\GTA Vice City 1.0\VC_DXFont.asi : fatal error LNK1120: неразрешенных внешних элементов: 1
========== Перестроение всех проектов: успешно: 0, с ошибками: 1, пропущено: 0 ==========
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июль 31, 2016, 08:21:13 am
kenking, plugin_vc пересобрал с _D3D_INCLUDE?

PS прямо сейчас занимаюсь классом CCarCtrl, после покажу пример создания транспорта и манипулирования им.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 31, 2016, 10:31:35 am
Цитировать
plugin_vc пересобрал с _D3D_INCLUDE?
Да.

Цитировать
прямо сейчас занимаюсь классом CCarCtrl, после покажу пример создания транспорта и манипулирования им.
Жду с нетерпением. Спасибо, что подробно всё разъясняешь.

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июль 31, 2016, 05:54:42 pm
Да.
Попробуй именно пересобрать (не Build, а Rebuild).
А после этого пересобери VC_DXFont.

Пример по спавну авто и управлению компонентом уже добавил.
https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_CreateCar/Main.cpp

Спрашивай если что-то не понятно.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 31, 2016, 07:51:08 pm
Цитировать
Попробуй именно пересобрать (не Build, а Rebuild).
А после этого пересобери VC_DXFont.
Так и делал. Пересобрал ещё раз - тоже самое.

Цитировать
Пример по спавну авто и управлению компонентом уже добавил.
За пример с подробными комментариями огромное спасибо!

Цитировать
Спрашивай если что-то не понятно.
Как вращать компоненты (CMatrix__rotateAroundX, CMatrix__rotateAroundY, CMatrix__rotateAroundZ)? Попробовал так:
if (automobile->m_aCarNodes[CAR_DOOR_RR])
automobile->m_aCarNodes[CAR_DOOR_RR]->modelling.at.z += 1.57f;
и так:
if (automobile->m_aCarNodes[CAR_DOOR_RF])
automobile->m_aCarNodes[CAR_DOOR_RF]->modelling.up.z += 1.57f;
Вот что вышло:  ;D
(http://savepic.net/8321684m.jpg) (http://savepic.net/8321684.jpg)

Сделай пожалуйста пример вращения компонента в цикле на транспорте игрока.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июль 31, 2016, 09:24:17 pm
Тут всё очень просто - метод CVehicle::SetComponentRotation(RwFrame* компонент, int ось, float угол(радианы), bool ресет_позиции_после_вращения).
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CAutomobile.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class RotateDoorExample {
  8. public:
  9.     static float m_angle;
  10.  
  11.     RotateDoorExample() {
  12.         Events::gameProcessEvent.Add([] {
  13.             CVehicle *vehicle = FindPlayerVehicle(0, false); // Находим авто игрока (0 - это индекс игрока)
  14.             if (vehicle && vehicle->m_dwVehicleClass == VEHICLE_AUTOMOBILE) { // если транспорт найден и его тип - автомобиль
  15.                 m_angle += 0.01f; // прибавляем 0.01 каждый фрейм
  16.                 if (m_angle > (_RW_pi * 2.0f)) // 2 pi = ~ 6,28
  17.                     m_angle = 0.0f; // обнуляем если дошли до максимума
  18.                 CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle); // приводим тип, чтобы обращаться к транспорту как к CAutomobile (CAutomobile - дочерний класс CVehicle)
  19.                 // Этот массив компонентов (m_aCarNodes @0x648) - уникален для CAutomobile. Имея указатель на CVehicle,
  20.                 // мы не сможем к нему обратиться - поэтому и приводим тип, предварительно убедившись, что транспорт - автомобиль.
  21.                 // У CBike, CTrain - также есть свои таблицы компонентов.
  22.                 if (automobile->m_aCarNodes[CAR_DOOR_RF])
  23.                     automobile->SetComponentRotation(automobile->m_aCarNodes[CAR_DOOR_RF], 0, m_angle, true); // здесь 0 - это ось (0,1,2 - соотв. X,Y,Z)
  24.                 if (automobile->m_aCarNodes[CAR_DOOR_LF])
  25.                     automobile->SetComponentRotation(automobile->m_aCarNodes[CAR_DOOR_LF], 0, m_angle, true);
  26.             }
  27.         });
  28.     }
  29. } example;
  30.  
  31. float RotateDoorExample::m_angle = 0.0f; // начальное значение = 0.0
Также есть функции RwMatrixRotate/RwFrameRotate, которые вращают матрицу/фрейм вокруг оси (ось можно задать своим вектором).
Ну и ещё вариант - вращение методами CMatrix: RotateX,RotateY,RotateZ и другими (см. файл CMatrix.h) Eсли будет нужно, то покажу на примере.

Вот тут более сложный вариант, с возможностью вращения по трём осям с помощью кватерниона.
https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_RotateDoor/Main.cpp (https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_RotateDoor/Main.cpp)
Вращение устанавливается методом
quat.Set(m_angle, 0.0f, 0.0f);где 3 параметра - вращение в радианах по осям y, z, x, соответственно.


По поводу VC_DXFont - в plugin_vc открой в студии файл game_vc/RenderWare.cpp и глянь, не закомменчена ли строка
LPDIRECT3DDEVICE8 &_RwD3DDevice = *(LPDIRECT3DDEVICE8 *)0x7897A8;как у меня на скрине
(http://i.imgur.com/paKRub2.png)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 01, 2016, 08:05:13 am
Цитировать
По поводу VC_DXFont - в plugin_vc открой в студии файл game_vc/RenderWare.cpp и глянь, не закомменчена ли строка
Вот:
(http://savepic.net/8307367m.png) (http://savepic.net/8307367.png)

С примерами буду разбираться, спасибо.

Ещё вопросы:
1) При обновлении sdk как лучше обновить у себя? Достаточно ли будет копировать новые файлы с заменой старых и пересобрать плагин? Шаблон пересобирать надо или нет?
2) В SA_CreateCar CStreaming::RequestModel(modelId, 2); цифра 2 что означает?
а в SA_PedSpawner стоит 0
CStreaming::RequestModel(modelID, 0);
UPD:
Вот здесь
void CVehicle::OpenDoor(CPed* ped, int componentId, eDoors door, float doorOpenRatio, bool playSound)eDoors door - что ставить? В клео я ставил 0-5, а здесь пишет аргумент типа int несовместим с параметром типа "eDoors".
Вот код моего скрипта (для GTA3, но не суть), не пойму, как сделать такое в плагине (для SA). Цикл for в частности, как реализовать wait 0? Можно пример? Пожалуйста  ???

{$CLEO .cs}
05E5: 15@ = game_version
if
  15@ == 0
then
    6@ = 0x52E660
    7@ = 0x545930
    8@ = 0x52EF90
    9@ = 0x52E750
else
    if
      15@ == 1
    then 
        6@ = 0x52E8A0
        7@ = 0x545B30
        8@ = 0x52F1D0
        9@ = 0x52E990
    else
        05DC: end_custom_thread
    end   
end
var
   12@: float
end

while true
wait 0
    if
      Player.Defined($PLAYER_CHAR)
    then
        if and
          $ONMISSION == 0
          Actor.Driving($PLAYER_ACTOR)
          80DE: not player $PLAYER_CHAR driving_vehicle_type #PREDATOR
          80DE: not player $PLAYER_CHAR driving_vehicle_type #SPEEDER
          80DE: not player $PLAYER_CHAR driving_vehicle_type #REEFER
          80DE: not player $PLAYER_CHAR driving_vehicle_type #GHOST
        then
            if
              05EE: key_pressed 219 // [
            then
                0@ = 17 // ComponentID
                1@ = 0  // eDoors
                gosub @open_component // капот
                repeat
                  wait 0
                until 85EE: not key_pressed 219 // [ 
            end
            if
              05EE: key_pressed 221 // ]
            then
                0@ = 18
                1@ = 1
                gosub @open_component // багажник
                repeat
                  wait 0
                until 85EE: not key_pressed 221 // ] 
            end
            if and
              05EE: key_pressed 186 // ;
              05EE: key_pressed 187 // =
            then
                0@ = 15
                1@ = 2
                gosub @open_component // левая передняя дверь
                repeat
                  wait 0
                until 85EE: not key_pressed 187 // = 
            end
            if and
              05EE: key_pressed 222 // '
              05EE: key_pressed 187 // =
            then
                0@ = 11
                1@ = 3
                gosub @open_component // правая передняя дверь
                repeat
                  wait 0
                until 85EE: not key_pressed 187 // = 
            end
            if and
              05EE: key_pressed 186 // ;
              05EE: key_pressed 189 // -
            then
                0@ = 16
                1@ = 4
                gosub @open_component // левая задняя дверь
                repeat
                  wait 0
                until 85EE: not key_pressed 189 // - 
            end
            if and
              05EE: key_pressed 222 // '
              05EE: key_pressed 189 // -
            then
                0@ = 12
                1@ = 5
                gosub @open_component // правая задняя дверь
                repeat
                  wait 0
                until 85EE: not key_pressed 189 // - 
            end
        end
    end
end

:open_component
if
  Actor.Driving($PLAYER_ACTOR)
then 
    03C0: 10@ = actor $PLAYER_ACTOR car
    05E7: 10@ = car 10@ struct
    0085: 11@ = 10@
    05E4: call_function_method 6@ struct 11@ num_params 1 pop 0 0@ {1..19} 2@ // IsComponentPresent
    if
      2@ == 1
    then
        0085: 3@ = 10@
        3@ += 0x288 // CDamageManager
        05E4: call_function_method 7@ struct 3@ num_params 1 pop 0 1@ {0..5} 4@ // GetDoorStatus
        if
          4@ <> 3
        then
            05E4: call_function_method 8@ struct 10@ num_params 1 pop 0 1@ {0..5} 5@ // IsDoorFullyOpen
            if
              5@ == 0
            then
                for 12@ = 0.0 TO 1.0 step 0.1
                   05E3: call_function_method 9@ struct 10@ num_params 3 pop 0 12@ 1@ 0@ {1..19} // CAutomobile__OpenDoor
                   wait 0
                end
            else
                for 12@ = 1.0 DOWNTO 0.0 step 0.1
                   05E3: call_function_method 9@ struct 10@ num_params 3 pop 0 12@ 1@ 0@ {1..19} // CAutomobile__OpenDoor
                   wait 0
                end
            end
        end 
    end 
end
return         
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 01, 2016, 10:02:53 pm
Вот:

Ты что-то не так сделал.
Открой настройки plugin_vc, должно быть определение _D3D_INCLUDE вот тут:
http://i.imgur.com/WyptPrQ.png (http://i.imgur.com/WyptPrQ.png)
У тебя проект plugin_vc сейчас скомпилирован без переменной _RwD3DDevice. Поэтому при попытке компилировать VC_DXFont ты получаешь ошибку с сообщением, что переменная не найдена.

1) При обновлении sdk как лучше обновить у себя? Достаточно ли будет копировать новые файлы с заменой старых и пересобрать плагин? Шаблон пересобирать надо или нет?

Можно и так. Скопировать, заменить, пересобрать plugin-sdk, пересобрать свои проекты. Шаблон менять не надо, если он не изменялся в репозитории.
Но я бы советовал использовать специальные утилиты для обновления/изменения:
Git for Windows (https://git-scm.com)
TortoiseGit (http://"https://tortoisegit.org)

Как с этим работать:
Скачать Git, установить, скачать TortoiseGit, установить. После этого в контекстном меню Windows появятся новые элементы.
Открыть страницу plugin-sdk на github, нажать кнопку "Clone or Download", скопировать ссылку:
(http://i.imgur.com/CdMvdeP.png)

Зайти в папку своих проектов (если там уже есть папка plugin-sdk - удалить её), нажать ПКМ, далее "Git Clone":
(http://i.imgur.com/LTKDVAc.png)

Если ссылка правильно скопировалась, то программа сама всё настроит:
(http://i.imgur.com/T2dizUI.png)

Нажать "ОК", после загрузки - "Close".

Теперь у тебя будет папка-репозитарий plugin-sdk.  :P
(http://i.imgur.com/pNlgHaz.png)

Как с ней работать:
Нажать ПКМ на папке (plugin-sdk), далее выбрать "Git Sync...":
(http://i.imgur.com/6Uyyx86.png)

Если надо обновить (перед этой процедурой желательно закрыть студию):
Нажимаешь кл. Pull
(http://i.imgur.com/z16OA7H.png)
После апдейтинга, ты увидишь список "коммитов", которые были загружены:
(http://i.imgur.com/FgIom7r.png)
Нажать Close.

Если ты внес изменения (например, добавил какую-то функцию, класс, что-то поправил, или даже добавил свой пример) и хочешь внести их в репозиторий:
Создать аккаунт на github.
Сообщить мне свой никнейм (мне нужно будет добавить его в список редакторов).

Нажать кл. Commit
(http://i.imgur.com/G5fQpd6.png)
Далее в окне "коммита" дать ему какое-то название (обычно описание изменений) и выбрать все файлы, которые ты изменял (по дефолту, новодобобавленные файлы не отмаечаются автоматом):
(http://i.imgur.com/arrNtDD.png)
Нажать Commit & Push (на кнопке Commit есть справа стрелка, открывающая доп. опции), после отправки нажать Close.

2) В SA_CreateCar CStreaming::RequestModel(modelId, 2); цифра 2 что означает?
а в SA_PedSpawner стоит 0
CStreaming::RequestModel(modelID, 0);

Это флаги загрузки и стриминга модели. Честно скажу - сам пока что не очень разобрался, как правильно их использовать. Примерно я их наименовал так:
enum eStreamingFlags {
    GAME_REQUIRED = 0x2, // Модель нужна игре?  (Сохранять в памяти, пока не будет вызвана SetModelIsDeletable, дальше - пусть игра сама решает, когда удалить модель)
    MISSION_REQUIRED = 0x4, // Модель нужна миссии? (Сохранять в памяти, пока не будет вызвана SetMissionDoesntRequireModel, дальше - пусть игра сама решает, когда удалить модель)
    KEEP_IN_MEMORY = 0x8, // Сохранять в памяти, пока мы сами не выгрузим модель (RemoveModel)
    PRIORITY_REQUEST = 0x10 // Особый приоритет загруки (в функции LoadAllRequestedModels есть параметр на загрузку только таких моделей)
};
Эти описания - примерные, я их только вчера составил, и не было времени всё проверить. Раньше этого перечисления я вообще нигде не находил :)
Вот здесь
void CVehicle::OpenDoor(CPed* ped, int componentId, eDoors door, float doorOpenRatio, bool playSound)eDoors door - что ставить? В клео я ставил 0-5, а здесь пишет аргумент типа int несовместим с параметром типа "eDoors".

Типы, которые начинаются с "e" - это enumerations (перечисления).
Тип eDoors обьявлен, но он пустой (в CDamageManager.h):
(http://i.imgur.com/xuwNt2Z.png)
Если ты знаешь значения этого перечисления - можешь их добавить в файле CDamageManager.h, и далее использовать их при вызове (напр. DOOR_FRONT_LEFT).
Если нужно использовать integer вместо enum - нужно привести тип:
static_cast<eDoors>(5)
Вот код моего скрипта (для GTA3, но не суть), не пойму, как сделать такое в плагине (для SA). Цикл for в частности, как реализовать wait 0? Можно пример? Пожалуйста  ???

Wait вообще не нужен (есть аналог в виде Sleep(), но использовать его где-либо не желательно). Ты же внедряешь свой код в код игры. Сделаешь где-то задержку - и игра тоже её сделает.
Тебе нужно мыслить по-другому - ты "вклиниваешься" в процесс каждый фрейм. Твой код (функция) будет вызываться один раз за фрейм - допустим, где-то в CGame::Process (если используется gameProcessEvent). Что делать в такой ситуации? Тут есть несколько вариантов. Самое простое - разделить код на отдельные процессы (состояния) и создать переменную, которая будет хранить id поточного процесса (состояния) (и которой будем переключать процессы (состояния))
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CAutomobile.h"
  4. #include "game_sa\CTimer.h"
  5. #include "game_sa\CMessages.h"
  6.  
  7. using namespace plugin;
  8.  
  9. class OpenDoorExample {
  10. public:
  11.     enum eOpenDoorState {
  12.         STATE_OPENING, // сейчас мы что-то открываем
  13.         STATE_CLOSING, // закрываем
  14.         STATE_WAITING  // ждём указаний
  15.     };
  16.  
  17.     static eOpenDoorState m_currentState; // наш статус
  18.     static CAutomobile *m_pCurrentCar; // авто, с которым сейчас что-то делаем
  19.     static float m_openingState; // статус открытия/закрытия
  20.     static int m_currentComponentId;
  21.     static eDoors m_currentDoorId;
  22.     static unsigned int m_nLastTimeWhenAnyActionWasEnabled;
  23.  
  24.     static void OpenComponent(CAutomobile *automobile, int componentId, eDoors doorId) {
  25.         if (automobile->IsComponentPresent(componentId)) {
  26.             if (automobile->m_damageManager.GetDoorStatus(doorId) != 3) { // 3 - это тоже член какого-то перечисления, напр. STATUS_DAMAGED
  27.                 m_pCurrentCar = automobile; // сохраняем все данные в переменные, чтобы потом заюзать при обработке STATE_OPENING/STATE_CLOSING (см. функцию Process)
  28.                 m_currentComponentId = componentId;
  29.                 m_currentDoorId = doorId;
  30.                 if (!automobile->IsDoorFullyOpen(doorId)) {
  31.                     m_currentState = STATE_OPENING; // переключаем статус
  32.                     m_openingState = 0.0f; // и ресетим статус открытия
  33.                 }
  34.                 else {
  35.                     m_currentState = STATE_CLOSING; // переключаем статус
  36.                     m_openingState = 1.0f; // и ресетим статус открытия
  37.                 }
  38.                 m_nLastTimeWhenAnyActionWasEnabled = CTimer::m_snTimeInMilliseconds; // запоминаем время
  39.             }
  40.         }
  41.     }
  42.  
  43.     static void Process() { // Обрабатываем поточное состояние - ждём нажатия клавиши ИЛИ открываем ИЛИ закрываем компонент
  44.         switch (m_currentState) {
  45.         case STATE_OPENING: // Что-то открываем. Обрати внимание, что ранее мы записали поточное авто и ид компонентов в статические переменные класса (по сути, это глобальные переменные)
  46.             m_pCurrentCar->OpenDoor(0, m_currentComponentId, m_currentDoorId, m_openingState, true);
  47.             m_openingState += 0.05f;
  48.             if (m_openingState > 1.0f) { // Если полностью открыли
  49.                 m_currentState = STATE_WAITING; // Переключаем статус на "ожидание"
  50.                 m_pCurrentCar->OpenDoor(0, m_currentComponentId, m_currentDoorId, 1.0f, true); // Полностью открываем
  51.             }
  52.             break;
  53.         case STATE_CLOSING: // Что-то закрываем
  54.             m_pCurrentCar->OpenDoor(0, m_currentComponentId, m_currentDoorId, m_openingState, true);
  55.             m_openingState -= 0.05f;
  56.             if (m_openingState < 0.0f) { // Если полностью закрыли
  57.                 m_currentState = STATE_WAITING; // Переключаем статус на "ожидание"
  58.                 m_pCurrentCar->OpenDoor(0, m_currentComponentId, m_currentDoorId, 0.0f, true); // Полностью закрываем
  59.             }
  60.             break;
  61.         case STATE_WAITING:
  62.             if (CTimer::m_snTimeInMilliseconds > (m_nLastTimeWhenAnyActionWasEnabled + 500)) { // если прошло 500 мс с того времени, как мы начали открывать/закрывать что-то
  63.                 CVehicle *vehicle = FindPlayerVehicle(0, false);
  64.                 if (vehicle && vehicle->m_dwVehicleClass == VEHICLE_AUTOMOBILE) {
  65.                     CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle); // опять же, приведение типов. Т.к. мы будет юзать damageManager, нам нужно убедиться, что транспорт - это автомобиль (CAutomobile)
  66.                     if (KeyPressed(219)) // [
  67.                         OpenComponent(automobile, CAR_BONNET, static_cast<eDoors>(0)); // капот
  68.                     else if (KeyPressed(221)) // ]
  69.                         OpenComponent(automobile, CAR_BOOT, static_cast<eDoors>(1)); // багажник
  70.                     else if (KeyPressed(186) && KeyPressed(187)) // ; =
  71.                         OpenComponent(automobile, CAR_DOOR_LF, static_cast<eDoors>(2)); // левая передняя дверь
  72.                     else if (KeyPressed(222) && KeyPressed(187)) // ' =
  73.                         OpenComponent(automobile, CAR_DOOR_RF, static_cast<eDoors>(3)); // правая передняя дверь
  74.                     else if (KeyPressed(186) && KeyPressed(189)) // ; -
  75.                         OpenComponent(automobile, CAR_DOOR_LR, static_cast<eDoors>(4)); // левая задняя дверь
  76.                     else if (KeyPressed(222) && KeyPressed(189)) // ' -
  77.                         OpenComponent(automobile, CAR_DOOR_RR, static_cast<eDoors>(5)); // правая задняя дверь
  78.                 }
  79.             }
  80.         }
  81.  
  82.         switch (m_currentState) { // Для наглядности выведем поточный статус на экран
  83.         case STATE_OPENING:
  84.             CMessages::AddMessageJumpQ("State: OPENING", 100, 0, false);
  85.             break;
  86.         case STATE_CLOSING:
  87.             CMessages::AddMessageJumpQ("State: CLOSING", 100, 0, false);
  88.             break;
  89.         case STATE_WAITING:
  90.             CMessages::AddMessageJumpQ("State: WAITING", 100, 0, false);
  91.             break;
  92.         }
  93.     }
  94.  
  95.     OpenDoorExample() {
  96.         Events::gameProcessEvent.Add(Process);
  97.     }
  98. } example;
  99.  
  100. OpenDoorExample::eOpenDoorState OpenDoorExample::m_currentState = STATE_WAITING;
  101. CAutomobile *OpenDoorExample::m_pCurrentCar;
  102. float OpenDoorExample::m_openingState;
  103. int OpenDoorExample::m_currentComponentId;
  104. eDoors OpenDoorExample::m_currentDoorId;
  105. unsigned int OpenDoorExample::m_nLastTimeWhenAnyActionWasEnabled = 0;
Не стал делать проверку нажатия/отжатия клавиши, чтобы не усложнять  :D
Заметь, что и в твоём скрипте, и в этом примере есть небольшая проблема - это выполнение действий над авто в цикле, без доп. проверки на существование этого авто. Чисто теоретически - пока обрабатывается открытие/закрытие, с авто может что-то случиться :) Но это уже мелочи.
Можно было бы вообще разделить процессы открытия/закрытия и обработки клавиш (чтобы эти процессы выполнялись одновременно). Но для базовой реализации подойдёт и так.

По for и другим циклам лучше найти какой-то урок/туториал по C++ (например этот (https://code-live.ru/post/cpp-loops))
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 02, 2016, 09:11:07 am
С plugin_vc и VC_DXFont разобрался, спасибо.
Как я понял, и для SA, и для VC плагины идут только под версию exe 1.0. Ну для SA то ладно, а для VC хорошо бы и версию 1.1 учитывать.
А есть ли в планах и для GTA3 плагин сделать?

Цитировать
Но я бы советовал использовать специальные утилиты для обновления/изменения:
Git for Windows
TortoiseGit
Скачал, установил.

Цитировать
Создать аккаунт на github.
Сообщить мне свой никнейм (мне нужно будет добавить его в список редакторов).
kenkingGitHub (никнейм kenking уже кто-то занял, наглость какая  ;D)

Цитировать
Тебе нужно мыслить по-другому - ты "вклиниваешься" в процесс каждый фрейм.
Буду пробовать, после клео как-то непривычно. Ещё раз большое спасибо за подробные пояснения!

Цитировать
Заметь, что и в твоём скрипте, и в этом примере есть небольшая проблема - это выполнение действий над авто в цикле, без доп. проверки на существование этого авто. Чисто теоретически - пока обрабатывается открытие/закрытие, с авто может что-то случиться
Есть такое дело. Я проверку там в общем-то сознательно не поставил, потому как при написании такого скрипта для VC во время процесса открывания/закрывания компонента специально взрывал авто и вылета не было, поскольку авто сразу не удаляется. Ну так-то проверку лучше ставить, согласен.
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Август 02, 2016, 10:11:36 am
для VC хорошо бы и версию 1.1 учитывать
Не думаю, что ради этого стоит напрягаться - сейчас мало кто учитывает 1.1: даже MVL работает лишь с 1.0
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 02, 2016, 10:18:05 am
Не думаю, что ради этого стоит напрягаться - сейчас мало кто учитывает 1.1 - даже MVL работает лишь с 1.0
Я в клео скриптах учитываю. В библиотеке клео тоже учитывали это дело. Не думаю, что это большой напряг для того, кто разбирается в этом. Ну автору, конечно, решать.

UPD:
По коду открытия компонентов есть непонятка. Вот здесь:
if (automobile->m_damageManager.GetDoorStatus(doorId) != 3)Для VC и GTA3 значение 3 - это компонент отсутствует, т.е. он повредился и отвалился. Для SA такое состояние компонента будет 4. Однако при замене 3 на 4 плагин перестаёт работать, т.е. компоненты не открываются и не закрываются. Это как понимать?

Цитировать
Если ты знаешь значения этого перечисления - можешь их добавить в файле CDamageManager.h, и далее использовать их при вызове (напр. DOOR_FRONT_LEFT).
Добавил:
enum eDoors
{
BONNET = 0,
BOOT = 1,
DOOR_FRONT_LEFT = 2,
DOOR_FRONT_RIGHT = 3,
DOOR_REAR_LEFT = 4,
DOOR_REAR_RIGHT = 5
};

А также:
enum ePanels
{
WING_FRONT_LEFT = 0,
WING_FRONT_RIGHT = 1,
WINDSCREEN = 4,
BUMP_FRONT = 5,
BUMP_REAR = 6
};
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 02, 2016, 08:59:56 pm
А есть ли в планах и для GTA3 плагин сделать?
Нет. Даже на plugin_vc у меня времени почти нет.
kenkingGitHub (никнейм kenking уже кто-то занял, наглость какая  ;D)
Кинул тебе инвайт.
Не думаю, что это большой напряг для того, кто разбирается в этом.
Я не скажу, что это очень сложно. Это просто требует времени. Много времени. Сейчас в plugin-sdk (SA) более 2700 адресов.
Поиск всех этих адресов в exe какой-либо другой версии может занять месяцы (с моим графиком). Я для себя вообще отбросил этот вариант.
Для VC и GTA3 значение 3 - это компонент отсутствует, т.е. он повредился и отвалился. Для SA такое состояние компонента будет 4. Однако при замене 3 на 4 плагин перестаёт работать, т.е. компоненты не открываются и не закрываются. Это как понимать?
Действительно, не работает.
UPD: разобрался, это ошибка в sdk. Дело в том, что есть 2 функции GetDoorStatus. Одна в качестве аргумента принимает перечисление eDoors, вторая - id компонента. В sdk эти функции были перепутаны. Уже исправил.
Добавил:
Как будет время - можешь попробовать сделать коммит.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 03, 2016, 07:45:50 am
Цитировать
Нет. Даже на plugin_vc у меня времени почти нет.
Жаль, было бы хорошо собрать плагин для GTA3, VC и SA в один "инструмент". А если ещё сделать для IV и V - это была бы самая крутая вещь для скриптинга GTA.

Цитировать
Я не скажу, что это очень сложно. Это просто требует времени. Много времени. Сейчас в plugin-sdk (SA) более 2700 адресов.
Поиск всех этих адресов в exe какой-либо другой версии может занять месяцы (с моим графиком). Я для себя вообще отбросил этот вариант.
Да для SA это в общем-то без надобности. Я скрипты писал тоже только под exe 1.0. Да и остальные скриптёры тоже.

Цитировать
Действительно, не работает.
UPD: разобрался, это ошибка в sdk. Дело в том, что есть 2 функции GetDoorStatus. Одна в качестве аргумента принимает перечисление eDoors, вторая - id компонента. В sdk эти функции были перепутаны. Уже исправил.
Вот теперь всё отлично!

Как я понял, после каждого обновления надо пересобирать плагин?

В plugin-sdk файлы отмечены разными значками:
(http://savepic.net/8320524m.png) (http://savepic.net/8320524.png)
Что означают эти предупреждения и "кирпичи". Какие нужны действия?

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 03, 2016, 05:53:33 pm
Как я понял, после каждого обновления надо пересобирать плагин?
Да.
Что означают эти предупреждения и "кирпичи". Какие нужны действия?
Красным отмечены файлы, которые ты изменил (и которые, по идее, нужно "закоммитить"). Зелёный - совпадает с текущим (на репозитарии). Серый - файлы игнорируются (не включаются в коммит и их нету в репозитории).
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 04, 2016, 11:56:28 am
В в CDamageManager.h есть ещё "пустые" перечисления
tComponent
tComponentGroup
eWheels

Ну с eWheels вроде, как понятно - это 6 колёс, а остальные что означают? 

Цитировать
Красным отмечены файлы, которые ты изменил (и которые, по идее, нужно "закоммитить")
При сборке примеров у меня выходило сообщение компилятора:
Цитировать
Main.obj : найден .netmodule MSIL или модуль, откомпилированный с параметром /GL; перезапускается компоновка с параметром /LTCG; добавьте /LTCG в командную строку компоновки для повышения производительности компоновщика
В общем я добавил во все примеры. Также по незнанию, я начал было экспериментировать в этом решении. ??? "Откатил" всё назад. Теперь буду учиться в своём решении, а не в plugin-sdk.

Цитировать
Как будет время - можешь попробовать сделать коммит.
Вот и сделал... :(
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 04, 2016, 06:25:16 pm
В в CDamageManager.h есть ещё "пустые" перечисления
tComponent
tComponentGroup
eWheels

Ну с eWheels вроде, как понятно - это 6 колёс, а остальные что означают?
Тоже какие-то перечисления. Надо смотреть код функций
Код: C++
  1. bool GetComponentGroup(tComponent component, tComponentGroup* group, unsigned char* damageCompId);
  2. bool ApplyDamage(CAutomobile* car, tComponent component, float intensity, float arg3);
  3.  

Чтобы разобраться.

UPD: Нашел их у себя в базе, добавил.

Вот и сделал... :(
Ты о чём? Вроде всё правильно сделал.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 04, 2016, 07:08:30 pm
Цитировать
Ты о чём? Вроде всё правильно сделал.
Да там https://github.com/DK22Pac/plugin-sdk/tree/master/examples (https://github.com/DK22Pac/plugin-sdk/tree/master/examples) теперь везде

Цитировать
CDamageManager: added enum ePanels and enum eDoors

ну так-то ничего страшного, теперь протестил, что да как делать при коммите, в следующий раз всё будет как надо.

Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 05, 2016, 06:22:26 pm
Потихоньку разбираюсь. Есть вопросы:
1) Как от найденного компонента перейти к child, next, root, а также прочитать их названия (+ 172 // NodeName)?
2) Какой алгоритм добавления новой функции в плагин?
Допустим, я знаю такой адрес:
:007F0ED0     ; RwFrame *__cdecl RwFrameScale(RwFrame *frame, RwV3D *v, int combine)Как добавить в плагин? 
3) Планируешь ли добавить в примеры код IVF? Не устаю повторять - это лучший мод на эту тему, когда-либо сделанный для SA! Хорошо бы с комментариями добавить его в примеры (ну или выслать в ЛС, если можно). Кстати, (я про это писал уже на GCU форуме) в версии IVF 2.1 на прицепах поворотники не работают.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 05, 2016, 06:38:30 pm
1) Как от найденного компонента перейти к child, next, root, а также прочитать их названия (+ 172 // NodeName)?
Если у тебя есть указатель на RwFrame, используй оператор -> для доступа к членам структуры:
Код: C++
  1. RwFrame *pNext = component->next;
Можешь посмотртеть структуру в файле rw\rwcore.h.

Для перебора всех child'ов есть специальная функция
Код: C++
  1. RwFrameForAllChildren(RwFrame* фрейм, RwFrameCallBack функция_коллбэк, void* данные_для_передачи_в_коллбэк);
2) Какой алгоритм добавления новой функции в плагин?
Допустим, я знаю такой адрес:
:007F0ED0     ; RwFrame *__cdecl RwFrameScale(RwFrame *frame, RwV3D *v, int combine)Как добавить в плагин? 
Эта функция уже есть в sdk.
Вообще, я добавил почти все функции RW, которые есть в exe.

Обычно, для добавления функции, нужно её обьявить (обычно в файле-хедере .h) и определить (обычно в .cpp файле).
Можешь посмотреть на примере той же RwFrameScale (в файлах RenderWare.h и RenderWare.cpp).

Большинство процедур в exe - это методы различных классов.
Для добавления таких процедур нужно также обьявить класс, членами которого являются методы.
Пример - посмотри, например, CMatrix.h и CMatrix.cpp.
3) Планируешь ли добавить в примеры код IVF? Не устаю повторять - это лучший мод на эту тему, когда-либо сделанный для SA! Хорошо бы с комментариями добавить его в примеры (ну или выслать в ЛС, если можно). Кстати, (я про это писал уже на GCU форуме) в версии IVF 2.1 на прицепах поворотники не работают.
Для начала нужно весь код IVF адаптировать под новый sdk. Тогда, возможно, выложу исходники на github.

UPD: Добавил файлы с функциями NodeName.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 05, 2016, 07:54:25 pm
Цитировать
Эта функция уже есть в sdk.
Это я для примера. А как её правильно вызывать? Для клео ты мне тогда объяснял, теперь, что-то не пойму здесь как надо.

Цитировать
Если у тебя есть указатель на RwFrame, используй оператор -> для доступа к членам структуры:
А название компонента, как прочитать? В клео по смещению + 172 читалось имя компонента. Я делал скрипт для дверей автобусов, там в модель добавлялись вспомогательные компоненты и их названия были величины углов, на которые нужно вращать двери (у разных моделей разные значения), потом я считывал название этого компонента (child, next) и переводил из string в float, получал значение угла вращения.

Цитировать
Тогда, возможно, выложу исходники на github.
Было бы здорово!
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 05, 2016, 08:01:20 pm
Дело в том, что имя компонента (NodeName) не является частью RenderWare - поэтому его нету в структуре RwFrame. Это "надстройка" от создателей GTA.
Для доступа к имени есть специальне фунеции, я их добавлю в скором времени (файлы NodeName.h, NodeName.cpp).
Ну и пример - вывод иерархии транспорта на экран.
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\NodeName.h"
  4. #include "game_sa\CFont.h"
  5.  
  6. using namespace plugin;
  7.  
  8. class VehicleHierarchy {
  9. public:
  10.     static RwFrame *DrawFrameHierarchyNames(RwFrame *frame, void *data) {
  11.         CVector2D *offset = reinterpret_cast<CVector2D *>(data);
  12.         // сначала выводим имя самого фрейма
  13.         char *name = GetFrameNodeName(frame);
  14.         CFont::PrintString(offset->x, offset->y, name[0] ? name : "<no_name>");
  15.         offset->y += 20.0f; //опускаемся ниже
  16.         // Теперь выводим имена всех дочерних компонентов
  17.         offset->x += 20.0f; // детей выводим правее
  18.         RwFrameForAllChildren(frame, DrawFrameHierarchyNames, offset); // для всех дочерних фреймов вызываем DrawFrameHierarchyNames. Таким образом, мы переберём всех детей, детей всех детей, и т.д. Это называется рекурсией.
  19.         offset->x -= 20.0f; // вывели всех детей
  20.         return frame;
  21.     }
  22.  
  23.     VehicleHierarchy() {
  24.         Events::drawingEvent += [] {
  25.             CVehicle *vehicle = FindPlayerVehicle(-1, false);
  26.             if (vehicle && vehicle->m_pRwObject) {
  27.                 // Настраивем вывод текста
  28.                 CFont::SetScale(0.5f, 1.0f);
  29.                 CFont::SetColor(CRGBA(255, 255, 255, 255));
  30.                 CFont::SetAlignment(ALIGN_LEFT);
  31.                 CFont::SetOutlinePosition(1);
  32.                 CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  33.                 CFont::SetBackground(false, false);
  34.                 CFont::SetFontStyle(FONT_SUBTITLES);
  35.                 CFont::SetProp(true);
  36.                 CFont::SetWrapx(600.0f);
  37.                 // Теперь выводим, начиная с корневого фрейма (vehicle->m_pRwObject->parent) (член "parent" имеет тип void*, поэтому приводим к RwFrame*.
  38.                 CVector2D offset = {10.0f, 10.0f}; // Начальные координаты
  39.                 DrawFrameHierarchyNames(reinterpret_cast<RwFrame *>(vehicle->m_pRwObject->parent), &offset);
  40.             }
  41.         };
  42.     }
  43. } vehicleHierarchy;
Вроде как всё очень просто, не так ли?

Ещё раз:
RwFrameForAllChildren(frame - родительский фрейм (доступ к детям которого надо получить
                                  DrawFrameHierarchyNames - функция (функция-коллбэк), которую надо выполнить для каждого ребёнка,
                                  offset - наши данные, которые будут переданы в функцию-коллбэк );
Можно расшифровать так:
Выполнить функцию DrawFrameHierarchyNames для всех детей frame, с данными offset. Данные offset (2д-вектор) в примере мы использовали для сохранения координат вывода - ведь нам нужно опускать текст после каждого компонента и двигать его вправо для детей. Мы передавали эти данные в функцию обработки каждого отдельного компонента.

UPD: Добавил файлы.

Цитировать
А как её правильно вызывать? Для клео ты мне тогда объяснял, теперь, что-то не пойму здесь как надо.

Когда напечатаешь имя функции в Visual Studio и откроешь скобку, увидишь список параметров:
(http://i.imgur.com/cGoKHIs.png)

Пример вызова
Код: C++
  1. RwV3d savedPosn = automobile->m_aCarNodes[CAR_DOOR_LF]->modelling.pos;
  2. RwV3d scale = { 2.0f, 2.0f, 2.0f };
  3. RwMatrixScale(&automobile->m_aCarNodes[CAR_DOOR_LF]->modelling, &scale, rwCOMBINEREPLACE);
  4. automobile->m_aCarNodes[CAR_DOOR_LF]->modelling.pos = savedPosn;

Ещё это почитать можно:
Рекурсия https://acmp.ru/article.asp?id_sec=1&id_text=1333 (https://acmp.ru/article.asp?id_sec=1&id_text=1333)
Тернарный оператор http://cppstudio.com/post/304/ (http://cppstudio.com/post/304/)

Ещё один пример, показывает как использовать VehicleExtendedData.
Код: C++
  1. #include <plugin.h>
  2.  
  3. using namespace plugin;
  4.  
  5. class VehicleExtendedExample {
  6. public:
  7.     class VehicleComponents { // Класс, который представляет наши данные (можно сказать, что эти данные "прикрепляются" к структуре транспорта)
  8.     public:
  9.         RwFrame *m_pDoorLF;
  10.         RwFrame *m_pDoorRF;
  11.         RwFrame *m_pDoorLR;
  12.         RwFrame *m_pDoorRR;
  13.  
  14.         VehicleComponents(CVehicle *) { // Конструктор этого класса будет вызван при вызове конструктора транспорта (CVehicle::CVehicle)
  15.             m_pDoorLF = m_pDoorRF = m_pDoorLR = m_pDoorRR = nullptr; // устанавливаем все указатели в 0
  16.         }
  17.     };
  18.  
  19.     VehicleExtendedExample() {
  20.         static VehicleExtendedData<VehicleComponents> vehComps; // Создаем экземпляр нашего расширения. vehComps - это переменная, через которую мы будем
  21.                                                                 // обращаться к нашим данным (используя метод Get(CVehicle *транспорт) )
  22.  
  23.         Events::vehicleSetModelEvent += [](CVehicle *vehicle, int modelIndex) { // Выполняем нашу функцию, когда игра устанавливает модель транспорту
  24.             if (vehicle->m_pRwClump) { // Если создан графический обьект модели (RpClump)
  25.                 vehComps.Get(vehicle).m_pDoorLF = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "door_lf_dummy"); // Находим компоненты в иерархии
  26.                 vehComps.Get(vehicle).m_pDoorRF = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "door_rf_dummy"); // и записываем их в наш класс
  27.                 vehComps.Get(vehicle).m_pDoorLR = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "door_lr_dummy");
  28.                 vehComps.Get(vehicle).m_pDoorRR = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "door_rr_dummy");
  29.             }
  30.             else // иначе устанавливаём всё в 0
  31.                 vehComps.Get(vehicle).m_pDoorLF = vehComps.Get(vehicle).m_pDoorRF = vehComps.Get(vehicle).m_pDoorLR = vehComps.Get(vehicle).m_pDoorRR = nullptr;
  32.         };
  33.  
  34.         Events::vehicleRenderEvent += [](CVehicle *vehicle) { // Выполняем нашу функцию, когда игра рендерит транспорт
  35.             if (vehComps.Get(vehicle).m_pDoorLF)
  36.                 vehComps.Get(vehicle).m_pDoorLF->modelling.pos.z = 1.0f; // Сдвигаем компонент вверх
  37.             if (vehComps.Get(vehicle).m_pDoorRF)
  38.                 vehComps.Get(vehicle).m_pDoorRF->modelling.pos.z = 1.0f;
  39.             if (vehComps.Get(vehicle).m_pDoorLR)
  40.                 vehComps.Get(vehicle).m_pDoorLR->modelling.pos.z = 1.0f;
  41.             if (vehComps.Get(vehicle).m_pDoorRR)
  42.                 vehComps.Get(vehicle).m_pDoorRR->modelling.pos.z = 1.0f;
  43.         };
  44.     }
  45. } vehicleExtendedExample;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 06, 2016, 03:52:41 pm
Дмитрий, ты волшебник.  ;)

Спасибо за очередные примеры и пояснения. Чем больше будет примеров, тем быстрей я освоюсь в написании плагинов. За ссылки на уроки тоже спасибо. Я сейчас читаю книгу
Прохоренок Н.А. Программирование на С++ в Visual Studio 2010 Express (2010) и дополнительный материал будет кстати.

По примерам:
с первым примером разобрался, всё нормально. Для теста написал небольшой код, глянь верно ли? Можно, что-то оптимизировать? Хотел ещё вывести скорость авто, но что-то не вышло, вот это CVector GetSpeed(CVector direction) оно или нет? С вектором не понял, как работать. Также не понятно, как вывести название транспорта. Пожалуйста пример.
#include <plugin.h>
#include "game_sa\common.h"
#include "game_sa\CFont.h"

using namespace plugin;

class VehicleGetPosition {
public:

VehicleGetPosition() {
Events::drawingEvent += [] {
CVehicle *vehicle = FindPlayerVehicle(-1, false);
if (vehicle) {
// Настраивем вывод текста
CFont::SetScale(0.5f, 1.0f);
CFont::SetColor(CRGBA(255, 255, 255, 255));
CFont::SetAlignment(ALIGN_LEFT);
CFont::SetOutlinePosition(1);
CFont::SetDropColor(CRGBA(0, 0, 0, 255));
CFont::SetBackground(false, false);
CFont::SetFontStyle(FONT_SUBTITLES);
CFont::SetProp(true);
CFont::SetWrapx(600.0f);
CVector vspeed = vehicle->m_vLinearVelocity;
float speed = sqrt(vspeed.x*vspeed.x + vspeed.y*vspeed.y + vspeed.z*vspeed.z);
speed *= 180;
float vhealth = vehicle->m_fHealth;
float vmass = vehicle->m_fMass;
CVector posn = vehicle->GetPosition();
char t_speed[16];
char t_health[16];
char t_vmass[16];
char t_posnx[16];
char t_posny[16];
char t_posnz[16];
sprintf(t_speed, "speed %.0f km/h", speed);
sprintf(t_health, "health %.0f \%\%", vhealth/10.0f);
sprintf(t_vmass, "massa %.1f kg", vmass);
sprintf(t_posnx, "posn x %.2f", posn.x);
sprintf(t_posny, "posn y %.2f", posn.y);
sprintf(t_posnz, "posn z %.2f", posn.z);
CFont::PrintString(5.0f, 5.0f, t_speed);
CFont::PrintString(5.0f, 25.0f, t_health);
CFont::PrintString(5.0f, 45.0f, t_vmass);
CFont::PrintString(5.0f, 65.0f, t_posnx);
CFont::PrintString(5.0f, 85.0f, t_posny);
CFont::PrintString(5.0f, 105.0f, t_posnz);
}
};
}
} vehicleGetPosition;


во втором примере пишет
Цитировать
namespase "plugin::Events" не содержит члена "vehicleSetModelEvent"

Цитировать
Пример вызова
Спасибо, теперь ясно. Но есть одно но - при RwMatrixScale если вращать компонент, например дверь, то она принимает стандартный размер. В клео я поэтому вызывал RwFrameScale - тогда компонент при вращении остаётся запланированного масштаба. По примеру попробовал вызвать RwFrameScale так:
RwFrameScale(automobile->m_aCarNodes[CAR_DOOR_LR], &scale, rwCOMBINEPRECONCAT);Не знаю правильно или нет, но компонент масштабируется, но при вращении опять становится стандартного размера. А при rwCOMBINEREPLACE так и вовсе оказывается в центре модели (как и при вращении с этим параметром после RwMatrixScale). В клео нормально работало, что я делаю не так?

UPD:
    RwV3d savedPosn = automobile->m_aCarNodes[CAR_DOOR_LF]->modelling.pos;
    RwV3d scale = { 2.0f, 2.0f, 2.0f };
    RwMatrixScale(&automobile->m_aCarNodes[CAR_DOOR_LF]->modelling, &scale, rwCOMBINEREPLACE);
    automobile->m_aCarNodes[CAR_DOOR_LF]->modelling.pos = savedPosn;
Можно, как ты написал до этого:
RwV3d scale = { 2.0f, 2.0f, 2.0f };
RwMatrixScale(&automobile->m_aCarNodes[CAR_DOOR_LR]->modelling, &scale, rwCOMBINEPRECONCAT);
только combine поменять на rwCOMBINEPRECONCAT

Но всё равно в обоих вариантах после вращения масштабирование сбрасывается в стандарт.


UPD2:
Обновил sdk, пересобрал плагин, теперь
Цитировать
пример, показывает как использовать VehicleExtendedData.
работает.

А практически для чего например можно это использовать в плагине?

UPD3:Со скоростью "разобрался" так:
CVector vspeed = vehicle->m_vLinearVelocity;
float speed = sqrt(vspeed.x*vspeed.x + vspeed.y*vspeed.y + vspeed.z*vspeed.z);
speed *= 180;
Верно?

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 07, 2016, 12:31:25 pm
Со скоростью "разобрался" так:
Верно?

Да.
В опкоде 02E3 скорость считается вот так (длина вектора MoveForce умножается на 50):
(http://i.imgur.com/Qo8YfWx.png)

PS Я поменял названия некоторых членов в CPhysical (коммит 99 (https://github.com/DK22Pac/plugin-sdk/commit/8d18c41a2af20588e50c9eb6d32c0878dbd3222b#diff-16e208f83bec7d0b8058b273b70b9f7d)).

Также не понятно, как вывести название транспорта.

Находишь gxt-ключ названия в структуре модели транспорта (CVehicleModelInfo) и переводишь его в текст (CText::Get(char* ключ))

Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CFont.h"
  4. #include "game_sa\CModelInfo.h"
  5. #include "game_sa\CText.h"
  6.  
  7. using namespace plugin;
  8.  
  9. class VehicleGetPosition {
  10. public:
  11.     VehicleGetPosition() {
  12.         Events::drawingEvent += [] {
  13.             CVehicle *vehicle = FindPlayerVehicle(-1, false);
  14.             if (vehicle) {
  15.                 // Настраивем вывод текста
  16.                 CFont::SetScale(0.5f, 1.0f);
  17.                 CFont::SetColor(CRGBA(255, 255, 255, 255));
  18.                 CFont::SetAlignment(ALIGN_LEFT);
  19.                 CFont::SetOutlinePosition(1);
  20.                 CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  21.                 CFont::SetBackground(false, false);
  22.                 CFont::SetFontStyle(FONT_SUBTITLES);
  23.                 CFont::SetProp(true);
  24.                 CFont::SetWrapx(600.0f);
  25.                 static char str[32];
  26.                 CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]);
  27.                 sprintf(str, "vehicle %s", TheText.Get(vehModel->m_szGameName));
  28.                 CFont::PrintString(5.0f, 25.0f, str);
  29.                 sprintf(str, "health %.0f%%", vehicle->m_fHealth / 10.0f);
  30.                 CFont::PrintString(5.0f, 45.0f, str);
  31.                 sprintf(str, "mass %.1f kg", vehicle->m_fMass);
  32.                 CFont::PrintString(5.0f, 65.0f, str);
  33.                 sprintf(str, "posn x %.2f", vehicle->GetPosition().x);
  34.                 CFont::PrintString(5.0f, 85.0f, str);
  35.                 sprintf(str, "posn y %.2f", vehicle->GetPosition().y);
  36.                 CFont::PrintString(5.0f, 105.0f, str);
  37.                 sprintf(str, "posn z %.2f", vehicle->GetPosition().z);
  38.                 CFont::PrintString(5.0f, 125.0f, str);
  39.                 sprintf(str, "speed %.2f", vehicle->m_vecMoveForce.Magnitude() * 50.0f);
  40.                 CFont::PrintString(5.0f, 145.0f, str);
  41.             }
  42.         };
  43.     }
  44. } vehicleGetPosition;

В клео я поэтому вызывал RwFrameScale - тогда компонент при вращении остаётся запланированного масштаба.

Можешь показать свой код в клео?

PS Для вывода кода C++ используй
[code=cpp][/code
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 07, 2016, 02:25:54 pm
Цитировать
Можешь показать свой код в клео?

Я немного ввел тебя в заблуждение, прошу прощения. Дело в том, что при вызове RwFrameScale я масштабировал все компоненты в том числе и chassis_dummy в который вложены подвижные компоненты (двери, капот и багажник). Так вот в этом случае масштаб сохраняется при вращении этих компонентов, а если вызывать RwFrameScale отдельно для вращающегося компонента, то при вращении масшаб сбрасывается в стандартный. Вывод - для таких компонентов надо масштабировать parent. Вот код клео:
{$CLEO .cs}
20@ = 0.5 // X
21@ = 0.5 // Y
22@ = 0.5 // Z

while true
wait 0
    if
      Player.Defined($PLAYER_CHAR)
    then
        if and
          Actor.Driving($PLAYER_ACTOR)
          0AB0: key_pressed 53
        then
            03C0: 0@ = actor $PLAYER_ACTOR car
            0A97: 0@ = car 0@ struct
            0A8E: 0@ = 0@ + 0x18
            0A8D: 0@ = read_memory 0@ size 4 virtual_protect 0
            0AA7: call_function 0x4C5400 num_params 2 pop 2 _nodename "chassis_dummy" _rwObject 0@ _store_to 1@
            if
              1@ > 0
            then
                0AA5: call {RwFrameScale} 0x7F0ED0 num_params 3 pop 3 _combine 1 _v 20@v _frame 1@
            end
            repeat
              wait 0
            until 8AB0: not key_pressed 53
        end
    end
end       
(http://savepic.net/8372643m.jpg) (http://savepic.net/8372643.jpg) (http://savepic.net/8373667m.jpg) (http://savepic.net/8373667.jpg)


Как правильно вызвать RwFrameScale в плагине?
Код: C++
  1. RwFrameScale(automobile->m_aCarNodes[CAR_CHASSIS], &scale, rwCOMBINEPRECONCAT);
Тот вариант, что я написал похоже неверный, поскольку вложенные компоненты не масштабируются вместе с CAR_CHASSIS, как в случае с клео. Происходит ровно тоже, что при вызове RwMatrixScale.

(http://savepic.net/8349090m.jpg) (http://savepic.net/8349090.jpg)

Цитировать
Находишь gxt-ключ названия в структуре модели транспорта (CVehicleModelInfo) и переводишь его в текст (CText::Get(char* ключ))
Спасибо.

UPD:В базе есть такой адрес:
.text:0043A570     _cheatSpawnTankerTruck proc nearВ sdk ты его не добавил? Я во всяком случае в CCheat его не нашёл. Ведь по-идеи он там должен быть? Или в других файлах? Попробовал туда добавить так:
Код: C++
  1. #include "CCheat.h"
  2.  
  3. char *CCheat::m_CheatString = (char *)0x969110;
  4.  
  5. CVehicle *CCheat::VehicleCheat(int vehicleId) {
  6.     return ((CVehicle *(__cdecl *)(int))0x43A0B0)(vehicleId);
  7. }
  8.  
  9. CVehicle *CCheat::TankerTruck() {
  10.         return ((CVehicle *(__cdecl *)())0x43A570)();
  11. }
Код: C++
  1. #pragma once
  2. #include "plbase/PluginBase_SA.h"
  3.  
  4. class PLUGIN_API CCheat {
  5. public:
  6.     // static char m_CheatString[30]
  7.     static char *m_CheatString;
  8.  
  9.     static class CVehicle *VehicleCheat(int vehicleId);
  10.         static class CVehicle *TankerTruck();
  11. };

Верно ли?
Ну по крайне мере вызывается правильно, бензовоз с прицепом спунятся.

Давно задаюсь вопросом - можно ли переписать эту функцию так, чтобы считывать пары ID тягача и ID прицепа из текстового файла (ну в крайнем случае в сам плагин набрать это сочетание, ну лучше считывать из текстового файла) и потом аналогичным образом спаунить другие тягачи с прицепами, ведь нормального спаунера авто с прицепами так и не сделали.

UPD2:
 :D Вот:
(http://savepic.net/8375770m.jpg) (http://savepic.net/8375770.jpg)
Код: C++
  1. if (automobile->m_aCarNodes[CAR_CHASSIS]) {
  2.    if (automobile->m_aCarNodes[CAR_DOOR_LF])
  3.       RwFrameAddChild(automobile->m_aCarNodes[CAR_CHASSIS], automobile->m_aCarNodes[CAR_DOOR_LF]);
  4.                
  5.    RwV3d scale = { 0.5f, 0.5f, 0.5f };
  6.    RwFrameScale(automobile->m_aCarNodes[CAR_CHASSIS], &scale, rwCOMBINEREPLACE);
  7. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 08, 2016, 07:35:51 pm
CCheat я особо не разбирал.
В sdk была только функция VehicleChear для спавна авто.
Давно задаюсь вопросом - можно ли переписать эту функцию так, чтобы считывать пары ID тягача и ID прицепа из текстового файла (ну в крайнем случае в сам плагин набрать это сочетание, ну лучше считывать из текстового файла) и потом аналогичным образом спаунить другие тягачи с прицепами, ведь нормального спаунера авто с прицепами так и не сделали.
Можно полноситью заменить оригинальную функцию своей.
Покажу пример, как доделаю полностью иерархию клаасов CVehicle, включая CTrailer.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 09, 2016, 08:55:17 am
Цитировать
CCheat я особо не разбирал.
В sdk была только функция VehicleChear для спавна авто.
А добавил-то я правильно?

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 09, 2016, 09:19:20 pm
Цитировать
CCheat я особо не разбирал.
В sdk была только функция VehicleChear для спавна авто.
А добавил-то я правильно?
Да.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 10, 2016, 09:40:39 am
1)
Цитировать
Можно было бы вообще разделить процессы открытия/закрытия и обработки клавиш (чтобы эти процессы выполнялись одновременно).
Т.е. нажал клавишу, дверь открывается\закрывается и в это же время нажал другую клавишу и одновременно пошло открытие\закрытие другой двери? И т.д. Можно это показать для этого же примера? (SA_OpenDoorExample) https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_OpenDoorExample/Main.cpp (https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_OpenDoorExample/Main.cpp)

2) Какой загрузчик asi использовать для VC, чтобы скрипты загружались не из корневого каталога, а из \scripts ?

3) Будет ли в плагине VC реализован поиск компонента по имени?
Код: C++
  1. RwFrame *component = CClumpModelInfo::GetFrameFromName(automobile->m_pRwClump, "bonnet_dummy");
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Август 10, 2016, 04:23:52 pm
Ох - наконец-то я что-то полезное оставлю в этой теме :D
Цитировать
2) Какой загрузчик asi использовать для VC, чтобы скрипты загружались не из корневого каталога, а из \scripts ?
Ultimate ASI Loader (https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 10, 2016, 10:51:45 pm
kenking, покажу позже.

По VC ничего не могу сказать. Если есть свободное время - дорабатываю версию для SA.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 11, 2016, 06:47:53 pm
kenking, покажу позже.
Хорошо. Ещё интересует создание спецактёра. Там же отличается (в клео по-крайне мере) загрузка модели, создание актёра, выгрузка модели и т.д. Также интересна установка (и удаление) деталей тюнинга на транспорт. Такие примеры были бы тоже кстати. 

Ultimate ASI Loader (https://github.com/ThirteenAG/Ultimate-ASI-Loader/releases)
Спасибо.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 11, 2016, 11:51:29 pm
Т.е. нажал клавишу, дверь открывается\закрывается и в это же время нажал другую клавишу и одновременно пошло открытие\закрытие другой двери? И т.д. Можно это показать для этого же примера?
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CAutomobile.h"
  4. #include "game_sa\CTimer.h"
  5.  
  6. using namespace plugin;
  7.  
  8. const float ACTION_TIME_STEP = 0.005f;
  9. const unsigned int TIME_FOR_KEYPRESS = 500;
  10.  
  11. class DoorsExample {
  12. public:
  13.     static int componentByDoorId[6]; // Таблица перевода eDoors в Id компонента
  14.  
  15.     static int m_nLastTimeWhenAnyActionWasEnabled; // Последнее время запуска события
  16.  
  17.     enum eDoorEventType { // Тип события
  18.         DOOR_EVENT_OPEN,
  19.         DOOR_EVENT_CLOSE
  20.     };
  21.  
  22.     class DoorEvent { // Класс события
  23.     public:
  24.         bool m_active;
  25.         eDoorEventType m_type;
  26.         float m_openingState;
  27.        
  28.         DoorEvent() {
  29.             m_active = false;
  30.             m_type = DOOR_EVENT_CLOSE;
  31.         }
  32.     };
  33.  
  34.     class VehicleDoors {
  35.     public:
  36.         DoorEvent events[6]; // События для всех 6 дверей
  37.  
  38.         VehicleDoors(CVehicle *) {}
  39.     };
  40.  
  41.     static VehicleExtendedData<VehicleDoors> VehDoors; // Наше расширение
  42.  
  43.     static void EnableDoorEvent(CAutomobile *automobile, eDoors doorId) { // Включить событие двери
  44.         if (automobile->IsComponentPresent(componentByDoorId[doorId])) {
  45.             if (automobile->m_damageManager.GetDoorStatus(doorId) != DAMSTATE_NOTPRESENT) {
  46.                 DoorEvent &event = VehDoors.Get(automobile).events[doorId];
  47.                 if (event.m_type == DOOR_EVENT_OPEN)
  48.                     event.m_type = DOOR_EVENT_CLOSE; // Если последнее событие - открытие, то закрываем
  49.                 else
  50.                     event.m_type = DOOR_EVENT_OPEN; // Если последнее событие закрытие - то открываем
  51.                 event.m_active = true; // Включаем обработку
  52.                 m_nLastTimeWhenAnyActionWasEnabled = CTimer::m_snTimeInMilliseconds;
  53.             }
  54.         }
  55.     }
  56.  
  57.     static void ProcessDoors(CVehicle *vehicle) { // Обработка событий для конкретного авто
  58.         if (vehicle->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE) {
  59.             CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  60.             for (unsigned int i = 0; i < 6; i++) { // Обрабатываем все события
  61.                 eDoors doorId = static_cast<eDoors>(i);
  62.                 DoorEvent &event = VehDoors.Get(automobile).events[doorId];
  63.                 if (event.m_active) { // Если событие активно
  64.                     if (event.m_type == DOOR_EVENT_OPEN) {
  65.                         event.m_openingState += ACTION_TIME_STEP;
  66.                         if (event.m_openingState > 1.0f) { // Если полностью открыли
  67.                             event.m_active = false; // Отключаем обработку
  68.                             automobile->OpenDoor(0, componentByDoorId[doorId], doorId, 1.0f, true); // Полностью открываем
  69.                             event.m_openingState = 1.0f;
  70.                         }
  71.                         else
  72.                             automobile->OpenDoor(0, componentByDoorId[doorId], doorId, event.m_openingState, true);
  73.                     }
  74.                     else {
  75.                         event.m_openingState -= ACTION_TIME_STEP;
  76.                         if (event.m_openingState < 0.0f) { // Если полностью открыли
  77.                             event.m_active = false; // Отключаем обработку
  78.                             automobile->OpenDoor(0, componentByDoorId[doorId], doorId, 0.0f, true); // Полностью открываем
  79.                             event.m_openingState = 0.0f;
  80.                         }
  81.                         else
  82.                             automobile->OpenDoor(0, componentByDoorId[doorId], doorId, event.m_openingState, true);
  83.                     }
  84.                 }
  85.             }
  86.         }
  87.     }
  88.  
  89.     static void MainProcess() { // Обработка нажатия клавиш и запуск событий
  90.         if (CTimer::m_snTimeInMilliseconds > (m_nLastTimeWhenAnyActionWasEnabled + TIME_FOR_KEYPRESS)) { // если прошло 500 мс с того времени, как мы начали открывать/закрывать что-то
  91.             CVehicle *vehicle = FindPlayerVehicle(0, false);
  92.             if (vehicle && vehicle->m_dwVehicleClass == VEHICLE_AUTOMOBILE) {
  93.                 CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle); // опять же, приведение типов. Т.к. мы будет юзать damageManager, нам нужно убедиться, что транспорт - это автомобиль (CAutomobile)
  94.                 if (KeyPressed(219)) // [
  95.                     EnableDoorEvent(automobile, BONNET); // капот
  96.                 else if (KeyPressed(221)) // ]
  97.                     EnableDoorEvent(automobile, BOOT); // багажник
  98.                 else if (KeyPressed(186) && KeyPressed(187)) // ; =
  99.                     EnableDoorEvent(automobile, DOOR_FRONT_LEFT); // левая передняя дверь
  100.                 else if (KeyPressed(222) && KeyPressed(187)) // ' =
  101.                     EnableDoorEvent(automobile, DOOR_FRONT_RIGHT); // правая передняя дверь
  102.                 else if (KeyPressed(186) && KeyPressed(189)) // ; -
  103.                     EnableDoorEvent(automobile, DOOR_REAR_LEFT); // левая задняя дверь
  104.                 else if (KeyPressed(222) && KeyPressed(189)) // ' -
  105.                     EnableDoorEvent(automobile, DOOR_REAR_RIGHT); // правая задняя дверь
  106.             }
  107.         }
  108.     }
  109.  
  110.     DoorsExample() {
  111.         Events::gameProcessEvent += MainProcess; // Тут обрабатываем нажатия и запускаем события
  112.         Events::vehicleRenderEvent += ProcessDoors; // Тут обрабатываем события, а также выключаем их
  113.     }
  114. } example;
  115.  
  116. int DoorsExample::componentByDoorId[6] = { CAR_BONNET, CAR_BOOT, CAR_DOOR_LF, CAR_DOOR_RF, CAR_DOOR_LR, CAR_DOOR_RR };
  117. int DoorsExample::m_nLastTimeWhenAnyActionWasEnabled = 0;
  118. VehicleExtendedData<DoorsExample::VehicleDoors> DoorsExample::VehDoors;
В этом примере процессы обработки нажатия клавиш и открытия/закрытия компонентов разделены.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 12, 2016, 03:58:18 pm
В этом примере процессы обработки нажатия клавиш и открытия/закрытия компонентов разделены.
Круто! Спасибо за пример.

Вопросы:
1) Названия классов могут совпадать в разных плагинах? Никакого конфликта не будет? Или всё, что делается в одном плагине остальных никак не касается?
2) В конце кода это зачем?
Код: C++
  1. int DoorsExample::componentByDoorId[6] = { CAR_BONNET, CAR_BOOT, CAR_DOOR_LF, CAR_DOOR_RF, CAR_DOOR_LR, CAR_DOOR_RR };
  2. int DoorsExample::m_nLastTimeWhenAnyActionWasEnabled = 0;
  3. VehicleExtendedData<DoorsExample::VehicleDoors> DoorsExample::VehDoors;
3) В примере спаунера транспорта https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_VehicleSpawner/Main.cpp (https://github.com/DK22Pac/plugin-sdk/blob/master/examples/SA_VehicleSpawner/Main.cpp) при вызове модели типа train происходит вылет игры. Видимо эта функция не предназначена для работы с таким типом транспорта.

Прошло две недели с начала моего обучения, пора показать первый результат. Переписал скрипт Дениса Car Spawner 3 на С++. Посмотри пожалуйста. Можно ли, что-то улучшить, оптимизировать?
Код клео
{$CLEO}  // 0 - 48 , 9 -57
var
    0@: array 5 of Integer  // digits     0 1 2 3 4
    17@: Integer             // index
    6@: Integer             // current_digit
    7@: Integer             // SUM
    8@: Integer             // KEY_HOLD
    15@: Integer             // KEY
end
const
    DIGIT = 0@
    i = 17@
    CURRENT_DIGIT = 6@
    SUM = 7@
    KEY_HOLD = 8@
    KEY = 15@
end
CURRENT_DIGIT = 1
while true
    wait 0
    if or
        not player.Defined($PLAYER_CHAR)
        $ONMISSION <> 0
    then   
        CURRENT_DIGIT = 1
        SUM = 0
        KEY_HOLD = False
        for i = 0 to 4
            0006: DIGIT[i] = 0 
        end
        continue
    end
    if
        8AB0: not key_pressed 2
    then
        if and
            SUM > 0
            SUM < 19010
        then
            if
                07DE: model SUM exists // versionB
            then
                0AA7: call_function 0x4C5AA0 num_params 1 pop 1 SUM 9@ // isModelCar
                0AA7: call_function 0x4C5B60 num_params 1 pop 1 SUM 10@ // isModelBike
                0AA7: call_function 0x4C5C20 num_params 1 pop 1 SUM 11@ // isModelBmx
                0AA7: call_function 0x4C5BF0 num_params 1 pop 1 SUM 12@ // isModelQuad
                0AA7: call_function 0x4C5C50 num_params 1 pop 1 SUM 13@ // isModelTrailer
                0AA7: call_function 0x4C5BC0 num_params 1 pop 1 SUM 14@ // isModelMTruck
                if or
                    081E:   model SUM boat
                    081F:   model SUM plane
                    0820:   model SUM heli
                    9@ == True
                then
                    0ADD: spawn_car_with_model SUM at_player_location
                else
                    if or
                        10@ == 8766721 // True
                        11@ == 8766721 // True
                        12@ == 8766721 // True
                        13@ == 8766721 // True
                        14@ == True
                    then
                        0ADD: spawn_car_with_model SUM at_player_location
                    end
                end
            end
        end
        CURRENT_DIGIT = 1
        SUM = 0
        KEY_HOLD = False
        for i = 0 to 4
            0006: DIGIT[i] = 0 
        end
        continue
    end    // key pressed 2
    if
        KEY_HOLD == False
    then
        if
            0AB0: key_pressed 8
        then
            KEY_HOLD = True
            if
                CURRENT_DIGIT > 1
            then
                CURRENT_DIGIT /= 10
                008F: 16@ = integer CURRENT_DIGIT to_float
                0AEF: 16@ = log 16@ base 10.0 //all floats
                SUM = 0
                0092: 16@ = float 16@ to_integer
                16@ -= 1
                for i = 0 to 16@
                    0016: DIGIT[i] /= 10
                    005A: SUM += DIGIT[i] // (int)
                end
            end
        else
            if
                SUM >= 19010
            then
                continue
            end
            KEY = 48
            for i = 0 to 9
                if
                    0AB0: key_pressed KEY
                then
                    008F: 16@ = integer CURRENT_DIGIT to_float
                    0AEF: 16@ = log 16@ base 10.0 //all floats
                    SUM = 0
                    0092: 16@ = float 16@ to_integer
                    0085: DIGIT[16@] = i   // int
                    for i = 0 to 16@
                        if
                            001D:   16@ > i // (int)
                        then
                            0012: DIGIT[i] *= 10
                        end
                        005A: SUM += DIGIT[i] // (int)
                    end
                    CURRENT_DIGIT *= 10
                    KEY_HOLD = True
                    break
                end
                KEY += 1
            end
        end
    else  //  KEY_HOLD == True
        if and
            8AB0: not key_pressed 48
            8AB0: not key_pressed 49
            8AB0: not key_pressed 50
            8AB0: not key_pressed 51
            8AB0: not key_pressed 52
        then
            if and
                8AB0: not key_pressed 53
                8AB0: not key_pressed 54
                8AB0: not key_pressed 55
                8AB0: not key_pressed 56
                8AB0: not key_pressed 57
                8AB0: not key_pressed 8
            then
                KEY_HOLD = False
            end
        end
    end  // KEY_HOLD == False
    if
        CURRENT_DIGIT > 1
    then
        03F0: enable_text_draw 1
        045A: draw_text_1number 320.0 240.0 GXT 'NUMBER' number SUM
    end
end

Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CFont.h"
  4. #include "game_sa\CText.h"
  5. #include "game_sa\CCheat.h"
  6. #include "game_sa\eModelID.h"
  7. #include "game_sa\CModelInfo.h"
  8.  
  9. // originally made by Den_spb
  10.  
  11. using namespace plugin;
  12.  
  13. class MoreVehiclesSpawner {
  14. public:
  15.     MoreVehiclesSpawner() {
  16.     static int digits[] = { 0, 0, 0, 0, 0 };
  17.     static int current_digit = 1;
  18.     static unsigned int sum = 0;
  19.     static bool key_hold = false;
  20.     static int key = 48;
  21.     static int i_16 = 0;
  22.     static float f_16 = 0.0f;
  23.  
  24.         Events::drawingEvent += [] {
  25.             CPed *playa = FindPlayerPed();
  26.             if (playa && playa->IsAlive()) {
  27.                 if (KeyPressed(2)) {
  28.                     // вывод на экран
  29.                     if (current_digit > 1) {
  30.                         CFont::SetScale(0.5f, 1.0f);
  31.                         CFont::SetColor(CRGBA(255, 255, 255, 255));
  32.                         CFont::SetAlignment(ALIGN_LEFT);
  33.                         CFont::SetOutlinePosition(1);
  34.                         CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  35.                         CFont::SetBackground(false, false);
  36.                         CFont::SetFontStyle(FONT_SUBTITLES);
  37.                         CFont::SetProp(true);
  38.                         CFont::SetWrapx(600.0f);
  39.                         char text[16];
  40.                         sprintf(text, "%d", sum);
  41.                         CFont::PrintString(300.0f, 10.0f, text);
  42.                     }
  43.                     if (key_hold == false) {
  44.                         // корректировка цифр
  45.                         if (KeyPressed(8)) {
  46.                             key_hold = true;
  47.                             if (current_digit > 1) {
  48.                                 current_digit /= 10;
  49.                                 f_16 = log10(static_cast<float>(current_digit));
  50.                                 sum = 0;
  51.                                 i_16 = static_cast<int>(f_16);
  52.                                 i_16 -= 1;
  53.                                 for (int i = 0; i <= i_16; i++) {
  54.                                     digits[i] /= 10;
  55.                                     sum += digits[i];
  56.                                 }
  57.                             }
  58.                         }
  59.                         // набор цифр
  60.                         else {
  61.                             if (sum >= 19010) {
  62.                                 sum = 0;
  63.                                 current_digit = 1;
  64.                                 key_hold = false;
  65.                                 for (int i = 0; i <= 4; i++) {
  66.                                     digits[i] = 0;
  67.                                 }
  68.                             }
  69.                             key = 48;
  70.                             for (int i = 0; i <= 9; i++) {
  71.                                 if (KeyPressed(key)) {
  72.                                     f_16 = log10(static_cast<float>(current_digit));
  73.                                     sum = 0;
  74.                                     i_16 = static_cast<int>(f_16);
  75.                                     digits[i_16] = i;
  76.                                     for (int i = 0; i <= i_16; i++) {
  77.                                         if (i_16 > i)
  78.                                             digits[i] *= 10;
  79.                                         sum += digits[i];
  80.                                     }
  81.                                     current_digit *= 10;
  82.                                     key_hold = true;
  83.                                     break;
  84.                                 }
  85.                                 key++;
  86.                             }
  87.                         }
  88.                     }
  89.                     else {
  90.                         if (!KeyPressed(8) && !KeyPressed(48) && !KeyPressed(49)
  91.                             && !KeyPressed(50) && !KeyPressed(51) && !KeyPressed(52)
  92.                             && !KeyPressed(53) && !KeyPressed(54) && !KeyPressed(55)
  93.                             && !KeyPressed(56) && !KeyPressed(57))
  94.                             key_hold = false;
  95.                     }
  96.                 }
  97.                 // спавн транспорта
  98.                 else {
  99.                     if (sum > 0 && sum < 19010) {
  100.                         CVehicleModelInfo *typModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::IsVehicleModelType(sum));
  101.                         if (reinterpret_cast<int>(typModel) != -1
  102.                             && reinterpret_cast<int>(typModel) != 6)
  103.                             CCheat::VehicleCheat(sum);
  104.                     }
  105.                                                
  106.                     sum = 0;
  107.                     current_digit = 1;
  108.                     key_hold = false;
  109.                     for (int i = 0; i <= 4; i++) {
  110.                         digits[i] = 0;
  111.                     }
  112.                 }
  113.             }
  114.         };
  115.     }
  116. } moreVehiclesSpawner;
  117.  
   
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 12, 2016, 08:03:45 pm
Цитировать
Круто! Спасибо за пример.
Пример не самый простой получился... Для полного понимания нужно ознакомиться с понятиями
-класса
-конструктора класса
-ссылками
в С++.
В plugin-sdk реализована возможность "прицепить" свой класс к классу транспорта (CVehicle).
Для наглядности я сделал ещё один пример.
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CSprite.h"
  3. #include "game_sa\CFont.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class DistanceExample {
  8. public:
  9.     class DistanceInfo {
  10.     public:
  11.         // данные нашего класса
  12.         float distance; // пройденная дистанция
  13.         bool startedPositionRecording; // если уже начали отслеживать позицию
  14.         CVector lastPosition; // последняя позиция
  15.  
  16.         DistanceInfo(CVehicle *vehicle) {
  17.             // Контсруктор нашего класса. Должен быть обязательно обьявлен. Принимает один параметр -
  18.             // транспорт, к которому "прицепляется" этот класс.
  19.             // Этот конструктор будет вызван на этапе конструирования CVehicle (CVehicle::CVehicle).
  20.             // При этом, обращаться к каким-либо членам CVehicle запрещено (обьект CVehicle ещё не построен до конца).
  21.             distance = 0.0f; // устанавливаем начальное значение
  22.             startedPositionRecording = false;
  23.         }
  24.     };
  25.  
  26.     DistanceExample() {
  27.         static VehicleExtendedData<DistanceInfo> VehDistance; // Наше расширение
  28.  
  29.         Events::vehicleRenderEvent += [](CVehicle *vehicle) {
  30.             DistanceInfo &info = VehDistance.Get(vehicle); // Получаем наши данные для этого транспорта
  31.             if (info.startedPositionRecording) // если info.lastPosition не "пустой"
  32.                 info.distance += DistanceBetweenPoints(info.lastPosition, vehicle->GetPosition()); // добавляем расстояние
  33.             else
  34.                 info.startedPositionRecording = true;
  35.             info.lastPosition = vehicle->GetPosition();
  36.         };
  37.  
  38.         Events::drawingEvent += [] {
  39.             for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  40.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  41.                 if (vehicle && vehicle->GetIsOnScreen()) {
  42.                     CVector &posn = vehicle->GetPosition();
  43.                     RwV3d rwp = { posn.x, posn.y, posn.z + 1.0f };
  44.                     RwV3d screenCoors; float w, h;
  45.                     if (CSprite::CalcScreenCoors(rwp, &screenCoors, &w, &h, true, true) && w > 10.0f) {
  46.                         CFont::SetAlignment(ALIGN_CENTER);
  47.                         CFont::SetColor(CRGBA(255, 255, 255, 255));
  48.                         CFont::SetOutlinePosition(1);
  49.                         CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  50.                         CFont::SetBackground(false, false);
  51.                         CFont::SetCentreSize(300.0f);
  52.                         CFont::SetScale(w * 0.015f, h * 0.03f);
  53.                         CFont::SetFontStyle(FONT_PRICEDOWN);
  54.                         CFont::SetProp(true);
  55.                         static char text[16];
  56.                         sprintf(text, "%.2f", VehDistance.Get(vehicle).distance);
  57.                         CFont::PrintString(screenCoors.x, screenCoors.y, text);
  58.                     }
  59.                 }
  60.             }
  61.         };
  62.     }
  63. } example;
Цитировать
1) Названия классов могут совпадать в разных плагинах? Никакого конфликта не будет? Или всё, что делается в одном плагине остальных никак не касается?
Да, можешь использовать одинаковые названия.
Цитировать
2) В конце кода это зачем?
Эти переменные были обьявлены как статические внутри класса.
Такие переменные надо дополнительно определить за пределами класса, в глобальной области видимости.
https://msdn.microsoft.com/ru-ru/library/b1b5y48f.aspx
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CMessages.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class ShowValue {
  7. public:
  8.     static unsigned int value; // Переменная обьявлена внутри класса.
  9.                                // Внутри класса мы можем обращаться к этой переменной вот так: value
  10.  
  11.     ShowValue() {
  12.         Events::gameProcessEvent += [] {
  13.             CMessages::AddMessageJumpQWithNumber("~1~", 100, 0, value, -1, -1, -1, -1, -1, false);
  14.         };
  15.     }
  16. } example;
  17.  
  18. unsigned int ShowValue::value = 12345; // А определяем в глобальной области.
  19.                                        // За пределами класса мы можем обращаться к этой переменной
  20.                                        // вот так: ShowValue::value
  21.  
  22. class AnotherClass {
  23. public:
  24.     AnotherClass() {
  25.         Events::gameProcessEvent += [] {
  26.             CMessages::AddBigMessageWithNumberQ("~1~", 100, 0, ShowValue::value, -1, -1, -1, -1, -1);
  27.         };
  28.     }
  29. } another;
Вообще, это всё - на твоё личное усмотрение :) Мне просто удобнее так - когда всё "упаковано" в класс, а конкретные переменные ассоциируются с конкретным классом.
Никто не запрещает обьявлять глобальные переменные вне класса.
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CMessages.h"
  3.  
  4. using namespace plugin;
  5.  
  6. // Переменная обьявлена и определена в глобальной области.
  7. // Мы можем использовать эту переменную где угодно.
  8. unsigned int value = 12345;
  9.  
  10. class ShowValue {
  11. public:
  12.     ShowValue() {
  13.         Events::gameProcessEvent += [] {
  14.             CMessages::AddMessageJumpQWithNumber("~1~", 100, 0, value, -1, -1, -1, -1, -1, false);
  15.         };
  16.     }
  17. } example;
Можно обьявлять статические переменные и в теле функций. Такие переменные не нужно определять вне класса. Но обращаться к таким переменным можно только внутри функции (в которой они обьявлены)!
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CMessages.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class ShowValue {
  7. public:
  8.     ShowValue() {
  9.         static unsigned int value = 12345; // Переменная обьявлена и определена внутри конструктора.
  10.                                            // Мы можем обращаться к этой переменной только в конструкторе.
  11.  
  12.         Events::gameProcessEvent += [] { // Здесь мы используем лямба-выражение - формируем функцию "на лету"
  13.             CMessages::AddMessageJumpQWithNumber("~1~", 100, 0, value, -1, -1, -1, -1, -1, false);
  14.         };
  15.     }
  16.  
  17.     static void MyDrawingFunction() {
  18.         // а вот тут мы уже не можем получить доступ к value
  19.     }
  20. } example;

По коду Den_spb могу точно сказать, что здесь у тебя что-то не так:
Код: C++
  1. CVehicleModelInfo *typModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::IsVehicleModelType(sum));
  2. if (reinterpret_cast<int>(typModel) != -1
  3.     && reinterpret_cast<int>(typModel) != 6)
CModelInfo::IsVehicleModelType возвращает boolean (true/false), зачем переводить его в VehicleModelInfo, и сравнивать с -1 и 6 - непонятно.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 13, 2016, 08:02:44 am
Спасибо за очередной пример и пояснения!

Цитировать
CModelInfo::IsVehicleModelType возвращает boolean (true/false), зачем переводить его в VehicleModelInfo, и сравнивать с -1 и 6 - непонятно.
После перевода получается тип модели (0=car, 9=bike, 11=trailer и т.д.). А если модель не является транспортом или вообще нет такой модели, то получается значение -1, а 6 - это модель типа train. Вот я и проверяю, что набранное число - это ID модели транспорта и при этом не является моделью train. Потому как, если модель train, то происходит вылет игры. По другому я не придумал, как проверить. Денис проверял, что модель есть (в моём коде сравнение с -1) и она является любой из моделей, кроме train (в моём коде сравнение с 6). Так-то плагин в работе я проверил, всё работает. Просто по самому коду - может, где-то можно, что-то оптимизировать?
                if
                07DE: model SUM exists // versionB
            then
                0AA7: call_function 0x4C5AA0 num_params 1 pop 1 SUM 9@ // isModelCar
                0AA7: call_function 0x4C5B60 num_params 1 pop 1 SUM 10@ // isModelBike
                0AA7: call_function 0x4C5C20 num_params 1 pop 1 SUM 11@ // isModelBmx
                0AA7: call_function 0x4C5BF0 num_params 1 pop 1 SUM 12@ // isModelQuad
                0AA7: call_function 0x4C5C50 num_params 1 pop 1 SUM 13@ // isModelTrailer
                0AA7: call_function 0x4C5BC0 num_params 1 pop 1 SUM 14@ // isModelMTruck
                if or
                    081E:   model SUM boat
                    081F:   model SUM plane
                    0820:   model SUM heli
                    9@ == True
                then
                    0ADD: spawn_car_with_model SUM at_player_location
                else
                    if or
                        10@ == 8766721 // True
                        11@ == 8766721 // True
                        12@ == 8766721 // True
                        13@ == 8766721 // True
                        14@ == True
                    then
                        0ADD: spawn_car_with_model SUM at_player_location
                    end
                end
            end


UPD:
Что-то я действительно намудрил.  :)
CModelInfo::IsVehicleModelType(sum) как раз и вернёт тип модели (0=car, 9=bike, 11=trailer и т.д.). А если модель не является транспортом или вообще нет такой модели, то получается значение -1.
Вот так надо:
Код: C++
  1. if (CModelInfo::IsVehicleModelType(sum) != -1 && CModelInfo::IsVehicleModelType(sum) != 6)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 13, 2016, 06:23:22 pm
Да, это я не досмотрел.
CModelInfo::IsVehicleModelType возвращает тип модели транспорта.
Но переводить его CVehicleModelInfo* не надо.
Код: C++
  1. if (sum > 0 && sum < 19010) {
  2.     int modelType = CModelInfo::IsVehicleModelType(sum);
  3.     if (modelType != -1 && modelType != 6)
  4.         CCheat::VehicleCheat(sum);
  5. }
Цитировать
Видимо эта функция не предназначена для работы с таким типом транспорта.

Действительно, в CCheat::VehicleCheat (которая также используется в опкоде 0ADD), нет варианта с созданием поезда. Вместо этого можно поэкспериментировать с функцией CTrain::CreateMissionTrain.
По поводу скрипта Дениса:
Я бы вообще переделал обработку набора числа.
В C++ можно сделать всё намного "чище".

KeyCheck.h
Код: C++
  1. #pragma once
  2.  
  3. class KeyCheck {
  4.     static unsigned char currStates[256];
  5.     static unsigned char prevStates[256];
  6.     static unsigned int timeDelayPressed[256];
  7. public:
  8.     static void Update(); // апдейт клавиш. Нужно вызывать эту функцию один раз за фрейм, перед тем, как проверять клавиши
  9.  
  10.     static bool Check(unsigned int key); // Проверить, нажата ли сейчас клавиша
  11.     static bool CheckJustDown(unsigned int key); // Проверить, была ли нажата клавиша прямо сейчас
  12.     static bool CheckJustUp(unsigned int key); // Проверить, была ли отпущена клавиша прямо сейчас
  13.     static bool CheckWithDelay(unsigned int key, unsigned int time); // Проверить нажата ли клавиша, с интервалом проверки
  14. };

KeyCheck.cpp
Код: C++
  1. #include "KeyCheck.h"
  2. #include "plugin.h"
  3. #include "game_sa\CTimer.h"
  4.  
  5. unsigned char KeyCheck::currStates[256] = {};
  6. unsigned char KeyCheck::prevStates[256] = {};
  7. unsigned int KeyCheck::timeDelayPressed[256] = {};
  8.  
  9. void KeyCheck::Update() {
  10.     memcpy(prevStates, currStates, 256);
  11.     GetKeyboardState(currStates);
  12. }
  13.  
  14. bool KeyCheck::Check(unsigned int key) {
  15.     return key < 256 && (currStates[key] & 0x80);
  16. }
  17.  
  18. bool KeyCheck::CheckJustDown(unsigned int key) {
  19.     return key < 256 && (currStates[key] & 0x80) && !(prevStates[key] & 0x80);
  20. }
  21.  
  22. bool KeyCheck::CheckJustUp(unsigned int key) {
  23.     return key < 256 && !(currStates[key] & 0x80) && (prevStates[key] & 0x80);
  24. }
  25.  
  26. bool KeyCheck::CheckWithDelay(unsigned int key, unsigned int time) {
  27.     if (key < 256 && (currStates[key] & 0x80)) {
  28.         if (!(prevStates[key] & 0x80) || CTimer::m_snTimeInMilliseconds >(timeDelayPressed[key] + time)) {
  29.             timeDelayPressed[key] = CTimer::m_snTimeInMilliseconds;
  30.             return true;
  31.         }
  32.     }
  33.     return false;
  34. }

Main.cpp
Код: C++
  1. #include <string>
  2. #include "plugin.h"
  3. #include "KeyCheck.h"
  4. #include "game_sa\common.h"
  5. #include "game_sa\CModelInfo.h"
  6. #include "game_sa\CCheat.h"
  7. #include "game_sa\CTimer.h"
  8. #include "game_sa\CFont.h"
  9. #include "game_sa\CSprite2d.h"
  10.  
  11. using namespace plugin;
  12.  
  13. class MoreVehiclesSpawner {
  14. public:
  15.     static std::string typedBuffer;
  16.     static std::string errorMessage;
  17.     static std::string errorMessageBuffer;
  18.     static unsigned int errorMessageTimer;
  19.     static bool enabled;
  20.  
  21.     static void ReportAudioEvent(int audioEventId, float volume, float speed) { // с классами, связанными со звуком, в sdk пока что не очень
  22.         CallMethod<NoRet, 0x506EA0, unsigned int, int, float, float>(0xB6BC90, audioEventId, volume, speed);
  23.     }
  24.  
  25.     static void Update() {
  26.         KeyCheck::Update(); // апдейтим состояния клавиш
  27.         if (FindPlayerPed() && FindPlayerPed()->IsAlive()) {
  28.             if (KeyCheck::CheckJustDown(VK_TAB)) { // Если нажата Tab - включаем или выключаем консоль
  29.                 enabled = !enabled;
  30.                 typedBuffer.clear();
  31.                 errorMessageBuffer.clear();
  32.             }
  33.             if (enabled) {
  34.                 errorMessage.clear();
  35.                 if (KeyCheck::CheckWithDelay(VK_BACK, 200)) { // Если нажат Backspace - убираем последний символ в строке
  36.                     if (typedBuffer.size() > 0) {
  37.                         typedBuffer.pop_back();
  38.                         ReportAudioEvent(3, 0.0f, 1.0f);
  39.                     }
  40.                 }
  41.                 else {
  42.                     for (int i = 0; i <= 9; i++) {
  43.                         if (KeyCheck::CheckWithDelay(i + 48, 200)) {
  44.                             if (typedBuffer.size() == 5)
  45.                                 errorMessage = "Too many digits!";
  46.                             else {
  47.                                 typedBuffer.push_back(i + 48); // Добавляем символ в конец строки
  48.                                 ReportAudioEvent(3, 0.0f, 1.0f);
  49.                             }
  50.                             break;
  51.                         }
  52.                     }
  53.                 }
  54.                 if (KeyCheck::CheckJustDown(VK_RETURN)) { // Если нажата Return - спавним транспорт
  55.                     if (typedBuffer.size() > 0) {
  56.                         unsigned int modelId = std::stoi(typedBuffer);
  57.                         if (modelId < 19010) {
  58.                             int modelType = CModelInfo::IsVehicleModelType(modelId);
  59.                             if (modelType != -1) {
  60.                                 if (modelType != 6) {
  61.                                     CCheat::VehicleCheat(modelId);
  62.                                     ReportAudioEvent(12, 0.0f, 1.0f);
  63.                                     errorMessageBuffer.clear(); // убираем надпись об ошибке (если она была на экране)
  64.                                 }
  65.                                 else
  66.                                     errorMessage = "Can't spawn a train model";
  67.                             }
  68.                             else
  69.                                 errorMessage = "This model is not a vehicle!";
  70.                         }
  71.                         else
  72.                             errorMessage = "ID is too big!";
  73.                     }
  74.                     else
  75.                         errorMessage = "Please enter model Id!";
  76.                 }
  77.             }
  78.         }
  79.         else
  80.             enabled = false;
  81.     }
  82.  
  83.     static void Render() {
  84.         if (enabled) {
  85.             CSprite2d::DrawRect(CRect(100.0f, 100.0f, 470.0f, 200.0f), CRGBA(0, 0, 0, 100));
  86.             CSprite2d::DrawRect(CRect(250.0f, 140.0f, 340.0f, 142.0f), CRGBA(255, 255, 255, 255));
  87.             CFont::SetScale(0.8f, 1.9f);
  88.             CFont::SetColor(CRGBA(255, 255, 255, 255));
  89.             CFont::SetAlignment(ALIGN_LEFT);
  90.             CFont::SetOutlinePosition(0);
  91.             CFont::SetBackground(false, false);
  92.             CFont::SetFontStyle(FONT_SUBTITLES);
  93.             CFont::SetProp(true);
  94.             CFont::SetWrapx(600.0f);
  95.             CFont::PrintString(105.0f, 105.0f, "Model ID:");
  96.             if (typedBuffer.size() > 0)
  97.                 CFont::PrintString(250.0f, 105.0f, const_cast<char*>(typedBuffer.c_str()));
  98.             if (errorMessage.size() > 0) {
  99.                 errorMessageBuffer = errorMessage;
  100.                 errorMessageTimer = CTimer::m_snTimeInMilliseconds;
  101.                 ReportAudioEvent(4, 0.0f, 1.0f);
  102.             }
  103.             if (errorMessageBuffer.size() > 0 && CTimer::m_snTimeInMilliseconds < (errorMessageTimer + 2000)) {
  104.                 CFont::SetColor(CRGBA(255, 0, 0, 255));
  105.                 CFont::PrintString(105.0f, 150.0f, const_cast<char*>(errorMessageBuffer.c_str()));
  106.             }
  107.         }
  108.     }
  109.  
  110.     MoreVehiclesSpawner() {
  111.         Events::gameProcessEvent += Update;
  112.         Events::drawingEvent += Render;
  113.     };
  114. } moreVehiclesSpawner;
  115.  
  116. std::string MoreVehiclesSpawner::typedBuffer;
  117. std::string MoreVehiclesSpawner::errorMessage;
  118. std::string MoreVehiclesSpawner::errorMessageBuffer;
  119. unsigned int MoreVehiclesSpawner::errorMessageTimer = 0;
  120. bool MoreVehiclesSpawner::enabled = false;

Цитировать
Давно задаюсь вопросом - можно ли переписать эту функцию так, чтобы считывать пары ID тягача и ID прицепа из текстового файла (ну в крайнем случае в сам плагин набрать это сочетание, ну лучше считывать из текстового файла) и потом аналогичным образом спаунить другие тягачи с прицепами, ведь нормального спаунера авто с прицепами так и не сделали.

Для прямой работы с памятью в sdk есть класс patch.
Для подмены функций можно использовать:
plugin::patch::RedirectCall(адрес_места_вызова, своя_функция);
plugin::patch::RedirectJump(адрес_функции, своя_функция);
При этом, новая функция должна совпадать с оригинальной - параметрами и соглашением вызова.
Выбор способа патча зависит от ситуации.
В большинстве случаев, если нужно полностью заменить тело функции, я использую RedirectJump.

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

(http://i.imgur.com/7zxL7Le.png)

Вот что получилось:
Код: C++
  1. #include "plugin.h"
  2. #include "game_sa\CStreaming.h"
  3. #include "game_sa\CCheat.h"
  4. #include "game_sa\CTrailer.h"
  5. #include "game_sa\CWorld.h"
  6.  
  7. using namespace plugin;
  8.  
  9. unsigned int truckModelIds[3] = { MODEL_LINERUN, MODEL_PETRO, MODEL_RDTRAIN };
  10. unsigned int trailerModelIds[4] = { MODEL_ARTICT1, MODEL_ARTICT2, MODEL_PETROTR, MODEL_ARTICT3 };
  11.  
  12. class SpawnTruckCheat {
  13. public:
  14.     static void Spawn() {
  15.         CVehicle *vehicle = CCheat::VehicleCheat(truckModelIds[rand() % 3]); // спавним тягач
  16.         if (vehicle) {
  17.             unsigned int modelId = trailerModelIds[rand() % 4]; // получаем случайный ID
  18.             CStreaming::RequestModel(modelId, 0); // 0 - значит, что игра может удалить эту модель когда она больше нигде не будет нужна
  19.             CStreaming::LoadAllRequestedModels(false);
  20.             if (CStreaming::ms_aInfoForModel[modelId].m_loadState == LOADSTATE_LOADED) {
  21.                 CTrailer *trailer = new CTrailer(modelId, 1); // создаём прицеп //--+
  22.                 if (trailer) {                                                  //  | По сути, функция CCheat::VehicleCheat
  23.                     trailer->SetPosn(vehicle->GetPosition());                   //  | делает всё то же самое - создаёт обьект
  24.                     trailer->SetOrientation(0.0f, 0.0f, 3.4906585f);            //  | CAutomobile/CBike/CBoat/CHeli и т.д.,
  25.                     trailer->m_nStatus = 4; // что это за статус - без понятия  //  | устанавливает ему позицию и вращение,
  26.                     CWorld::Add(trailer);                                       //  | добавляет в "мир", и т.д.
  27.                     trailer->SetTowLink(vehicle, true);                         //--+
  28.                 }
  29.             }
  30.         }
  31.     }
  32.    
  33.     SpawnTruckCheat() {
  34.         patch::RedirectJump(0x43A570, Spawn);
  35.     };
  36. } spawnTruck;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 14, 2016, 11:13:48 am
Цитировать
KeyCheck.h
KeyCheck.cpp
Добавил в \plugin_sa\game_sa или надо было в другое место добавлять?

Цитировать
По поводу скрипта Дениса:
Я бы вообще переделал обработку набора числа.
В C++ можно сделать всё намного "чище".
Ну да, так лучше, чем в моём варианте.  :)

Цитировать
Вот что получилось:
Класс! Спасибо за пример и пояснения! Есть один момент - при повторном спауне первый тягач благополучно удаляется, а вот первый прицеп нет и получается ко второму тягачу цепляются два прицепа, через некоторое время они взрываются. Для прицепа нужен RemoveReferences. Как добавить?

И ещё сразу по прицепам есть вопрос - можно ли в трафике в процессе создания транспорта проверить, если модель определённого ID (тягач), то цеплять к нему прицеп. Цеплять не на весь транспорт с таким ID, а выборочно, ну скажем через определённое время? Цеплять разные прицепы?

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 14, 2016, 11:34:17 am
Добавил в \plugin_sa\game_sa или надо было в другое место добавлять?

Добавляй в проект твоего плагина.
(http://i.imgur.com/fbVCB2c.png)

Есть один момент - при повторном спауне первый тягач благополучно удаляется, а вот первый прицеп нет и получается ко второму тягачу цепляются два прицепа, через некоторое время они взрываются. Для прицепа нужен RemoveReferences. Как добавить?

Тут нужен не RemoveReference.
В функции CCheat::VehicleCheat ещё вызывается CTheScripts::ClearSpaceForMissionEntity, которая удаляет все обьекты на месте спавна транспорта.
После
Код: C++
  1. trailer->SetTowLink(vehicle, true);
Добавь
Код: C++
  1. Call<NoRet, 0x486B00, CVector const&, CEntity *>(trailer->GetPosition(), trailer);
Класс CTheScripts я постараюсь добавить позже.

И ещё сразу по прицепам есть вопрос - можно ли в трафике в процессе создания транспорта проверить, если модель определённого ID (тягач), то цеплять к нему прицеп. Цеплять не на весь транспорт с таким ID, а выборочно, ну скажем через определённое время? Цеплять разные прицепы?

Можно, надо разбирать CCarCtrl::GenerateOneRandomCar.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 14, 2016, 12:23:45 pm
Цитировать
Добавь
Код: C++
  1. Call<NoRet, 0x486B00, CVector const&, CEntity *>(trailer->GetPosition(), trailer);
Теперь нормально, спасибо!

Цитировать
trailer->m_nStatus = 4; // что это за статус - без понятия
Проверил, с значениями 0-2 прицеп становится поверх тягача, 3 тоже, что и 4 получился результат.

Цитировать
Добавляй в проект твоего плагина.
Упс.. а я добавил в \plugin_sa\game_sa да ещё и коммит сделал...  поторопился... Убрать из \plugin_sa\game_sa и сделать новый коммит или ты сам исправишь?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 14, 2016, 12:54:03 pm
Надо удалить файлы из папки, а также убрать из проекта (в Solution-explorer'e).
Можешь сделать, я позже буду коммиты делать.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 16, 2016, 11:30:39 am
Я с новой порцией вопросов.
1) Почитал про классы в С++. Написано:
Код: C++
  1. // объявление классов в С++
  2. class /*имя класса*/
  3. {
  4.   private:
  5.   /* список свойств и методов для использования внутри класса */
  6.   public:
  7.   /* список методов доступных другим функциям и объектам программы */
  8.   protected:
  9.   /*список средств, доступных при наследовании*/
  10. };

В примерах sdk в конце класса перед ; ставится ещё слово (здесь, например, playerTest, в других примерах другое, при этом я заметил, что с названием класса оно вообще может не совпадать). Для чего это слово?
Код: C++
  1. class PlayerTest {
  2. public:
  3.         PlayerTest() {
  4.                
  5.         }
  6. } playerTest;

2) Имеет ли значение в какой процесс "вклиниваться"?
3) Имеет ли значение каким способом это делать? Так
Код: C++
  1. Events::gameProcessEvent += [] {
  2.                        
  3. };
или так
Код: C++
  1. OpenDoorExample() {
  2.     Events::gameProcessEvent.Add(Process);
  3. }

4) Как я понял, если надо, чтобы два действия обрабатывались одновременно, надо "вклиниваться" в два разных процесса?
5) Как в плагине проверить $ONMISSION == 0
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 16, 2016, 07:35:27 pm
Код: C++
  1. class PlayerTest {
  2. public:
  3.         PlayerTest() {
  4.                
  5.         }
  6. } playerTest;
Это то же, что и
Код: C++
  1. class PlayerTest {
  2. public:
  3.         PlayerTest() {
  4.                
  5.         }
  6. };
  7.  
  8. PlayerTest playerTest;
Просто первый вариант выглядит компактнее.
Ну а это
Код: C++
  1. PlayerTest playerTest;
Обявление переменной playerTest с типом PlayerTest.
Причем обьявление происходит в глобальной области.
А все глобальные обьекты конструируются (т.е. вызывается их конструктор) при загрузке dll (asi).
Поэтому мы и определяем конструктор и добавляем туда инжект наших функций.

Уже говорил об этом тут (http://forum.gtabuilder.ru/index.php?topic=337.msg2155#msg2155) и тут (http://i.imgur.com/rFDIFbP.png)

2) Имеет ли значение в какой процесс "вклиниваться"?

Имеет. Например, ты не сможешь выводить что-либо на экран из эвента gameProcess. Для этого есть drawingEvent и подобные.
Или, например, тебе нужно загрузить текстуру, которая бы постоянно была в памяти (аналог в оригинальной игре - текстуры из hud.txt). Тут можно использовать rwInitEvent, а для выгрузки - rwShutdownEvent.
Для рисования на радаре есть drawRadarEvent. Ну и эвенты, связанные с игровыми субьектами - напр. vehicle/ped/object RenderEvent.
3) Имеет ли значение каким способом это делать? Так
Код: C++
  1. Events::gameProcessEvent += [] {
  2.                        
  3. };
или так
Код: C++
  1. OpenDoorExample() {
  2.     Events::gameProcessEvent.Add(Process);
  3. }

Нет. Просто в первом варинте используется лямбда-выражение (https://msdn.microsoft.com/uk-ua/library/dd293608.aspx).
А во втором - отдельно создается функция Process.
4) Как я понял, если надо, чтобы два действия обрабатывались одновременно, надо "вклиниваться" в два разных процесса?

Не обязательно. Просто с примером с открыванием компонентов удобнее было сделать именно так.
5) Как в плагине проверить $ONMISSION == 0

Есть функция CTheScripts::IsPlayerOnAMission().
Про этот класс я уже говорил.
Пока что вызвать можно так:
Код: C++
  1. plugin::Call<bool, 0x464D50>();
Или добавить её в класс.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 20, 2016, 01:12:47 pm
Понятно. Спасибо.

Решил переписать свой скрипт "Дизель" на С++
{$CLEO .cs}
0000:
const
   AVTO = 0@          // авто
   MODEL_AVTO = 1@    // модель авто
   CLASS_AVTO = 2@    // класс авто
   STRUCT_AVTO = 3@   // структура авто                         
   ENGINE_TYPE = 4@   // тип двигателя
   EXHAUST = 5@       // тип выхлопа
   PARTICLE_1 = 6@    // эффект_1
   PARTICLE_2 = 7@    // эффект_2
   DOUBLE = 8@        // вспомогательная переменная
   X_1 = 9@           // координата Х_1
   Y_1 = 10@          // координата Y_1
   Z_1 = 11@          // координата Z_1
   X_2 = 12@          // координата Х_2
end

var
   X_1: Float
   X_2: Float
end

while true
    wait 0
    if
      Player.Defined($PLAYER_CHAR)
    then
        if 
          actor.Driving($PLAYER_ACTOR)
        then
            03C0: AVTO = actor $PLAYER_ACTOR car // транспорт игрока
            if
              01C1: car AVTO stopped // транспорт стоит
            then
                if 
                  00E1: key_pressed 0 16
                then 
                    0441: MODEL_AVTO = car AVTO model   // модель транспорта
                    08EC: CLASS_AVTO = car AVTO type   // класс транспорта
                    if and
                      0A01: model MODEL_AVTO car // транспорт = авто
                      04A4: CLASS_AVTO == 4  // @ == any // класс авто worker
                    then
                        0A97: STRUCT_AVTO = car AVTO struct // структура авто
                        STRUCT_AVTO += 0x384
                        0A8D: STRUCT_AVTO = read_memory STRUCT_AVTO size 4 virtual_protect 0 // получили указатель на handling-структуру
                        STRUCT_AVTO += 0x75
                        0A8D: ENGINE_TYPE = read_memory STRUCT_AVTO size 1 virtual_protect 0 // получили тип двигателя
                        if
                          ENGINE_TYPE == 68 // тип двигателя = дизель
                        then 
                            MODEL_AVTO *= 4
                            MODEL_AVTO += 0xA9B0C8
                            0A8D: STRUCT_AVTO = read_memory MODEL_AVTO size 4 virtual_protect 0 // CModel
                            STRUCT_AVTO += 0x5C                                       
                            0A8D: STRUCT_AVTO = read_memory STRUCT_AVTO size 4 virtual_protect 0 // vehicle struct
                            STRUCT_AVTO += 0x48
                            0A8D: X_1 = read_memory STRUCT_AVTO size 4 virtual_protect 0 // X_1
                            STRUCT_AVTO += 4
                            0A8D: Y_1 = read_memory STRUCT_AVTO size 4 virtual_protect 0 // Y_1
                            STRUCT_AVTO += 4
                            0A8D: Z_1 = read_memory STRUCT_AVTO size 4 virtual_protect 0 // Z_1
                            //---определение второго глушителя---
                            0A97: STRUCT_AVTO = car AVTO struct
                            STRUCT_AVTO += 0x384
                            0A8D: STRUCT_AVTO = read_memory STRUCT_AVTO size 4 virtual_protect 0
                            STRUCT_AVTO += 0xCC
                            0A8D: EXHAUST = read_memory STRUCT_AVTO size 4 virtual_protect 0
                            if
                              08B7: test EXHAUST bit 13
                            then
                                DOUBLE = 2
                                X_2 = X_1
                                X_2 *= -1.0
                            else
                                DOUBLE = 1
                            end
                            //----------------------------------
                            066C: PARTICLE_1 = attach_particle "riot_smoke" to_car AVTO with_offset X_1 Y_1 Z_1 rotation 0.0 0.0 0.0 flag 1
                            064C: make_particle PARTICLE_1 visible
                            if
                              DOUBLE == 2
                            then
                                066C: PARTICLE_2 = attach_particle "riot_smoke" to_car AVTO with_offset X_2 Y_1 Z_1 rotation 0.0 0.0 0.0 flag 1
                                064C: make_particle PARTICLE_2 visible
                            end
                            wait 500
                            0650: destroy_particle PARTICLE_1
                            if
                              DOUBLE == 2
                            then
                                0650: destroy_particle PARTICLE_2
                            end
                        end     
                    end     
                end
            end
        end
    end
end 

Возникли вопросы:
1) Не нашёл в sdk замены
01C1: car AVTO stoppedПосмотрел опкод в базе и нашёл функцию
.text:004861F0     CScriptEngine__isVehicleStopped proc nearДобавил в CVehicle
Код: C++
  1. //CVehicle.h
  2. bool CVehicle::IsStopped();
  3. //CVehicle.cpp
  4. // Converted from thiscall bool CVehicle::IsStopped(void) 0x4861F0
  5. bool CVehicle::IsStopped()
  6. {
  7.   return ((bool(__cdecl *)(CVehicle*))0x4861F0)(this);
  8. }
Ну и вроде как этот вопрос решился.
2) Не нашёл в sdk замены (нашёл только перечисление ePadButton)
00E1: key_pressed 0 16В базе нашёл функцию
.text:00485B10     _CScriptThread__getPlayerKeyState proc nearТолько куда и как её добавить в sdk не разобрался.
3) Не могу понять как считать значение m_nEngineType из cTransmission.h
4) Также не понятно как проверить наличие второго глушителя у модели
m_bDoubleExhaust из tHandlingData.h

5) Работу с партициклами в sdk я тоже не нашёл
066C: PARTICLE_1 = attach_particle "riot_smoke" to_car AVTO with_offset X_1 Y_1 Z_1 rotation 0.0 0.0 0.0 flag 1
064C: make_particle PARTICLE_1 visible
0650: destroy_particle PARTICLE_1
Пока набросал примерный код без учёта непонятных моментов. Создание партицикла заменил на создание короны.
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CTimer.h"
  4. #include "game_sa\CModelInfo.h"
  5. #include "game_sa\CVehicle.h"
  6. #include "game_sa\tHandlingData.h"
  7. #include "game_sa\CCoronas.h"
  8.  
  9. using namespace plugin;
  10.  
  11. class Diesel {
  12. public:
  13.     Diesel() {
  14.     static bool m_currentState = true;
  15.     static unsigned int m_nLastTimeWhenAnyActionWasEnabled = 0;
  16.     static tHandlingData *hanlData;
  17.  
  18.         Events::gameProcessEvent += [] {
  19.             CVehicle *vehicle = FindPlayerVehicle(-1, false);
  20.             if (vehicle && vehicle->m_dwVehicleClass == VEHICLE_AUTOMOBILE && vehicle->IsStopped() && KeyPressed(87) && m_currentState) {
  21.                 CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]);
  22.                 hanlData = vehicle->m_pHandlingData;
  23.                 if (vehModel->m_nClass == 4 && hanlData->m_transmissionData.m_nEngineType == 68) {
  24.                     m_currentState = false;
  25.                     m_nLastTimeWhenAnyActionWasEnabled = CTimer::m_snTimeInMilliseconds;
  26.                 }
  27.             } else if (!m_currentState) {
  28.                        if (CTimer::m_snTimeInMilliseconds < (m_nLastTimeWhenAnyActionWasEnabled + 2000)) {
  29.                            CVector posn = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex])->m_pVehicleStruct->m_avDummyPosn[6];
  30.                            CCoronas::RegisterCorona(reinterpret_cast<unsigned int>(vehicle) + 50 + 6 + 0, vehicle, 255, 128, 0, 255, posn, 0.3f, 150.0f, CORONATYPE_SHINYSTAR, 0, false, false, 0, 0.0f, false, 0.5f, 0, 50.0f, false, true);
  31.                                if (hanlData->m_bDoubleExhaust) {
  32.                                    posn.x *= -1.0f;
  33.                                    CCoronas::RegisterCorona(reinterpret_cast<unsigned int>(vehicle) + 50 + 6 + 1, vehicle, 255, 128, 0, 255, posn, 0.3f, 150.0f, CORONATYPE_SHINYSTAR, 0, false, false, 0, 0.0f, false, 0.5f, 0, 50.0f, false, true);
  34.                                }
  35.                        } else
  36.                              m_currentState = true;
  37.               }
  38.         };
  39.     }
  40. } example;

Просьба прояснить эти вопросы.
6) Ещё в sdk есть перечисление eCommandName. Как можно использовать в написании плагина?


UPD:
С вопросами 3 и 4 разобрался, эти вопросы снимаются.
Код подредактировал.

Остальные вопросы всё ещё неразрешимы пока. Просьба помочь разобраться.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 24, 2016, 06:12:21 pm
.text:004861F0     CScriptEngine__isVehicleStopped proc near
Это CTheScripts::IsVehicleStopped(CVehicle *). Вообще, класс CScriptEngine (который в старой базе) - это CTheScripts ("Скрипты"). CScriptThread из старой базы - CRunningScript ("Исполняемый скрипт").
Я эту функцию и ещё некоторые (включая IsPlayerOnMission) добавил в последнем коммите.

2) Не нашёл в sdk замены (нашёл только перечисление ePadButton)
00E1: key_pressed 0 16В базе нашёл функцию
.text:00485B10     _CScriptThread__getPlayerKeyState proc near
Это
short CRunningScript::GetPadState(unsigned short player, unsigned short key)Тебе надо смотреть в CPad.
По идее, так должно работать:
Код: C++
  1. if (CPad::GetPad()->NewState.RightStickX)

5) Работу с партициклами в sdk я тоже не нашёл
Да, по партиклам почти ничего не было. Теперь есть.
Для создания и управления над партиклам есть классы FxManager_c, Fx_c, FxSystem_c.
Например, для создания можно использовать функции
Код: C++
  1. FxSystem_c* FxManager_c::CreateFxSystem(char* name, RwMatrixTag* transform, RwMatrixTag* objectMatrix, unsigned char ignoreBoundingChecks);
  2. FxSystem_c* FxManager_c::CreateFxSystem(char* name, RwV3d* position, RwMatrixTag* objectMatrix, unsigned char ignoreBoundingChecks);
А для удаления
Код: C++
  1. void FxSystem_c::Kill()
Вообще, рекомендую глянуть, как в оригинале создаются партиклы эффекта нитро, можно по аналогии прицеплять свои партиклы.
Детальнее чуть позже расскажу, может и пример сделаю.

Ещё в sdk есть перечисление eCommandName. Как можно использовать в написании плагина?
Это просто перечисление опкодов.
Использование вызова опкодов в плагинах не желательно (лучше просто посмотреть, как реализован опкод).

PS Добавил ссылку на свою базу в подпись. Для открытия нужна IDA 6.8.

UPD: Вот ещё немножко инфы.
Опкод 066C создаёт партикл примерно вот так (direction - в стром описании опкода это rotation, ignoreBoundingChecks - flag):
Код: C++
  1. g_fx.CreateMatFromVec(&rotationMat, &offset, &direction);
  2. FxSystem_c *fxSystem = g_fxMan.CreateFxSystem(name, &rotationMat, &vehicle->m_pRwObject->object.parent->modelling, ignoreBoundingChecks);
Опкод 064C делает вот это:
Код: C++
  1. fxSystem->Play()
Опкод 064E
Код: C++
  1. fxSystem->Stop()
Опкод 064F
Код: C++
  1. fxSystem->PlayAndKill()
Опкод 0650
Код: C++
  1. fxSystem->Kill()

Код: C++
  1. #include "plugin.h"
  2. #include "game_sa\CTheScripts.h"
  3. #include "game_sa\Fx_c.h"
  4. #include "game_sa\CTimer.h"
  5. #include "game_sa\CModelInfo.h"
  6. #include "game_sa\CPad.h"
  7. #include "game_sa\common.h"
  8.  
  9. using namespace plugin;
  10.  
  11. class Diesel {
  12. public:
  13.     class DieselData {
  14.     public:
  15.         FxSystem_c *m_apParticles[2];
  16.         unsigned int m_nCreationTime;
  17.  
  18.         DieselData(CVehicle *) {
  19.             m_apParticles[0] = m_apParticles[1] = nullptr;
  20.             m_nCreationTime = 0;
  21.         }
  22.  
  23.         ~DieselData() {
  24.             for (unsigned int i = 0; i < 2; i++) {
  25.                 if (m_apParticles[i]) {
  26.                     m_apParticles[i]->Kill();
  27.                     m_apParticles[i] = nullptr;
  28.                 }
  29.             }
  30.         }
  31.     };
  32.  
  33.     Diesel() {
  34.         static VehicleExtendedData<DieselData> VehDiesel;
  35.  
  36.         Events::gameProcessEvent += [] {
  37.             CVehicle *vehicle = FindPlayerVehicle(-1, false);
  38.             if (vehicle && vehicle->m_dwVehicleClass == VEHICLE_AUTOMOBILE && CTheScripts::IsVehicleStopped(vehicle) && CPad::GetPad()->NewState.ButtonCross) {
  39.                 CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]);
  40.                 if (vehModel->m_nClass == 4 && vehicle->m_pHandlingData->m_transmissionData.m_nEngineType == 'D') {
  41.                     DieselData &dieselData = VehDiesel.Get(vehicle);
  42.                     dieselData.m_nCreationTime = CTimer::m_snTimeInMilliseconds;
  43.                     RwV3d offset = *reinterpret_cast<RwV3d*>(&vehModel->m_pVehicleStruct->m_avDummyPosn[6]);
  44.                     if (!dieselData.m_apParticles[0]) {
  45.                         dieselData.m_apParticles[0] = g_fxMan.CreateFxSystem("riot_smoke", &offset, &reinterpret_cast<RwFrame*>(vehicle->m_pRwObject->parent)->modelling, true);
  46.                         if (dieselData.m_apParticles[0])
  47.                             dieselData.m_apParticles[0]->Play();
  48.                     }
  49.                     if (vehicle->m_pHandlingData->m_bDoubleExhaust) {
  50.                         if (!dieselData.m_apParticles[1]) {
  51.                             offset.x *= -1.0f;
  52.                             dieselData.m_apParticles[1] = g_fxMan.CreateFxSystem("riot_smoke", &offset, &reinterpret_cast<RwFrame*>(vehicle->m_pRwObject->parent)->modelling, true);
  53.                             if (dieselData.m_apParticles[1])
  54.                                 dieselData.m_apParticles[1]->Play();
  55.                         }
  56.                     }
  57.                 }
  58.             }
  59.         };
  60.  
  61.         Events::vehicleRenderEvent += [](CVehicle *vehicle) {
  62.             DieselData &dieselData = VehDiesel.Get(vehicle);
  63.             for (unsigned int i = 0; i < 2; i++) {
  64.                 if (dieselData.m_apParticles[i] && CTimer::m_snTimeInMilliseconds > (dieselData.m_nCreationTime + 500)) {
  65.                     dieselData.m_apParticles[i]->Kill();
  66.                     dieselData.m_apParticles[i] = nullptr;
  67.                 }
  68.             }
  69.         };
  70.     }
  71. } diesel;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 26, 2016, 09:41:52 am
Спасибо за пояснения и новую базу. Буду разбираться.

Когда-то меня просили написать скрипт для SA, чтобы у дополнительно установленных моделей типа zr350, фары открывались на разный угол. Ну т.е. задавать каждой модели в .ini файле свой угол открытия фар, т.к. есть модели у которых он значительно отличается и получается при использовании плагина Александра GTA SA Vehicle Special Abilities Editor и новых моделей, фары у некоторых моделей открываются не полностью или наоборот поворачиваются на лишние градусы. Для VC и GTA III я такую возможность сделал (только там не считывание угла с .ini для каждой модели, а значение угла "зашивается" в саму модель путём названия вспомогательного дамми, т.е. получается надо редактировать саму модель).
 (http://www.youtube.com/watch?v=QWWcvHoUvRk&feature=youtu.be#)

Для SA хотелось бы это сделать без редактирования самой модели. Можно ли это реализовать с помощью плагина?

И ещё, касаемо плагина Александра GTA SA Vehicle Special Abilities Editor - как известно, плагин
Цитировать
позволяет ставить модели авто,обладающие особыми способностями, к примеру фары у ZR350, ковш у Dozer'a ... на лю6ые другие свободные ID с сохранением всех рабочих деталей

так вот, если можно, то просьба показать, как это реализовать на С++ на примере хотя бы возможности цеплять прицепы к моделям, где изначально эта возможность не имелась.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 30, 2016, 12:23:20 am
Если я ничего не путаю, то проверка по ID модели для тягачей производится в функции CAutomobile::GetTowBarPos (функция, которая получает позицию крепления).
Тут есть 2 варианта:
1) Переписать функцию GetTowBarPos.
2) Изменить функцию GetTowBarPos частично, внедрением в ту часть, где идёт проверка модели.
Пример замены функции я уже показывал (SpawnTruck).
Второй вариант сложнее - нужно будет писать код на ассемблере.

Первый вариант, конечно, предпочтительнее. Тем более, функция не такая уж и большая.

Вместо ini я бы использовал такой формат
Код: C++
  1. section
  2. 1,2,3,4
  3. end
По-моему, так намного удобнее.

Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <string>
  4. #include <sstream>
  5. #include <fstream>
  6. #include "game_sa\CModelInfo.h"
  7. #include "game_sa\CAutomobile.h"
  8. #include "game_sa\CCoronas.h"
  9.  
  10. using namespace plugin;
  11.  
  12. std::vector<unsigned int> truckIDs;
  13.  
  14. #define Z_POS_FOR_MODELS_WITHOUT_NODE 1.3f
  15.  
  16. #define g_TOWTRUCK_HOIST_DOWN_LIMIT *(unsigned short *)0x8D313C
  17.  
  18. class VehicleAdvanced {
  19. public:
  20.     static void ReadSettingsFile() {
  21.         std::ifstream stream("vehicle_advanced.dat");
  22.         for (std::string line; getline(stream, line); ) {
  23.             if (line[0] != ';' && line[0] != '#') {
  24.                 if (!line.compare("trucks")) {
  25.                     while (line.compare("end") && getline(stream, line)) {
  26.                         if (line[0] != ';' && line[0] != '#') {
  27.                             std::stringstream ss(line);
  28.                             int i;
  29.                             while (ss >> i) {
  30.                                 truckIDs.push_back(i);
  31.                                 if (ss.peek() == ',')
  32.                                     ss.ignore();
  33.                             }
  34.                         }
  35.                     }
  36.                 }
  37.             }
  38.         }
  39.     }
  40.  
  41.     static bool IsTruckModel(unsigned int modelId) {
  42.         for (unsigned int i : truckIDs) {
  43.             if (i == modelId)
  44.                 return true;
  45.         }
  46.         return false;
  47.     }
  48.  
  49.     static bool __fastcall MyGetTowBarPos(CAutomobile *automobile, int, CVector &outPos, bool ignoreModelType, CVehicle *attachTo) {
  50.         if (automobile->m_wModelIndex == MODEL_TOWTRUCK || automobile->m_wModelIndex == MODEL_TRACTOR) {
  51.             float yOffset = -1.05f;
  52.             if (automobile->m_wModelIndex == MODEL_TRACTOR) {
  53.                 if (attachTo && attachTo->m_dwVehicleSubClass == VEHICLE_TRAILER && attachTo->m_wModelIndex != MODEL_FARMTR1)
  54.                     return false;
  55.                 yOffset = -0.6f;
  56.             }
  57.             else if (attachTo && attachTo->m_dwVehicleSubClass == VEHICLE_TRAILER)
  58.                 return false;
  59.             outPos.x = 0.0f;
  60.             outPos.y = yOffset + CModelInfo::ms_modelInfoPtrs[automobile->m_wModelIndex]->m_pColModel->m_boundBox.m_vSup.y;
  61.             outPos.z = (1.0f - static_cast<float>(automobile->m_wMiscComponentAngle) / static_cast<float>(g_TOWTRUCK_HOIST_DOWN_LIMIT)) * 0.5f + 0.5f - automobile->m_fFrontHeightAboveRoad;
  62.             outPos = *automobile->m_matrix * outPos;
  63.             return true;
  64.         }
  65.         if (IsTruckModel(automobile->m_wModelIndex)
  66.             || automobile->m_wModelIndex == MODEL_UTILITY && attachTo && attachTo->m_wModelIndex == MODEL_UTILTR1
  67.             || (automobile->m_wModelIndex == MODEL_BAGGAGE || automobile->m_wModelIndex == MODEL_TUG || automobile->m_wModelIndex == MODEL_BAGBOXA || automobile->m_wModelIndex == MODEL_BAGBOXB)
  68.             && attachTo
  69.             && (attachTo->m_wModelIndex == MODEL_BAGBOXA
  70.                 || attachTo->m_wModelIndex == MODEL_BAGBOXB
  71.                 || attachTo->m_wModelIndex == MODEL_TUGSTAIR))
  72.         {
  73.             if (automobile->m_aCarNodes[CAR_MISC_A]) {
  74.                 RwMatrix *ltm = RwFrameGetLTM(automobile->m_aCarNodes[CAR_MISC_A]);
  75.                 outPos.x = ltm->pos.x;
  76.                 outPos.y = ltm->pos.y;
  77.                 outPos.z = ltm->pos.z;
  78.             }
  79.             else {
  80.                 outPos.x = 0.0f;
  81.                 outPos.y = CModelInfo::ms_modelInfoPtrs[automobile->m_wModelIndex]->m_pColModel->m_boundBox.m_vSup.y - 0.5f;
  82.                 outPos.z = Z_POS_FOR_MODELS_WITHOUT_NODE - automobile->m_fFrontHeightAboveRoad;
  83.                 outPos = *automobile->m_matrix * outPos;
  84.             }
  85.             return true;
  86.         }
  87.         if (ignoreModelType) {
  88.             outPos.x = 0.0f;
  89.             outPos.y = CModelInfo::ms_modelInfoPtrs[automobile->m_wModelIndex]->m_pColModel->m_boundBox.m_vSup.y - 0.5f;
  90.             outPos.z = 0.5f - automobile->m_fFrontHeightAboveRoad;
  91.             outPos = *automobile->m_matrix * outPos;
  92.             return true;
  93.         }
  94.         return false;
  95.     }
  96.  
  97.     static void Test() {
  98.         for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  99.             CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  100.             if (vehicle) {
  101.                 if (IsTruckModel(vehicle->m_wModelIndex)) {
  102.                     if (vehicle->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE && reinterpret_cast<CAutomobile *>(vehicle)->m_aCarNodes[CAR_MISC_A]) {
  103.                         CVector *posn = reinterpret_cast<CVector *>(&RwFrameGetLTM(reinterpret_cast<CAutomobile *>(vehicle)->m_aCarNodes[CAR_MISC_A])->pos);
  104.                         CCoronas::RegisterCorona(reinterpret_cast<unsigned int>(vehicle) + 100, 0, 0, 255, 0, 255, *posn, 1.0f, 150.0f, CORONATYPE_SHINYSTAR,
  105.                             0, false, false, 0, 0.0f, false, 0.1f, 0, 15.0f, false, false);
  106.                     }
  107.                     else {
  108.                         CCoronas::RegisterCorona(reinterpret_cast<unsigned int>(vehicle) + 100, vehicle, 255, 0, 0, 255, CVector(0.0f,
  109.                             CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]->m_pColModel->m_boundBox.m_vSup.y - 0.5f,
  110.                             1.3f - reinterpret_cast<CAutomobile *>(vehicle)->m_fFrontHeightAboveRoad), 1.0f, 150.0f, CORONATYPE_SHINYSTAR,
  111.                             0, false, false, 0, 0.0f, false, 0.1f, 0, 15.0f, false, false);
  112.                     }
  113.                 }
  114.             }
  115.         }
  116.     }
  117.  
  118.     VehicleAdvanced() {
  119.         patch::RedirectJump(0x6AF250, MyGetTowBarPos);
  120.         Events::gameProcessEvent += Test;
  121.         ReadSettingsFile();
  122.     }
  123. } vehAdv;

vehicle_advanced.dat
Код: C++
  1. trucks
  2. 400,401,402,403,404,405,406,407,408,409
  3. 410
  4. 411
  5. end

(http://i.imgur.com/RiNWFzjm.png) (http://i.imgur.com/RiNWFzj.png)

PS Соединять LANDSTALKER и ARTICT2 не желательно  :P Наверное, лучше ещё добавить настройку офсета под каждую модель.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 30, 2016, 09:11:22 am
 :( Студия ругается на строчки
Код: C++
  1. outPos = *automobile->m_matrix * outPos;

Цитировать
1>VehicleAdvanced.cpp(62): error C2676: бинарный "*": "CMatrixLink" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору
1>VehicleAdvanced.cpp(83): error C2676: бинарный "*": "CMatrixLink" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору
1>VehicleAdvanced.cpp(91): error C2676: бинарный "*": "CMatrixLink" не определяет этот оператор или преобразование к типу приемлемо к встроенному оператору


http://savepic.net/8355422.png (http://savepic.net/8355422.png)

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Август 30, 2016, 05:57:49 pm
Обнови проект.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 30, 2016, 08:01:28 pm
Теперь нормально.
Что сказать? Круто! Спасибо за пример.
С каждым новым примером я всё больше убеждаюсь в том, что надо было мне раньше заняться изучением С++. Ну рано или поздно это должно было произойти, в рамках клео скриптов давно стало "тесно".  :)

Нашёл, кстати, исходник на Delphi того плагина Александра. Вот часть с тягачами:
{TRAILER_HOOKs}
  Reset(F);

  {FIRST'n'LAST Hook}
  CodePtr := VirtualAlloc(0, 1000 , MEM_COMMIT , PAGE_READWRITE) ;
  VirtualProtect(ptr($6AF26C),5,PAGE_READWRITE,OldProtect);
  PByte($6AF26C)^:= $E9;     // jmp
  PInteger($6AF26D)^:= Integer(CodePtr) - $6AF26C - 5;   // Alloced place

  While not EOF(F) do
  begin
    ReadLn(F,StrName);
    if not (strpos(PChar(StrName),'[TRAILER_HOOKs]')=nil) then break;
  end;

  Count:= ReadIntValue('MAIN','TRAILER_HOOKs');

  For i:= 0 to Count-1 do
  begin
    ReadLn(F,S[i]);
    PByte(Integer(CodePtr)+i*6)^:= $66;
    PByte(Integer(CodePtr)+i*6+1)^:= $3D;
    PSmallInt(Integer(CodePtr)+i*6+2)^:= StrToInt(S[i]);
    PByte(Integer(CodePtr)+i*6+4)^:= $74;
    PByte(Integer(CodePtr)+i*6+5)^:= (Count-i-1)*6 + $A;
  end;

  PByte(Integer(CodePtr)+Count*6)^:= $66;  // cmp
  PByte(Integer(CodePtr)+Count*6+1)^:= $3D; // ax
  PByte(Integer(CodePtr)+Count*6+2)^:= $02;   // id
  PByte(Integer(CodePtr)+Count*6+3)^:= $02;   // 2 b
  PByte(Integer(CodePtr)+Count*6+4)^:= $0F;  // jnz
  PByte(Integer(CodePtr)+Count*6+5)^:= $85;  // $6AF284
  PInteger(Integer(CodePtr)+Count*6+6)^:= $6AF272 - (Integer(CodePtr)+Count*6+10);
  PByte(Integer(CodePtr)+Count*6+10)^:= $E9;   // jmp $6AF2CC
  PInteger(Integer(CodePtr)+Count*6+11)^:= $6AF2CC - (Integer(CodePtr)+Count*6+15);

  CloseFile(F);
{TRAILER_HOOKs_END}
Название: Re: Написание плагина. Настройка проекта
Отправлено: mfisto от Август 31, 2016, 12:31:25 am
Есть плагин fastman92 лимит-аджастер. Там тоже есть попытка сделать дополнительные модели. Проект отличный, можно расширять карту, воду, кол-во авто итд. Так вот к чему это я, может вам объединиться с ним касательно части новых фишек для авто. Возможно его дело пойдет быстрее.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 01, 2016, 12:41:19 pm
Цитировать
Есть плагин fastman92 лимит-аджастер. Там тоже есть попытка сделать дополнительные модели. Проект отличный, можно расширять карту, воду, кол-во авто итд. Так вот к чему это я, может вам объединиться с ним касательно части новых фишек для авто. Возможно его дело пойдет быстрее.
С меня в данный момент польза для fastman'а вряд ли будет, я только начал изучать.  ;D

Цитировать
Вместо ini я бы использовал такой формат
Код: C++
  1. section
  2. 1,2,3,4
  3. end
Цитировать
По-моему, так намного удобнее.

Да, разобрал, что к чему. Удобная вещь.
Есть вопросы:
1) Есть ли ограничение по количеству элементов записываемых в truckIDs?
2) Длина строки в .dat ограничена в 256 символа или никакого ограничения нет?
3) Как бы ещё организовать запись/считывание пары значений. Например, одного типа - ID тягача и ID прицепа? А разных типов? Например, ID дополнительной модели типа zr350 и угол, на который должны открываться у неё фары?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 01, 2016, 09:31:39 pm
Нет, ограничений нету.

Я бы сделал так, по аналогии с vehicles.ide:
Код: C++
  1. trucks
  2. 400, 500, 0.0
  3. 401, 505, 1.0
  4. end
Или вообще всё в отдельный файл и убрать метки trucks и end.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 02, 2016, 02:11:22 pm
Цитировать
Я бы сделал так, по аналогии с vehicles.ide:
Код: C++
  1. trucks
  2. 400, 500, 0.0
  3. 401, 505, 1.0
  4. end
Цитировать
Или вообще всё в отдельный файл и убрать метки trucks и end.
Надо ещё один объект std::stringstream и std::vector для float значений? А как сопоставлять их значения? Или как-то по другому? Вот, допустим, первой колонкой идёт набор ID каких-то моделей транспорта, второй колонкой идёт какое-то значение float (допустим, угол поворота фар). Как их правильно считать и сопоставить угол и ID?
Код: C++
  1. trucks
  2. 500, 1.5
  3. 501, 1.71
  4. 502, 1.35
  5. end



Решил попробовать сделать неоновую подсветку для автомобилей в плагине. Посмотрел скрипт Дениса для SA, что-то там сложновато. Глянул твой скрипт для GTA III - тут всё понятно, можно взять за основу. Посмотрел в базе опкод 016F, там вызывается  CShadows__registerShadowByType, глянул в sdk - есть такое дело в CShadows.
Код: C++
  1. static void StoreShadowToBeRendered(unsigned char type, RwTexture* texture, CVector* posn, float x1, float y1, float x2, float y2, short intensity, unsigned char red, unsigned char green, unsigned char blue, float zDistance, bool bDrawOnWater, float scale, CRealTimeShadow* shadowData, bool bDrawOnBuildings);


Можно пожалуйста пример, как вызвать эту функцию. С текстурами примеров не было, как с ними работать? Ещё например, установка винила на авто. 

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 02, 2016, 05:14:35 pm
Обьяви структуру, которая будет содержать все нужные параметры, и создай вектор для хранения этих структур.
https://ru.wikipedia.org/wiki/Vector_(C%2B%2B) (https://ru.wikipedia.org/wiki/Vector_(C%2B%2B))
Ну и для чтения можно заюзать sscanf.
Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <string>
  4. #include <fstream>
  5.  
  6. using namespace plugin;
  7. using namespace std;
  8.  
  9. class SettingsTest {
  10. public:
  11.     struct MyData {
  12.         unsigned int baseModelId;
  13.         unsigned int linkedModelId;
  14.         float value;
  15.     };
  16.  
  17.     static vector<MyData> entries;
  18.  
  19.     static void ReadSettingsFile() {
  20.         std::ifstream stream("vehicle_advanced.dat");
  21.         for (std::string line; getline(stream, line); ) {
  22.             if (line[0] != ';' && line[0] != '#') {
  23.                 if (!line.compare("trucks")) {
  24.                     while (getline(stream, line) && line.compare("end")) {
  25.                         if (line[0] != ';' && line[0] != '#') {
  26.                             MyData entry;
  27.                             if (sscanf(line.c_str(), "%d, %d, %f", &entry.baseModelId, &entry.linkedModelId, &entry.value) == 3)
  28.                                 entries.push_back(entry);
  29.                             else
  30.                                 Error("Failed to scan line: %s", line.c_str());
  31.                         }
  32.                     }
  33.                 }
  34.             }
  35.         }
  36.     }
  37.  
  38.     MyData *GetDataInfoForModel(unsigned int BaseModelId) {
  39.         for (unsigned int i = 0; i < entries.size(); i++) {
  40.             if (entries[i].baseModelId == BaseModelId)
  41.                 return &entries[i];
  42.         }
  43.         return nullptr;
  44.     }
  45.  
  46.     SettingsTest() {
  47.         ReadSettingsFile();
  48.         for (unsigned int i = 0; i < entries.size(); i++)
  49.             Error("Entry %d: %d %d %.2f", i + 1, entries[i].baseModelId, entries[i].linkedModelId, entries[i].value);
  50.  
  51.         MyData *entryModel400 = GetDataInfoForModel(400);
  52.         if (entryModel400) {
  53.             Error("Test for model 400: %d %d %.2f", entryModel400->baseModelId, entryModel400->linkedModelId, entryModel400->value);
  54.         }
  55.     }
  56. } test;

Код: C++
  1. #include "plugin.h"
  2. #include "game_sa\CClock.h"
  3. #include "game_sa\CShadows.h"
  4. #include "game_sa\common.h"
  5. #include "KeyCheck.h"
  6.  
  7. using namespace plugin;
  8. using namespace std;
  9.  
  10. RwTexture *&pExpTex = *(RwTexture **)0xC403F4;
  11.  
  12. class NeonLights {
  13. public:
  14.     enum eNeonColor {
  15.         NEON_YELLOW, NEON_GREEN, NEON_RED, NEON_BLUE, NEON_PURPLE
  16.     };
  17.  
  18.     class Neon {
  19.     public:
  20.         unsigned char color;
  21.         bool activated;
  22.         bool processed;
  23.  
  24.         Neon(CVehicle *) {
  25.             activated = processed = false;
  26.         }
  27.  
  28.         void Enable(eNeonColor Color) {
  29.             color = Color;
  30.             activated = true;
  31.         }
  32.  
  33.         void Disable() {
  34.             activated = false;
  35.         }
  36.     };
  37.  
  38.     static VehicleExtendedData<Neon> VehNeon;
  39.  
  40.     static bool CanEnableNeonOnThisVehicle(CVehicle *vehicle) {
  41.         return CClock::GetIsTimeInRange(23, 5) && vehicle->m_pDriver && (vehicle->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE ||
  42.             vehicle->m_dwVehicleSubClass == VEHICLE_MTRUCK || vehicle->m_dwVehicleSubClass == VEHICLE_QUAD);
  43.     }
  44.  
  45.     static void ProcessNpcVehicle(CVehicle *vehicle) {
  46.         if (CanEnableNeonOnThisVehicle(vehicle) && !VehNeon.Get(vehicle).processed) {
  47.             VehNeon.Get(vehicle).processed = true;
  48.             if (rand() % 11 == 10) {
  49.                 VehNeon.Get(vehicle).activated = true;
  50.                 VehNeon.Get(vehicle).color = rand() % 5;
  51.             }
  52.         }
  53.     }
  54.  
  55.     static void ProcessVehicles() {
  56.         KeyCheck::Update();
  57.         CVehicle *playaVeh = FindPlayerVehicle(0, false);
  58.         if (playaVeh) {
  59.             if (KeyCheck::Check(VK_SHIFT)) {
  60.                 if (KeyCheck::CheckJustDown('1'))
  61.                     VehNeon.Get(playaVeh).Enable(NEON_YELLOW);
  62.                 else if (KeyCheck::CheckJustDown('2'))
  63.                     VehNeon.Get(playaVeh).Enable(NEON_GREEN);
  64.                 else if (KeyCheck::CheckJustDown('3'))
  65.                     VehNeon.Get(playaVeh).Enable(NEON_RED);
  66.                 else if (KeyCheck::CheckJustDown('4'))
  67.                     VehNeon.Get(playaVeh).Enable(NEON_BLUE);
  68.                 else if (KeyCheck::CheckJustDown('5'))
  69.                     VehNeon.Get(playaVeh).Enable(NEON_PURPLE);
  70.                 else if (KeyCheck::CheckJustDown('0'))
  71.                     VehNeon.Get(playaVeh).Disable();
  72.             }
  73.         }
  74.         for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  75.             CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  76.             if (vehicle && vehicle != playaVeh)
  77.                 ProcessNpcVehicle(vehicle);
  78.         }
  79.     }
  80.  
  81.     static void RenderNeonForVehicle(CVehicle *vehicle) {
  82.         if (VehNeon.Get(vehicle).activated) {
  83.             unsigned char r, g, b;
  84.             switch (VehNeon.Get(vehicle).color) {
  85.             case NEON_YELLOW:
  86.                 r = 255; g = 200; b = 0;
  87.                 break;
  88.             case NEON_GREEN:
  89.                 r = 0; g = 255; b = 0;
  90.                 break;
  91.             case NEON_RED:
  92.                 r = 255; g = 0; b = 0;
  93.                 break;
  94.             case NEON_BLUE:
  95.                 r = 0; g = 0; b = 255;
  96.                 break;
  97.             case NEON_PURPLE:
  98.                 r = 255; g = 0; b = 255;
  99.                 break;
  100.             }
  101.             CShadows::StoreShadowToBeRendered(2, pExpTex, &vehicle->GetPosition(), 2.5f, 0.0f, 0.0f, -2.5f, 255, r, g, b, 2.0f, false, 1.0f, 0, true);
  102.         }
  103.     }
  104.  
  105.     NeonLights() {
  106.         Events::gameProcessEvent += ProcessVehicles;
  107.         Events::vehicleRenderEvent += RenderNeonForVehicle;
  108.     }
  109. } neon;
  110.  
  111. VehicleExtendedData<NeonLights::Neon> NeonLights::VehNeon;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 03, 2016, 10:48:35 am
Спасибо за примеры.

По первому примеру студия ругается на:
Код: C++
  1. 1>------ Перестроение всех файлов начато: проект: testVector, Конфигурация: Release Win32 ------
  2. 1>  Source.cpp
  3. 1>Source.obj : error LNK2001: неразрешенный внешний символ ""public: static class std::vector<struct SettingsTest::MyData,class std::allocator<struct SettingsTest::MyData> > SettingsTest::entries" (?entries@SettingsTest@@2V?$vector@UMyData@SettingsTest@@V?$allocator@UMyData@SettingsTest@@@std@@@std@@A)"
  4. 1>D:\Games\GTA San Andreas\scripts\testVector.asi : fatal error LNK1120: неразрешенных внешних элементов: 1
  5. ========== Перестроение всех проектов: успешно: 0, с ошибками: 1, пропущено: 0 ==========

По второму примеру всё отлично, за исключением того, что проекция на поверхности стоит под одним и тем же углом, т.е. не поворачивается вместе с авто. Это заметно, если сделать проекцию овальной, а не круглой или заменить текстуру на квадратную. Можно это, как-то исправить? У Дениса в скрипте проекция поворачивается вместе с авто.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 03, 2016, 01:06:38 pm
В первом примере надо определить переменную entries.
Код: C++
  1. vector<SettingsTest::MyData> SettingsTest::entries;
По второму - смотри этот пост.
http://modsforgta.ucoz.ru/forum/9-22-3523-16-1333570000 (http://modsforgta.ucoz.ru/forum/9-22-3523-16-1333570000)
Код: C++
  1. CVector center = vehicle->TransformFromObjectSpace(CVector(0.0f, -3.0f, 0.0f));
  2. CVector up = vehicle->TransformFromObjectSpace(CVector(0.0f, -2.0f, 0.0f)) - center;
  3. CVector right = vehicle->TransformFromObjectSpace(CVector(2.0f, -3.0f, 0.0f)) - center;
  4. CShadows::StoreShadowToBeRendered(2, pExpTex, &center, up.x, up.y, right.x, right.y, 255, r, g, b, 2.0f, false, 1.0f, 0, true);
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 03, 2016, 07:00:36 pm
Разобрался, спасибо! Есть только один момент:
Код: C++
  1. RwTexture *&pExpTex = *(RwTexture **)0xC403F4;
Такие записи (*& и **) ранее не встречались. Просьба разъяснить. Где про это почитать?

Немного изменил и дополнил код:
1) Ограничил для транспорта трафика по m_nClass (оставил для poorfamily, richfamily и executive).
2) Ограничил для транспорта игрока по m_dwVehicleSubClass.
3) Изменил случайный выбор для транспорта в трафике.
4) Взял другую (прямоугольную) текстуру.
5) Размер проекции "привязал" на габариты модели.
6) Так как текстура с ровными краями, сделал мигание проекции, чтобы это сильно "не бросалось в глаза".

Код: C++
  1. #include "plugin.h"
  2. #include "game_sa\CClock.h"
  3. #include "game_sa\CShadows.h"
  4. #include "game_sa\common.h"
  5. #include "KeyCheck.h"
  6. #include "game_sa\CModelInfo.h"
  7. #include "game_sa\CTimer.h"
  8.  
  9. #define TURN_ON_OFF_DELAY 500
  10.  
  11. using namespace plugin;
  12. using namespace std;
  13.  
  14. RwTexture *&pWhiteTex = *(RwTexture **)0xB4E3EC;
  15.  
  16. class NeonLights {
  17. public:
  18.     enum eNeonColor {
  19.         NEON_YELLOW, NEON_GREEN, NEON_RED, NEON_BLUE, NEON_PURPLE
  20.     };
  21.  
  22.     class Neon {
  23.     public:
  24.         unsigned char color;
  25.         bool activated;
  26.         bool processed;
  27.  
  28.         Neon(CVehicle *) {
  29.             activated = processed = false;
  30.         }
  31.  
  32.         void Enable(eNeonColor Color) {
  33.             color = Color;
  34.             activated = true;
  35.         }
  36.  
  37.         void Disable() {
  38.             activated = false;
  39.         }
  40.     };
  41.  
  42.     static VehicleExtendedData<Neon> VehNeon;
  43.  
  44.     static bool CanEnableNeonOnThisVehicle(CVehicle *vehicle) {
  45.         CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]);
  46.         return CClock::GetIsTimeInRange(22, 5) && vehicle->m_pDriver && (vehModel->m_nClass == 1 || vehModel->m_nClass == 2 || vehModel->m_nClass == 3) && (vehicle->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE ||
  47.                         vehicle->m_dwVehicleSubClass == VEHICLE_MTRUCK || vehicle->m_dwVehicleSubClass == VEHICLE_QUAD);
  48.     }
  49.  
  50.     static void ProcessNpcVehicle(CVehicle *vehicle) {
  51.         if (CanEnableNeonOnThisVehicle(vehicle) && !VehNeon.Get(vehicle).processed) {
  52.             VehNeon.Get(vehicle).processed = true;
  53.             if (rand() % 3 == 1) {
  54.                 VehNeon.Get(vehicle).activated = true;
  55.                 VehNeon.Get(vehicle).color = rand() % 5;
  56.             }
  57.         }
  58.     }
  59.  
  60.     static void ProcessVehicles() {
  61.         KeyCheck::Update();
  62.         CVehicle *playaVeh = FindPlayerVehicle(0, false);
  63.         if (playaVeh && (playaVeh->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE ||
  64.                         playaVeh->m_dwVehicleSubClass == VEHICLE_MTRUCK || playaVeh->m_dwVehicleSubClass == VEHICLE_QUAD)) {
  65.             if (KeyCheck::Check(VK_SHIFT)) {
  66.                 if (KeyCheck::CheckJustDown('1'))
  67.                     VehNeon.Get(playaVeh).Enable(NEON_YELLOW);
  68.                 else if (KeyCheck::CheckJustDown('2'))
  69.                     VehNeon.Get(playaVeh).Enable(NEON_GREEN);
  70.                 else if (KeyCheck::CheckJustDown('3'))
  71.                     VehNeon.Get(playaVeh).Enable(NEON_RED);
  72.                 else if (KeyCheck::CheckJustDown('4'))
  73.                     VehNeon.Get(playaVeh).Enable(NEON_BLUE);
  74.                 else if (KeyCheck::CheckJustDown('5'))
  75.                     VehNeon.Get(playaVeh).Enable(NEON_PURPLE);
  76.                 else if (KeyCheck::CheckJustDown('0'))
  77.                     VehNeon.Get(playaVeh).Disable();
  78.             }
  79.         }
  80.         for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  81.             CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  82.             if (vehicle && vehicle != playaVeh)
  83.                 ProcessNpcVehicle(vehicle);
  84.         }
  85.     }
  86.  
  87.     static void RenderNeonForVehicle(CVehicle *vehicle) {
  88.         if (VehNeon.Get(vehicle).activated) {
  89.             unsigned char r, g, b;
  90.             switch (VehNeon.Get(vehicle).color) {
  91.             case NEON_YELLOW:
  92.                 r = 255; g = 200; b = 0;
  93.                 break;
  94.             case NEON_GREEN:
  95.                 r = 0; g = 255; b = 0;
  96.                 break;
  97.             case NEON_RED:
  98.                 r = 255; g = 0; b = 0;
  99.                 break;
  100.             case NEON_BLUE:
  101.                 r = 0; g = 0; b = 255;
  102.                 break;
  103.             case NEON_PURPLE:
  104.                 r = 255; g = 0; b = 255;
  105.                 break;
  106.             }
  107.             if (CTimer::m_snTimeInMilliseconds % (TURN_ON_OFF_DELAY + 250) < TURN_ON_OFF_DELAY) {
  108.                 CVector Pos = CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]->m_pColModel->m_boundBox.m_vSup;
  109.                 CVector center = vehicle->TransformFromObjectSpace(CVector(0.0f, 0.0f, 0.0f));
  110.                 CVector up = vehicle->TransformFromObjectSpace(CVector(0.0f, -Pos.y - 0.5f, 0.0f)) - center;
  111.                 CVector right = vehicle->TransformFromObjectSpace(CVector(Pos.x + 0.2f, 0.0f, 0.0f)) - center;
  112.                 CShadows::StoreShadowToBeRendered(2, pWhiteTex, &center, up.x, up.y, right.x, right.y, 255, r, g, b, 2.0f, false, 1.0f, 0, true);
  113.             }
  114.         }
  115.     }
  116.  
  117.     NeonLights() {
  118.         Events::gameProcessEvent += ProcessVehicles;
  119.         Events::vehicleRenderEvent += RenderNeonForVehicle;
  120.     }
  121. } neon;
  122.  
  123. VehicleExtendedData<NeonLights::Neon> NeonLights::VehNeon;
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 03, 2016, 10:07:05 pm
Такая конструкция используется для определения игровых переменных.
Читать про ссылки, указатели, разыменование.

Допустим, мы знаем, что по адресу 0x863984 находится значение гравитации (float, дефолтное значение - 0.008).
Как работать с этим адресом (записать, прочитать)? (функции класса patch не трогаем)
Например, вот так
Код: C++
  1. // Чтение
  2. float gravity = *(float *)0x863984; // C-шный стиль; представляем 0x863984 как указатель на float и разыменовываем его
  3. float gravity = *reinterpret_cast<float *>0x863984; // C++ -шный type casting
  4. // Запись
  5. *(float *)0x863984 = 1.0f;
  6. *reinterpret_cast<float *>0x863984 = 1.0f;
Отлично. Но выглядит не очень. Что делать?
Можно сделать так
Код: C++
  1. #define GRAVITY *(float *)0x863984
  2.  
  3. /* ... */
  4.  
  5. GRAVITY = 1.0f;
А ещё лучше - создать переменную-указатель, и читать/записывать значение через неё:
Код: C++
  1. float *pGravity = (float *)0x863984;
  2.  
  3. /* ... */
  4.  
  5. *pGravity = 1.0f; // предварительно разыменовываем
  6. float gravity = *pGravity; // предварительно разыменовываем
Всё вроде хорошо... Но можно сделать ещё лучше, если вспомнить о ссылках.
Код: C++
  1. float &gGravity = *(float *)0x863984; // создаём ссылку на значение по адресу 0x863984
  2.  
  3. /* ... */
  4.  
  5. gGravity = 1.0f;
Ситуация с RwTexture* - аналогична.
По адресу 0xB4E3EC находится указатель на обьект текстуры графического движка игры (RwTexture).
Код: C++
  1. RwTexture *&pWhiteTex = *(RwTexture **)0xB4E3EC; // создаём ссылку на RwTexture* (указатель на обьект текстуры) по адресу 0xB4E3EC
  2.  
  3. /* ... */
  4.  
  5. plugin::Error("Texture \"%s\" size: %dx%d", pWhiteTex->name, pWhiteTex->raster->width, pWhiteTex->raster->height);
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 04, 2016, 12:53:26 pm
Спасибо за разъяснения.

По sdk для VC пока никакого продвижения нет? А по SA много ещё осталось не разобранного?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 04, 2016, 03:18:26 pm
По VC нету.
По SA - да, много.
В последнем коммите я обновил класс CShadows, добавил все функции класса и перечисления.
Ну и переменные тоже.

Добавил все функции класса CGeneral, теперь там есть такое:
Код: C++
  1. static unsigned int GetRandomNumberInRange(int min, int max); // returns random int in range [min;max)
  2. static float GetRandomNumberInRange(float min, float max); // returns random float in range [min;max)
Эти функции используются в опкодах 0208 и 0209.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 04, 2016, 04:34:14 pm
Добавил все функции класса CGeneral, теперь там есть такое:
Эти функции используются в опкодах 0208 и 0209.
Это хорошо. В скриптах я частенько пользовался этими опкодами.


И ещё сразу по прицепам есть вопрос - можно ли в трафике в процессе создания транспорта проверить, если модель определённого ID (тягач), то цеплять к нему прицеп. Цеплять не на весь транспорт с таким ID, а выборочно, ну скажем через определённое время? Цеплять разные прицепы?
Можно, надо разбирать CCarCtrl::GenerateOneRandomCar.
Как будет свободное время разбери пожалуйста это дело. Вопрос с прицепами интересен многим пользователям. Было написано несколько скриптов на эту тему (в том числе и у меня есть такой скрипт), но это всё не то.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 10, 2016, 09:19:14 am
Тем временем в plugin-sdk появились все классы из иерархии CVehicle (CAutomobile, CMonsterTruck, CQuadBike, CTrain, CHeli, CPlane, CBike, CBmx, CTrailer, CBoat).
Обновился пример CreateCar, теперь вместо CCheat::VehicleCheat там используется своя функция спавна.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 10, 2016, 10:43:02 am
Обновился пример CreateCar, теперь вместо CCheat::VehicleCheat там используется своя функция спавна.
Просьба пояснить эти строчки:
Код: C++
  1. reinterpret_cast<CBike *>(vehicle)->m_nDamageFlags |= 0x10;
  2. reinterpret_cast<CBmx *>(vehicle)->m_nDamageFlags |= 0x10;

и эти:
Код: C++
  1. reinterpret_cast<CBike *>(vehicle)->PlaceOnRoadProperly();
  2. reinterpret_cast<CAutomobile *>(vehicle)->PlaceOnRoadProperly();

Пробую работу с выводом текстур на экран. Почитал твой урок http://ru-script.3dn.ru/publ/programirovanie/sozdanie_dll_bibliotek/sa_124_c_plugin_sdk_risuem_chast_1/18-1-0-206 (http://ru-script.3dn.ru/publ/programirovanie/sozdanie_dll_bibliotek/sa_124_c_plugin_sdk_risuem_chast_1/18-1-0-206)

Перенёс пример на sdk:
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CSprite2d.h"
  3. #include "game_sa\CTxdStore.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class MyPlugin {
  8. public:
  9.     static CSprite2d mySprite;
  10.  
  11.     MyPlugin() {
  12.         Events::initRwEvent += [] {
  13.             // Добавляем новый слот для нашего txd
  14.             int txd = CTxdStore::AddTxdSlot("mytxd");
  15.             // Загружаем наш txd в выделенный слот
  16.             CTxdStore::LoadTxd(txd, "MODELS\\MYTXD.TXD");
  17.             // Увеличиваем счётчик использований для созданного txd
  18.             CTxdStore::AddRef(txd);
  19.             // Сохраняем текущий txd
  20.             CTxdStore::PushCurrentTxd();
  21.             // Устанавливаем наш txd как текущий
  22.             CTxdStore::SetCurrentTxd(txd);
  23.             // Назначаем текстру нашему спрайту (имя текстуры, имя альфа-маски для текстуры)
  24.             mySprite.SetTexture("skipicon", "skipicona");
  25.             // Восстанавливаем сохранённый txd
  26.             CTxdStore::PopCurrentTxd();
  27.         };
  28.  
  29.         Events::drawingEvent += [] {
  30.             // Рисуем наш спрайт (указываем параметры - позиция, ширина, высота, цвет)
  31.             mySprite.Draw(20.0, 20.0, 150.0, 150.0, CRGBA(255, 255, 255, 255));
  32.         };
  33.     }
  34.  
  35.     ~MyPlugin() {
  36.         Events::shutdownRwEvent += [] {
  37.             // Удаляем наш спрайт
  38.             mySprite.Delete();
  39.             // Удаляем наш txd
  40.             CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("mytxd"));
  41.         };
  42.     }
  43. } myPlugin;
  44.  
  45. CSprite2d MyPlugin::mySprite;

Верно ли?

Дальше задумался над кодом для спидометра, но не нашёл функции для вращения текстуры стрелки.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 10, 2016, 01:46:27 pm
Просьба пояснить эти строчки:
Код: C++
  1. reinterpret_cast<CBike *>(vehicle)->m_nDamageFlags |= 0x10;
  2. reinterpret_cast<CBmx *>(vehicle)->m_nDamageFlags |= 0x10;

Для мотоциклов и велосипедов надо установить этот флаг после создания. Что это за флаг - не знаю (0x10 = 5ый бит).
и эти:
Код: C++
  1. reinterpret_cast<CBike *>(vehicle)->PlaceOnRoadProperly();
  2. reinterpret_cast<CAutomobile *>(vehicle)->PlaceOnRoadProperly();

Название функции PlaceOnRoadProperly говорит само за себя - "ставит" транспорт на землю.
Верно ли?

Нет. Добавлять функции в эвенты надо в конструкторе. Конструктор (глобального обьекта) выполняется, когда ASI прицепляется к процессу игры.
Деструктор (глобального обьекта) выполняется, когда ASI открепляется от процесса игры.
Дальше задумался над кодом для спидометра, но не нашёл функции для вращения текстуры стрелки.

Действительно, в оригинальных классах нету такой функции (для отрисовки текстуры с наклоном). Надо самому писать.
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CSprite2d.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class MyPlugin {
  7. public:
  8.     static RwTexture *pMyTexture;
  9.     static float angle;
  10.  
  11.     // Повернуть Num вершин в массиве Verts на угол Angle вокруг (CX;CY)
  12.     static void RotateVertices(RwIm2DVertex *Verts, unsigned int Num, float CX, float CY, float Angle) {
  13.         float radAngle = fmod(Angle, 360.0f);
  14.         if (radAngle < 0.0f)
  15.             radAngle += 360.0;
  16.         radAngle = (360.0f - radAngle) / 57.2957795f;
  17.         float fCos = cosf(radAngle);
  18.         float fSin = sinf(radAngle);
  19.         for (unsigned int i = 0; i < Num; i++) {
  20.             float xold = Verts[i].x;
  21.             float yold = Verts[i].y;
  22.             Verts[i].x = CX + (xold - CX) * fCos + (yold - CY) * fSin;
  23.             Verts[i].y = CY - (xold - CX) * fSin + (yold - CY) * fCos;
  24.         }
  25.     }
  26.  
  27.     static void DrawRotatedSprite(RwTexture *texture, float x, float y, float w, float h, float angle) {
  28.         CSprite2d::SetVertices(CRect(x - w / 2.0f, y - h / 2.0f, x + w / 2.0f, y + h / 2.0f),
  29.             CRGBA(255, 255, 255, 255), CRGBA(255, 255, 255, 255), CRGBA(255, 255, 255, 255), CRGBA(255, 255, 255, 255));
  30.         RotateVertices(CSprite2d::maVertices, 4, x, y, angle);
  31.         RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATETEXTURERASTER, texture->raster);
  32.         RwEngineInstance->dOpenDevice.fpIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::maVertices, 4);
  33.     }
  34.  
  35.     MyPlugin() {
  36.         Events::initRwEvent += [] {
  37.             pMyTexture = RwD3D9DDSTextureRead("models\\image", 0); // загружает image.dds из папки models
  38.         };
  39.  
  40.         Events::drawingEvent += [] {
  41.             angle += 1.0f;
  42.             if(angle > 360.0f)
  43.                 angle = 0.0f;
  44.             DrawRotatedSprite(pMyTexture, 200.0f, 200.0f, 200.0f, 300.0f, angle);
  45.         };
  46.  
  47.         Events::shutdownRwEvent += [] {
  48.             RwTextureDestroy(pMyTexture);
  49.         };
  50.  
  51.         angle = 0.0f;
  52.     }
  53. } myPlugin;
  54.  
  55. RwTexture *MyPlugin::pMyTexture;
  56. float MyPlugin::angle;

Отрисовать стрелку можно ещё и как фигуру - треугольник.
Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\CSprite2d.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class MyPlugin {
  7. public:
  8.     static float angle;
  9.  
  10.     // Повернуть Num вершин в массиве Verts на угол Angle вокруг (CX;CY)
  11.     static void RotateVertices(RwIm2DVertex *Verts, unsigned int Num, float CX, float CY, float Angle) {
  12.         float radAngle = fmod(Angle, 360.0f);
  13.         if (radAngle < 0.0f)
  14.             radAngle += 360.0;
  15.         radAngle = (360.0f - radAngle) / 57.2957795f;
  16.         float fCos = cosf(radAngle);
  17.         float fSin = sinf(radAngle);
  18.         for (unsigned int i = 0; i < Num; i++) {
  19.             float xold = Verts[i].x;
  20.             float yold = Verts[i].y;
  21.             Verts[i].x = CX + (xold - CX) * fCos + (yold - CY) * fSin;
  22.             Verts[i].y = CY - (xold - CX) * fSin + (yold - CY) * fCos;
  23.         }
  24.     }
  25.  
  26.     // cx, cy - центр вращения треугольника, x1,y1...x3,y3 - точки треугольника
  27.     static void DrawRotatedTriangle(float cx, float cy, float x1, float y1, float x2, float y2, float x3, float y3, CRGBA &color, float angle) {
  28.         for (unsigned int i = 0; i < 3; i++) {
  29.             CSprite2d::maVertices[i].rhw = 1.0f;
  30.             CSprite2d::maVertices[i].u = CSprite2d::maVertices[i].v = 0.0f;
  31.             CSprite2d::maVertices[i].z = 0.0f;
  32.             CSprite2d::maVertices[i].emissiveColor = RWRGBALONG(color.red, color.green, color.blue, color.alpha);
  33.         }
  34.         CSprite2d::maVertices[0].x = x1;
  35.         CSprite2d::maVertices[0].y = y1;
  36.         CSprite2d::maVertices[1].x = x2;
  37.         CSprite2d::maVertices[1].y = y2;
  38.         CSprite2d::maVertices[2].x = x3;
  39.         CSprite2d::maVertices[2].y = y3;
  40.         RotateVertices(CSprite2d::maVertices, 3, cx, cy, angle);
  41.         RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
  42.         RwEngineInstance->dOpenDevice.fpIm2DRenderPrimitive(rwPRIMTYPETRILIST, CSprite2d::maVertices, 3);
  43.     }
  44.  
  45.     MyPlugin() {
  46.         Events::drawingEvent += [] {
  47.             angle += 1.0f;
  48.             if(angle > 360.0f)
  49.                 angle = 0.0f;
  50.             DrawRotatedTriangle(300.0f, 300.0f, // центр
  51.                                 300.0f - 10.0f, 300.0f + 10.0f, // точка A
  52.                                 300.0f, 300.0f - 250.0f, // точка B
  53.                                 300.0f + 10.0f, 300.0f + 10.0f, // точка С
  54.                                 CRGBA(255, 0, 0, 255), angle);
  55.             CSprite2d::DrawRect(CRect(300.0f - 2.0f, 300.0f - 2.0f, 300.0f + 2.0f, 300.0f + 2.0f), CRGBA(0, 0, 0, 255));
  56.         };
  57.  
  58.         angle = 0.0f;
  59.     }
  60. } myPlugin;
  61.  
  62. float MyPlugin::angle;

Рисование в RenderWare сводится к следующему:
1) Заполнить данные о вершинах (структуры RwIm2DVertex (или RwD3D9Vertex))
Код: C++
  1. struct RwD3D9Vertex
  2. {
  3.     RwReal      x;              /**< Screen X */
  4.     RwReal      y;              /**< Screen Y */
  5.     RwReal      z;              /**< Screen Z */
  6.     RwReal      rhw;            /**< Reciprocal of homogeneous W */
  7.  
  8.     RwUInt32    emissiveColor;  /**< Vertex color */
  9.  
  10.     RwReal      u;              /**< Texture coordinate U */
  11.     RwReal      v;              /**< Texture coordinate V */
  12. };
2) Настроить параметры рендеринга
Например, текстура устанавливается так:
Код: C++
  1. RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATETEXTURERASTER, texture->raster);
Если же нужно отрендерить фигуру без текстуры, устанавливаем этот параметр в 0:
Код: C++
  1. RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATETEXTURERASTER, 0);
Также можно настроить и другие параметры, например блендинг (http://netlib.narod.ru/library/book0032/ch07_01.htm) ("смешивание"), фильтрацию (http://netlib.narod.ru/library/book0032/ch06_03.htm), адресацию (http://netlib.narod.ru/library/book0032/ch06_05.htm), затенение (http://netlib.narod.ru/library/book0032/ch04_03.htm).
3) Отрендерить фигуру (примитив)
Код: C++
  1. RwEngineInstance->dOpenDevice.fpIm2DRenderPrimitive(rwPRIMTYPETRILIST, CSprite2d::maVertices, 3);
где rwPRIMTYPETRILIST - тип примитива (список треугольников - у нас это 1 треугольник)
CSprite2d::maVertices - наш буфер вершин
3 - кол-во вершин в буфере

CSprite2d::maVertices - это стандартный буфер вершин. Вмещает максимум 8 вершин.
Функции CSprite2d::SetVertices предоставляют возможность быстро заполнить этот буфер, правда, предназначены они, в основном, для заполнения данных о прямоугольниках. Поэтому для треугольника нам нужно вручную заполнять этот буфер.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 10, 2016, 05:31:12 pm
Код: C++
  1. pMyTexture = RwD3D9DDSTextureRead("models\\image", 0); // загружает image.dds из папки models
Как я понял, загружаются текстуры только формата .dds?
А если надо взять какую-либо текстуру из определённого .txd файла, какой код для отрисовки текстуры с наклоном будет в этом случае?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 10, 2016, 07:11:50 pm
Всё так же.
Из спрайта ты можешь получить доступ к текстуре.
Код: C++
  1. mySprite.m_pTexture
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Сентябрь 10, 2016, 08:23:00 pm
Цитировать
Действительно, в оригинальных классах нету такой функции (для отрисовки текстуры с наклоном). Надо самому писать.
Стоп, а как в опкоде это реализовали? Там и скейл, и поворот текстуры на экране. Помню, что работает(когда-то давнооо скриптил для SA)..
074B: draw_sprite_with_rotation 20 coords 428@ 429@ scale 430@ 431@ angle $TEMPVAR_ANGLE rgba 220 220 220 404@
Или вы про Вайс говорите?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 10, 2016, 08:56:43 pm
Цитировать
Действительно, в оригинальных классах нету такой функции (для отрисовки текстуры с наклоном). Надо самому писать.
Стоп, а как в опкоде это реализовали? Там и скейл, и поворот текстуры на экране. Помню, что работает(когда-то давнооо скриптил для SA)..
074B: draw_sprite_with_rotation 20 coords 428@ 429@ scale 430@ 431@ angle $TEMPVAR_ANGLE rgba 220 220 220 404@
Или вы про Вайс говорите?
Понятно, что отрисовать текстуру с поворотом в игре можно, что в Вайсе, что в СА.
Я имел ввиду, что отдельной функции для этого нету.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 11, 2016, 11:31:45 am
Всё так же.
Из спрайта ты можешь получить доступ к текстуре.
Код: C++
  1. mySprite.m_pTexture
Спасибо. А в этом случае удалять эту текстуру надо? Т.е. если у меня в Events::initRwEvent
Код: C++
  1. Events::initRwEvent += [] {
  2.     int txd = CTxdStore::AddTxdSlot("mytxd");
  3.     CTxdStore::LoadTxd(txd, "MODELS\\SPEED.txd");
  4.     CTxdStore::AddRef(txd);
  5.     CTxdStore::PushCurrentTxd();
  6.     CTxdStore::SetCurrentTxd(txd);
  7.     mySpriteRing.SetTexture("tablon", "tablona");
  8.     mySpriteArrow.SetTexture("arrow", "arrowa");
  9.     CTxdStore::PopCurrentTxd();
  10.     pMyTextureArrow = mySpriteArrow.m_pTexture;
  11.     pMyTextureRing = mySpriteRing.m_pTexture;
  12. };
то в Events::shutdownRwEvent
Код: C++
  1. Events::shutdownRwEvent += [] {
  2.     RwTextureDestroy(pMyTextureRing);
  3.     RwTextureDestroy(pMyTextureArrow);
  4.     mySpriteRing.Delete();
  5.     mySpriteArrow.Delete();
  6.     CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("mytxd"));
  7. };
или строчки
Код: C++
  1. RwTextureDestroy(pMyTextureRing);
  2. RwTextureDestroy(pMyTextureArrow);
лишние?

И ещё вопрос: как сделать, чтобы текстуры рисовались в нужных координатах независимо от разрешения экрана? Тот же вопрос и касательно вывода текста.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 11, 2016, 09:02:23 pm
Нет, текстуру удалять не надо.
Она удаляется вызовом CSprite2d::Delete.
Код: C++
  1. void CSprite2d::Delete() { // @0x727240
  2.     if (m_pTexture) {
  3.         RwTextureDestroy(m_pTexture);
  4.         m_pTexture = 0;
  5.     }
  6. }

Надо умножать координаты на коэффициент соотношения высоты экрана (если высота меньше ширины) и "принятого" (стандартного) значения высоты.

Например, за стандарт взято разрешение 1920х1080.
Ты хочешь отрисовать текстуру, которая на экране 1920х1080 располагалась бы справа, по координатам
Код: C++
  1. 150, 200
Допустим, разрешение пользователя - 1280х1024.
Используем формулу
Код: C++
  1. x = static_cast<int>( 150.0f * (1024.0f/1080.0f) ); // = 142
  2. y = static_cast<int>( 200.0f * (1024.0f/1080.0f) ); // = 190

Код: C++
  1. float screen(float a) {
  2.     return static_cast<int>(a * (static_cast<float>(RsGlobal.maximumHeight) / 1080.0f));
  3. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Сентябрь 12, 2016, 07:30:27 pm
Понятно, что отрисовать текстуру с поворотом в игре можно, что в Вайсе, что в СА.
Я имел ввиду, что отдельной функции для этого нету.
Ничего себе...сказывается, что опыта у меня пока маловато - я думал, что если есть опкод, то ничего особо самому писать не нужно(думал, что для каждого опкода есть функция)... просто пока ковырял примитивные опкоды  ;D
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 16, 2016, 12:34:55 pm
1)
Ещё например, установка винила на авто.
С этим разобрался. Набросал пример:
Код: C++
  1. #include "plugin.h"
  2. #include "game_sa\common.h"
  3. #include "game_sa\CTimer.h"
  4. #include "game_sa\CGeneral.h"
  5. #include "game_sa\CModelInfo.h"
  6.  
  7. using namespace plugin;
  8.  
  9. class Remap {
  10. public:
  11.     class RemapInfo {
  12.     public:
  13.         bool permitRemap;
  14.        
  15.         RemapInfo(CVehicle *vehicle) {
  16.             unsigned int random = CGeneral::GetRandomNumberInRange(0, 3);
  17.             if (random == 1)
  18.                 permitRemap = true;
  19.             else permitRemap = false;
  20.         }
  21.     };
  22.  
  23.     Remap() {
  24.         static VehicleExtendedData<RemapInfo> remInfo;
  25.         static unsigned int m_nLastTimeWhenAnyActionWasEnabled = 0;
  26.         static unsigned int randomRemap;
  27.         static unsigned int amountRemap;
  28.         static int currentRemap = -1;
  29.  
  30.         Events::vehicleRenderEvent += [](CVehicle *vehicle) {
  31.             if (vehicle) {
  32.                 RemapInfo &info = remInfo.Get(vehicle);
  33.                 if (info.permitRemap) {
  34.                     CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]);
  35.                     amountRemap = vehModel->GetNumRemaps();
  36.                     if (amountRemap > 0) {
  37.                         randomRemap = CGeneral::GetRandomNumberInRange(0, amountRemap);
  38.                         vehicle->SetRemap(randomRemap);
  39.                     }
  40.                     info.permitRemap = false;
  41.                 }
  42.             }
  43.         };
  44.  
  45.         Events::gameProcessEvent += [] {
  46.             CVehicle *plVehicle = FindPlayerVehicle(-1, false);
  47.             if (plVehicle) {
  48.                 if (CTimer::m_snTimeInMilliseconds >(m_nLastTimeWhenAnyActionWasEnabled + 1000) && KeyPressed(75)) {
  49.                     m_nLastTimeWhenAnyActionWasEnabled = CTimer::m_snTimeInMilliseconds;
  50.                     CVehicleModelInfo *plVehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[plVehicle->m_wModelIndex]);
  51.                     amountRemap = plVehModel->GetNumRemaps();
  52.                     if (amountRemap > 0) {
  53.                         if (currentRemap < static_cast<int>(amountRemap - 1))
  54.                             ++currentRemap;
  55.                         else currentRemap = -1;
  56.                         plVehicle->SetRemap(currentRemap);
  57.                     }
  58.                 }
  59.             }
  60.         };
  61.     }
  62. } remap;
  63.  

Работает, как запланировал. По самому коду есть какие-либо замечания?
Функция
Код: C++
  1. int GetNumRemaps();
описание есть, а определения нет (и другие функции из CVehicleModelInfo), добавил так:
Код: C++
  1. // Converted from thiscall int CVehicleModelInfo::GetNumRemaps(void) 0x4C86B0
  2. int CVehicleModelInfo::GetNumRemaps()
  3. {
  4.     return ((int(__thiscall *)(CVehicleModelInfo*))0x4C86B0)(this);
  5. }

2) Обнаружил интересную вещь - установить покрасочную работу на авто можно ещё так:
Код: C++
  1. vehicle->m_pRemapTexture = pMyTexture;
Получается этим способом можно обойти ограничение на количество покрасочных работ для модели.

Есть ли способ "заполучить" текстуру в RwTexture *pMyTexture;  (помимо способов:)
Код: C++
  1. pMyTexture = mySprite.m_pTexture;
  2. //и
  3. pMyTexture = RwD3D9DDSTextureRead("models\\image", 0);
например, из txd, который находится в gta3.img?

3)
Код: C++
  1. static void VehicleRemoveSphere(CVehicle *vehicle) {
  2.     CColData *colData = vehicle->GetColModel()->m_pColData;
  3.     for (unsigned int i = 0; i < colData->m_wNumSpheres; i++) {
  4.         if (colData->m_pSpheres[i].m_nFlags == 19) { // windscreen col sphere
  5.             colData->m_pSpheres[i].m_fRadius = 0.0f;
  6.             colData->m_pSpheres[i].m_vCenter = {0.0f, 0.0f, 0.0f};
  7.         }
  8.     }
  9. }
Интересная вещь!  :)
А для коллизии колёс как будет?
А можно как-то масштабировать тень модели?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 18, 2016, 08:58:12 am
В первом примере надо определить переменную entries.
Код: C++
  1. vector<SettingsTest::MyData> SettingsTest::entries;

Разобрался, спасибо!

Упс... оказывается не полностью разобрался.  :(
Подскажи пожалуйста, как таким же образом определить MyData *GetDataInfoForModel(unsigned int BaseModelId)
Код: C++
  1.     static void Test() {
  2.         CVehicle *vehicle = FindPlayerVehicle(-1, false);
  3.             if (vehicle) {
  4.                 CFont::SetScale(0.5f, 1.0f);
  5.                 CFont::SetColor(CRGBA(255, 255, 255, 255));
  6.                 CFont::SetAlignment(ALIGN_LEFT);
  7.                 CFont::SetOutlinePosition(1);
  8.                 CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  9.                 CFont::SetBackground(false, false);
  10.                 CFont::SetFontStyle(FONT_SUBTITLES);
  11.                 CFont::SetProp(true);
  12.                 CFont::SetWrapx(600.0f);
  13.                 static char str[32];
  14.                 MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
  15.                 if (entryModel) {
  16.                     sprintf(str, "yes %.d %.2f", entryModel->baseModelId, entryModel->value);
  17.                     CFont::PrintString(5.0f, 355.0f, str);
  18.                 }
  19.                 else {
  20.                     sprintf(str, "no %.d", vehicle->m_wModelIndex);
  21.                     CFont::PrintString(5.0f, 355.0f, str);
  22.                 }
  23.             }
  24.     }
  25.  
  26.     ZR350() {
  27.         ReadSettingsFile();
  28.         Events::drawingEvent += Test;
  29.     }
В этой строчке
Код: C++
  1. MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
студия ругается, что не статическая ссылка на член должна указываться относительно заданного объекта. Если записать так
Код: C++
  1. static MyData *GetDataInfoForModel(unsigned int BaseModelId)
то код не срабатывает.
Вынес
struct MyData
vector<MyData> entries;
void ReadSettingsFile()
MyData *GetDataInfoForModel(unsigned int BaseModelId)
за пределы класса, тогда работает.
Это из примера, что ты показывал здесь http://forum.gtabuilder.ru/index.php?topic=337.msg2414#msg2414 (http://forum.gtabuilder.ru/index.php?topic=337.msg2414#msg2414)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 19, 2016, 12:14:31 am
По самому коду есть какие-либо замечания?
Вроде всё правильно.
Функция
Код: C++
  1. int GetNumRemaps();
описание есть, а определения нет (и другие функции из CVehicleModelInfo), добавил так:
Код: C++
  1. // Converted from thiscall int CVehicleModelInfo::GetNumRemaps(void) 0x4C86B0
  2. int CVehicleModelInfo::GetNumRemaps()
  3. {
  4.     return ((int(__thiscall *)(CVehicleModelInfo*))0x4C86B0)(this);
  5. }
Да, есть такое. CVehicleModelInfo не до конца доработан.
2) Обнаружил интересную вещь - установить покрасочную работу на авто можно ещё так:
Код: C++
  1. vehicle->m_pRemapTexture = pMyTexture;
Получается этим способом можно обойти ограничение на количество покрасочных работ для модели.
Можно. Но и сами текстуры надо будет куда-то добавлять (например, в txd авто).
Есть ли способ "заполучить" текстуру в RwTexture *pMyTexture;  (помимо способов:)
Код: C++
  1. pMyTexture = mySprite.m_pTexture;
  2. //и
  3. pMyTexture = RwD3D9DDSTextureRead("models\\image", 0);
например, из txd, который находится в gta3.img?
Есть функции поиска текстуры в txd.
Код: C++
  1. RwTexture* RwTexDictionaryFindNamedTexture(RwTexDictionary* dict, const RwChar* name); // поиск по имени, RenderWare.h
  2. RwTexture* RwTexDictionaryFindHashNamedTexture(RwTexDictionary* txd, unsigned int hash);  // поиск по хеш-ключу, common.h
Вторая функция добавлена в последнем коммите.
TXD можно достать из пула (если она загружена).
Ты хочешь загружать из дополнительного txd или из уже существующего?
А для коллизии колёс как будет?
А можно как-то масштабировать тень модели?
Колёса, вроде бы, это тоже сферы. Не уверен. Позже гляну.
Тень масштабировать можно, но это сложно. Надо каждую вершину перемещать.
Подскажи пожалуйста, как таким же образом определить MyData *GetDataInfoForModel(unsigned int BaseModelId)
Обьявляй всё как статические члены (static).
Статические переменные дополнительно определяй за пределами класса.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 19, 2016, 09:35:58 am
Можно. Но и сами текстуры надо будет куда-то добавлять (например, в txd авто).
Да, в txd авто - это самый приемлемый вариант.

Есть функции поиска текстуры в txd.
Код: C++
  1. RwTexture* RwTexDictionaryFindNamedTexture(RwTexDictionary* dict, const RwChar* name); // поиск по имени, RenderWare.h
  2. RwTexture* RwTexDictionaryFindHashNamedTexture(RwTexDictionary* txd, unsigned int hash);  // поиск по хеш-ключу, common.h
Вторая функция добавлена в последнем коммите.
TXD можно достать из пула (если она загружена).
Ты хочешь загружать из дополнительного txd или из уже существующего?
Из существующего txd модели. У некоторых моделей есть по два набора покрасок (по четыре покрасочных работ в каждом наборе). Приходится ставить на выбор 4 из них. Если остальные 4 поместить в txd модели, доставать их оттуда и ставить таким образом
Код: C++
  1. vehicle->m_pRemapTexture = pMyTexture;
Можно пример, как достать текстуру (несколько текстур) из txd модели.

Обьявляй всё как статические члены (static).
Статические переменные дополнительно определяй за пределами класса.
Вот с объявлением 
Код: C++
  1. MyData *GetDataInfoForModel(unsigned int BaseModelId)
за пределами класса у меня как раз и непонятка возникла. Покажи пожалуйста.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 19, 2016, 07:42:13 pm
Можно пример, как достать текстуру (несколько текстур) из txd модели.

Код: C++
  1. #include <plugin.h>
  2. #include "game_sa\common.h"
  3. #include "game_sa\CModelInfo.h"
  4. #include "game_sa\CTxdStore.h"
  5. #include "game_sa\CKeyGen.h"
  6. #include "game_sa\CSprite2d.h"
  7.  
  8. using namespace plugin;
  9.  
  10. class VehicleTexture {
  11. public:
  12.     static void Draw() {
  13.         CVehicle *veh = FindPlayerVehicle(-1, false);
  14.         if (veh && veh->m_wModelIndex == MODEL_BOBCAT) {
  15.             TxdDef *txd = CTxdStore::ms_pTxdPool->GetAt(CModelInfo::ms_modelInfoPtrs[veh->m_wModelIndex]->m_wTxdIndex);
  16.             if (txd) {
  17.                 RwTexture *texture = RwTexDictionaryFindHashNamedTexture(txd->m_pRwDictionary, CKeyGen::GetUppercaseKey("bobcat92logo128"));
  18.                 if (texture) {
  19.                     RwEngineInstance->dOpenDevice.fpRenderStateSet(rwRENDERSTATETEXTURERASTER, texture->raster);
  20.                     CSprite2d::DrawTxRect(CRect(RsGlobal.maximumWidth / 2 - 128, 200.0f, RsGlobal.maximumWidth / 2 + 128, 264.0f), CRGBA(255, 255, 255, 255));
  21.                 }
  22.             }
  23.         }
  24.     }
  25.  
  26.     VehicleTexture() {
  27.         Events::drawingEvent += Draw;
  28.     }
  29. } vehTexture;
Вот с объявлением 
Код: C++
  1. MyData *GetDataInfoForModel(unsigned int BaseModelId)
за пределами класса у меня как раз и непонятка возникла. Покажи пожалуйста.

Код: C++
  1. static MyData *GetDataInfoForModel(unsigned int BaseModelId)

UPD: Обновил код, т.к. могли возникнуть проблемы с порядком создания обьектов (главного класса и вектора).
Вот в такой вот ситуации
Код: C++
  1. class A {
  2.     static vector<int> vec; // статическая переменная-вектор - глобальная переменная
  3.  
  4.     A() { // Конструктор класса A
  5.         vec.push_back(5); // Добавляем элемент в вектор
  6.     }
  7. } a; // определяем обьект a класса A (вызывается конструктор A)
  8.  
  9. vector<int> vec; // определяем переменную vec (вызывается конструктор std::vector)
Получается, что мы обращаемся к переменной vec (из конструктора A), которая ещё не была "построена".

Вот такой пример, скомпилированный в студии, является более "правильным".
Код: C++
  1. class A {
  2.     static vector<int> vec; // статическая переменная-вектор - глобальная переменная
  3.  
  4.     A() { // Конструктор класса A
  5.         vec.push_back(5); // Добавляем элемент в вектор
  6.     }
  7. }
  8.  
  9. vector<int> vec; // определяем переменную vec (вызывается конструктор std::vector)
  10.  
  11. A a; // а теперь определяем обьект a класса A (вызывается конструктор A)

http://quirks.chat.ru/cpp/faq/#s10p11 (http://quirks.chat.ru/cpp/faq/#s10p11)

Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <fstream>
  4. #include <string>
  5. #include "game_sa\common.h"
  6. #include "game_sa\CFont.h"
  7.  
  8. using namespace plugin;
  9. using namespace std;
  10.  
  11. class ZR350 {
  12. public:
  13.     struct MyData {
  14.         unsigned int baseModelId;
  15.         float value;
  16.     };
  17.  
  18.     static vector<MyData>& GetDataVector() {
  19.         static vector<MyData> vec; // глобальная переменная vec, доступ к которой осуществляется вызовом GetDataVector()
  20.         return vec;
  21.     }
  22.  
  23.     static void ReadSettingsFile() {
  24.         std::ifstream stream("vehicle_advanced.dat");
  25.         for (std::string line; getline(stream, line); ) {
  26.             if (line[0] != ';' && line[0] != '#') {
  27.                 if (!line.compare("zr350")) {
  28.                     while (getline(stream, line) && line.compare("end")) {
  29.                         if (line[0] != ';' && line[0] != '#') {
  30.                             MyData entry;
  31.                             if (sscanf(line.c_str(), "%d, %f", &entry.baseModelId, &entry.value) == 2)
  32.                                 GetDataVector().push_back(entry); // теперь мы точно знаем, что обращаемся к уже построенному обьекту
  33.                             else
  34.                                 Error("Failed to scan line: %s", line.c_str());
  35.                         }
  36.                     }
  37.                 }
  38.             }
  39.         }
  40.     }
  41.  
  42.     static MyData *GetDataInfoForModel(unsigned int BaseModelId) {
  43.         for (unsigned int i = 0; i < GetDataVector().size(); i++) {
  44.             if (GetDataVector()[i].baseModelId == BaseModelId)
  45.                 return &GetDataVector()[i];
  46.         }
  47.         return nullptr;
  48.     }
  49.  
  50.     static void Test() {
  51.         CVehicle *vehicle = FindPlayerVehicle(-1, false);
  52.         if (vehicle) {
  53.             CFont::SetScale(0.5f, 1.0f);
  54.             CFont::SetColor(CRGBA(255, 255, 255, 255));
  55.             CFont::SetAlignment(ALIGN_LEFT);
  56.             CFont::SetOutlinePosition(1);
  57.             CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  58.             CFont::SetBackground(false, false);
  59.             CFont::SetFontStyle(FONT_SUBTITLES);
  60.             CFont::SetProp(true);
  61.             CFont::SetWrapx(600.0f);
  62.             static char str[32];
  63.             MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
  64.             if (entryModel) {
  65.                 sprintf(str, "yes %d %.2f", entryModel->baseModelId, entryModel->value);
  66.                 CFont::PrintString(5.0f, 355.0f, str);
  67.             }
  68.             else {
  69.                 sprintf(str, "no %d", vehicle->m_wModelIndex);
  70.                 CFont::PrintString(5.0f, 355.0f, str);
  71.             }
  72.         }
  73.     }
  74.  
  75.     ZR350() {
  76.         ReadSettingsFile();
  77.         for (unsigned int i = 0; i < GetDataVector().size(); i++)
  78.             Error("Entry %d: %d - %.2f", i + 1, GetDataVector()[i].baseModelId, GetDataVector()[i].value);
  79.         Events::drawingEvent += Test;
  80.     }
  81. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 20, 2016, 03:54:46 pm
Спасибо за очередные примеры и пояснения!

1)
Цитировать
Обновил код, т.к. могли возникнуть проблемы с порядком создания обьектов (главного класса и вектора).
Вот в такой вот ситуации
А если так, то будет нормально, правильно я понимаю?
Код: C++
  1. vector<int> vec; // определяем переменную vec (вызывается конструктор std::vector)
  2. class A {
  3.              
  4.     A() { // Конструктор класса A
  5.         vec.push_back(5); // Добавляем элемент в вектор
  6.     }
  7. } a; // определяем обьект a класса A (вызывается конструктор A)

2) При сборке какого-либо проекта с подключением
Код: C++
  1. #include "game_sa\CTxdStore.h"
проект собирается, но студия выдаёт предупреждение
Цитировать
>d:\projects\plugin-sdk\plugin_sa\game_sa\TxdDef.h(19): warning C4161: #pragma pack(pop...): число извлечений из стека превышает число занесений

3) С поддержкой Windows XP какой-либо проект нельзя собрать?

4) Если объединять примеры для zr350 и тягачей, то считывание с vehicle_advanced.dat надо делать так?
Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <fstream>
  4. #include <string>
  5. #include <sstream>
  6. #include "game_sa\common.h"
  7. #include "game_sa\CFont.h"
  8.  
  9. using namespace plugin;
  10. using namespace std;
  11.  
  12. vector<unsigned int> truckIDs;
  13.  
  14. class ZR350 {
  15. public:
  16.     struct MyData {
  17.         unsigned int baseModelId;
  18.         float value;
  19.     };
  20.  
  21.     static vector<MyData>& GetDataVector() {
  22.         static vector<MyData> vec; // глобальная переменная vec, доступ к которой осуществляется вызовом GetDataVector()
  23.         return vec;
  24.     }
  25.  
  26.     static void ReadSettingsFile() {
  27.         ifstream stream("vehicle_advanced.dat");
  28.         for (string line; getline(stream, line); ) {
  29.             if (line[0] != ';' && line[0] != '#') {
  30.                 if (!line.compare("zr350")) {
  31.                     while (getline(stream, line) && line.compare("endzr350")) {
  32.                         if (line[0] != ';' && line[0] != '#') {
  33.                             MyData entry;
  34.                             if (sscanf(line.c_str(), "%d, %f", &entry.baseModelId, &entry.value) == 2)
  35.                                 GetDataVector().push_back(entry); // теперь мы точно знаем, что обращаемся к уже построенному обьекту
  36.                             else
  37.                                 Error("Failed to scan line: %s", line.c_str());
  38.                         }
  39.                     }
  40.                 }
  41.                 if (!line.compare("trucks")) {
  42.                     while (getline(stream, line) && line.compare("endtrucks")) {
  43.                         if (line[0] != ';' && line[0] != '#') {
  44.                             std::stringstream ss(line);
  45.                             int i;
  46.                             while (ss >> i) {
  47.                                 truckIDs.push_back(i);
  48.                                 if (ss.peek() == ',')
  49.                                     ss.ignore();
  50.                             }
  51.                         }
  52.                     }
  53.                 }
  54.             }
  55.         }
  56.     }
  57.  
  58.     static MyData *GetDataInfoForModel(unsigned int BaseModelId) {
  59.         for (unsigned int i = 0; i < GetDataVector().size(); i++) {
  60.             if (GetDataVector()[i].baseModelId == BaseModelId)
  61.                 return &GetDataVector()[i];
  62.         }
  63.         return nullptr;
  64.     }
  65.  
  66.     static bool IsTruckModel(unsigned int modelId) {
  67.         for (unsigned int i : truckIDs) {
  68.             if (i == modelId)
  69.                 return true;
  70.         }
  71.         return false;
  72.     }
  73.  
  74.     static void Test() {
  75.         CVehicle *vehicle = FindPlayerVehicle(-1, false);
  76.         if (vehicle) {
  77.             CFont::SetScale(0.5f, 1.0f);
  78.             CFont::SetColor(CRGBA(255, 255, 255, 255));
  79.             CFont::SetAlignment(ALIGN_LEFT);
  80.             CFont::SetOutlinePosition(1);
  81.             CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  82.             CFont::SetBackground(false, false);
  83.             CFont::SetFontStyle(FONT_SUBTITLES);
  84.             CFont::SetProp(true);
  85.             CFont::SetWrapx(600.0f);
  86.             static char str[32];
  87.             MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
  88.             if (entryModel) {
  89.                 sprintf(str, "yes %d %.2f", entryModel->baseModelId, entryModel->value);
  90.                 CFont::PrintString(5.0f, 445.0f, str);
  91.             }
  92.             else {
  93.                 sprintf(str, "no %d", vehicle->m_wModelIndex);
  94.                 CFont::PrintString(5.0f, 445.0f, str);
  95.             }
  96.             if (IsTruckModel(vehicle->m_wModelIndex)) {
  97.                 sprintf(str, "yes truck %d", vehicle->m_wModelIndex);
  98.                 CFont::PrintString(205.0f, 445.0f, str);
  99.             }
  100.             else {
  101.                 sprintf(str, "no truck %d", vehicle->m_wModelIndex);
  102.                 CFont::PrintString(205.0f, 445.0f, str);
  103.             }
  104.         }
  105.     }
  106.  
  107.     ZR350() {
  108.         ReadSettingsFile();
  109.         for (unsigned int i = 0; i < GetDataVector().size(); i++)
  110.             Error("Entry %d: %d - %.2f", i + 1, GetDataVector()[i].baseModelId, GetDataVector()[i].value);
  111.         Events::drawingEvent += Test;
  112.     }
  113. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 20, 2016, 07:52:32 pm
А если так, то будет нормально, правильно я понимаю?
Код: C++
  1. vector<int> vec; // определяем переменную vec (вызывается конструктор std::vector)
  2. class A {
  3.              
  4.     A() { // Конструктор класса A
  5.         vec.push_back(5); // Добавляем элемент в вектор
  6.     }
  7. } a; // определяем обьект a класса A (вызывается конструктор A)

Да. (обьект vec конструируется до обьекта a).

2) При сборке какого-либо проекта с подключением
Код: C++
  1. #include "game_sa\CTxdStore.h"
проект собирается, но студия выдаёт предупреждение
Цитировать
>d:\projects\plugin-sdk\plugin_sa\game_sa\TxdDef.h(19): warning C4161: #pragma pack(pop...): число извлечений из стека превышает число занесений


Надо убрать эту строчку (с #pragma pack). Будет в следующем коммите.

3) С поддержкой Windows XP какой-либо проект нельзя собрать?

Собирать с тулсетом для XP (v140_xp).
Если у тебя он не установлен, можно скачать и установить.
(http://i.imgur.com/MLkG2bvm.png) (http://i.imgur.com/MLkG2bv.png)

4) Если объединять примеры для zr350 и тягачей, то считывание с vehicle_advanced.dat надо делать так?


Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <fstream>
  4. #include <string>
  5. #include <sstream>
  6. #include "game_sa\common.h"
  7. #include "game_sa\CFont.h"
  8.  
  9. using namespace plugin;
  10. using namespace std;
  11.  
  12. class ZR350 {
  13. public:
  14.     struct Zr350Info {
  15.         unsigned int baseModelId;
  16.         float value;
  17.     };
  18.  
  19.     static vector<Zr350Info>& GetZr350Infos() {
  20.         static vector<Zr350Info> zr350Infos;
  21.         return zr350Infos;
  22.     }
  23.  
  24.     static vector<unsigned int>& GetTruckIDs() {
  25.         static vector<unsigned int> truckIDs;
  26.         return truckIDs;
  27.     }
  28.  
  29.     static void ReadSettingsFile() {
  30.         ifstream stream("vehicle_advanced.dat");
  31.         for (string line; getline(stream, line); ) {
  32.             if (line[0] != ';' && line[0] != '#') {
  33.                 if (!line.compare("zr350")) {
  34.                     while (getline(stream, line) && line.compare("end")) {
  35.                         if (line[0] != ';' && line[0] != '#') {
  36.                             Zr350Info entry;
  37.                             if (sscanf(line.c_str(), "%d, %f", &entry.baseModelId, &entry.value) == 2)
  38.                                 GetZr350Infos().push_back(entry);
  39.                         }
  40.                     }
  41.                 } else if (!line.compare("trucks")) {
  42.                     while (getline(stream, line) && line.compare("end")) {
  43.                         if (line[0] != ';' && line[0] != '#') {
  44.                             std::stringstream ss(line);
  45.                             int i;
  46.                             while (ss >> i) {
  47.                                 GetTruckIDs().push_back(i);
  48.                                 if (ss.peek() == ',')
  49.                                     ss.ignore();
  50.                             }
  51.                         }
  52.                     }
  53.                 }
  54.             }
  55.         }
  56.     }
  57.  
  58.     static Zr350Info *GetZr350InfoForModel(unsigned int BaseModelId) {
  59.         for (unsigned int i = 0; i < GetZr350Infos().size(); i++) {
  60.             if (GetZr350Infos()[i].baseModelId == BaseModelId)
  61.                 return &GetZr350Infos()[i];
  62.         }
  63.         return nullptr;
  64.     }
  65.  
  66.     static bool GetIsModelTruck(unsigned int modelId) {
  67.         for (unsigned int i : GetTruckIDs()) {
  68.             if (i == modelId)
  69.                 return true;
  70.         }
  71.         return false;
  72.     }
  73.  
  74.     static void Test() {
  75.         CVehicle *vehicle = FindPlayerVehicle(-1, false);
  76.         if (vehicle) {
  77.             CFont::SetScale(0.5f, 1.0f);
  78.             CFont::SetColor(CRGBA(255, 255, 255, 255));
  79.             CFont::SetAlignment(ALIGN_LEFT);
  80.             CFont::SetOutlinePosition(1);
  81.             CFont::SetDropColor(CRGBA(0, 0, 0, 255));
  82.             CFont::SetBackground(false, false);
  83.             CFont::SetFontStyle(FONT_SUBTITLES);
  84.             CFont::SetProp(true);
  85.             CFont::SetWrapx(600.0f);
  86.             static char str[32];
  87.             Zr350Info *entryModel = GetZr350InfoForModel(vehicle->m_wModelIndex);
  88.             if (entryModel) {
  89.                 sprintf(str, "yes %d %.2f", entryModel->baseModelId, entryModel->value);
  90.                 CFont::PrintString(5.0f, 445.0f, str);
  91.             }
  92.             else {
  93.                 sprintf(str, "no %d", vehicle->m_wModelIndex);
  94.                 CFont::PrintString(5.0f, 445.0f, str);
  95.             }
  96.             if (GetIsModelTruck(vehicle->m_wModelIndex)) {
  97.                 sprintf(str, "yes truck %d", vehicle->m_wModelIndex);
  98.                 CFont::PrintString(205.0f, 445.0f, str);
  99.             }
  100.             else {
  101.                 sprintf(str, "no truck %d", vehicle->m_wModelIndex);
  102.                 CFont::PrintString(205.0f, 445.0f, str);
  103.             }
  104.         }
  105.     }
  106.  
  107.     ZR350() {
  108.         ReadSettingsFile();
  109.         Events::drawingEvent += Test;
  110.     }
  111. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 21, 2016, 05:47:32 pm
Собирать с тулсетом для XP (v140_xp).
Если у тебя он не установлен, можно скачать и установить.

Я пробовал, но когда я выбираю режим Visual Studio 2015 - Windows XP (v140_xp), то в позиции целевая платформа надпись Windows исчезает.
(http://savepic.net/8409601m.png) (http://savepic.net/8409601.png)

при сборке выходит предупреждение
Цитировать
C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppBuild.targets(1193,5): warning MSB8030: The linker switch "Minimum Required Version" requires "SubSystem" to be set.  Without "SubSystem", the "Minimum Required Version" would not be passed to linker and could prevent to the output binary from running on older Operating Systems.

и плагин на Windows XP не работает (ребята проверяли, у меня семёрка установлена).

Когда устанавливал студию, то инструменты для поддержки XP ставил. Сейчас специально обновил, всё тоже самое.
Не пойму в чём дело.  :(
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 21, 2016, 06:37:24 pm
Попробуй поставить SubSystem на Windows.
(http://i.imgur.com/ufGfngZm.png) (http://i.imgur.com/ufGfngZ.png)

Какая именно ошибка выходит на WinXP?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 22, 2016, 09:59:25 am
Попробуй поставить SubSystem на Windows.

Поставил. Предупреждение при сборке проекта исчезло, но в позиции целевая платформа надпись Windows также исчезает.
(http://savepic.net/8410665m.png) (http://savepic.net/8410665.png)

(http://savepic.net/8393257m.png) (http://savepic.net/8393257.png)

Какая именно ошибка выходит на WinXP?
Плагин просто не работает, т.е. ничего не происходит. Я собирал для ребят твои примеры GPS и Универсальные поворотники. Скинул на тест эти же плагины, собранные по-новой. Протестируют, посмотрим какой будет результат. Но по-любому в целевой платформе надпись Windows так и не появилась.  :(


UPD:
Ребята протестировали, плагины на XP не работают.  >:(
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 23, 2016, 09:36:34 pm
Пока искал, кое-что понял: если изменяешь какие-либо параметры в настройках (пути включения/библиотек, обьявления препроцессора) и уже потом меняешь тулсет на xp, то эти поля не будут модифицироваться. Т.е., как я понял, надо для начала выставить нужный тулсет, а только потом настраивать проект.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 24, 2016, 07:23:37 am
Я пробовал так. Создал новый пустой проект. Выставил тулсет на xp и сразу в целевой платформе надпись Windows пропадает. Дальнейшая настройка проекта ничего в этой позиции не меняет. Пробовал и так - создал новый пустой проект. Выставил SubSystem на Windows. Потом поменял тулсет на xp. Всё тоже самое. Ерунда какая-то.
Ну что же, придётся писать, что плагины на XP не работают. Хотя пользователей с XP не так много осталось, но они есть.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 24, 2016, 04:18:36 pm
У меня пустой проект с настройками для XP (тулсет, субсистема) нормально запускается (проверил на виртуальной машине с XP SP3).
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 24, 2016, 04:35:28 pm
У меня пустой проект с настройками для XP (тулсет, субсистема) нормально запускается (проверил на виртуальной машине с XP SP3).
А у тебя  в позиции целевая платформа надпись Windows при этом есть?

Также есть функции RwMatrixRotate/RwFrameRotate, которые вращают матрицу/фрейм вокруг оси (ось можно задать своим вектором).
Ну и ещё вариант - вращение методами CMatrix: RotateX,RotateY,RotateZ и другими (см. файл CMatrix.h) Eсли будет нужно, то покажу на примере.
Да, покажи пожалуйста такие примеры для открытия и закрытия, например, капота авто функциями RwMatrixRotate/RwFrameRotate и методом CMatrix.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 24, 2016, 06:35:27 pm
У меня эта надпись была изначально, и не пропадала.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 24, 2016, 06:44:08 pm
Я у меня её нет. Не пойму, что я делаю не так. :( Версия Visual Studio 2015 у меня Community. Версия Windows 7 максимальная SP1.

Можешь скинуть мне свой пустой проект?


UPD:

Да, покажи пожалуйста такие примеры для открытия и закрытия, например, капота авто функциями RwMatrixRotate/RwFrameRotate и методом CMatrix.
С вызовом RwMatrixRotate/RwFrameRotate  разобрался.

Просьба показать вызов методов CMatrix.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 25, 2016, 12:31:54 pm
Оказывается, у меня под XP запускается даже плагин, собранный с v140.

Версия студии у меня - Enterprise 2015.
Может, в Community есть какие-то ограничения...
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 25, 2016, 05:31:30 pm
Может и так, а может я просто с настройками что-то не так делаю. Скинь пожалуйста настроенный пустой проект, проверю, если будет также, как сейчас - значит дело в версии студии, если будет нормально - значит я, что-то с настройками напутал.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 25, 2016, 05:41:50 pm
Мне тут подсказали, что на WinXP может некорректно работать т.н. паттерн синглтон.
http://stackoverflow.com/a/32776479 (http://stackoverflow.com/a/32776479)

Попробую что-то с этим сделать.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 25, 2016, 06:40:10 pm
У тебя же плагин нормально собирается и работает. Значит это у меня, что-то не так или с настройками, или с самой студией. Кстати, в свойствах sdk plugin_sa и plugin_vc тулсет выставлен на XP, но в позиции целевая платформа надписи Windows нет.

(http://savepic.net/8465854m.png) (http://savepic.net/8465854.png)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 25, 2016, 08:24:37 pm
У меня нормально работает только "пустой" плагин (с выводом сообщения). Собранные с sdk тоже не работают.

Просьба протестировать этот плагин на XP (это кар спаунер (https://github.com/DK22Pac/plugin-sdk/tree/master/examples/SA_VehicleSpawner) + сообщение при аттаче).

UP: Сделал новый шаблон проекта (для SA).
https://drive.google.com/uc?export=download&id=0B3pQzS44Fafddk85NlBpRl9ETW8
Все старые шаблоны удалить, папку Plugin-SDK разархивировать в
Documents\Visual Studio 2015\Templates\ProjectTemplatesЗаменить пути на свои в файле ProjectSA.vcxproj.
Шаблон будет доступен в категории Visual C++ -> Windows -> Plugin-SDK
Для сборки под XP выбрать режим Rel-XP.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 26, 2016, 11:14:12 am
Просьба протестировать этот плагин на XP (это кар спаунер (https://github.com/DK22Pac/plugin-sdk/tree/master/examples/SA_VehicleSpawner) + сообщение при аттаче).
Ребята протестили. Теперь работает и на XP.
http://gta.com.ua/forum/index.php?showtopic=3382&p=2224761 (http://gta.com.ua/forum/index.php?showtopic=3382&p=2224761)

Сделал новый шаблон проекта (для SA).

Для сборки под XP выбрать режим Rel-XP.
Собрал для теста два плагина с новым шаблоном. Проверил у родственников на компьютере с Windows XP SP2 - работают!  :D Спасибо!  ;)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 27, 2016, 12:56:01 pm
Чуток ещё изменил код для "Neon". Добавил отключение неона при взрыве или перевёртывании транспорта. Проверку по времени перенёс из функции CanEnableNeonOnThisVehicle в функцию RenderNeonForVehicle для того, чтобы неон не только включался, но и выключался в нужное время.
Можно добавить этот пример в sdk examples?

Код: C++
  1. #include "plugin.h"
  2. #include "game_sa\CClock.h"
  3. #include "game_sa\CShadows.h"
  4. #include "game_sa\common.h"
  5. #include "KeyCheck.h"
  6. #include "game_sa\CModelInfo.h"
  7. #include "game_sa\CTimer.h"
  8.  
  9. #define TURN_ON_OFF_DELAY 500
  10.  
  11. using namespace plugin;
  12. using namespace std;
  13.  
  14. RwTexture *&pWhiteTex = *(RwTexture **)0xB4E3EC;
  15.  
  16. class NeonLights {
  17. public:
  18.     enum eNeonColor {
  19.         NEON_YELLOW, NEON_GREEN, NEON_RED, NEON_BLUE, NEON_PURPLE
  20.     };
  21.  
  22.     class Neon {
  23.     public:
  24.         unsigned char color;
  25.         bool activated;
  26.         bool processed;
  27.  
  28.         Neon(CVehicle *) { activated = processed = false; }
  29.  
  30.         void Enable(eNeonColor Color) {
  31.             color = Color;
  32.             activated = true;
  33.         }
  34.  
  35.         void Disable() { activated = false; }
  36.     };
  37.  
  38.     static VehicleExtendedData<Neon> VehNeon;
  39.  
  40.     static bool CanEnableNeonOnThisVehicle(CVehicle *vehicle) {
  41.         CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]);
  42.         return vehicle->m_pDriver
  43.             && (vehModel->m_nClass == 1 || vehModel->m_nClass == 2 || vehModel->m_nClass == 3)
  44.             && (vehicle->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE || vehicle->m_dwVehicleSubClass == VEHICLE_MTRUCK || vehicle->m_dwVehicleSubClass == VEHICLE_QUAD);
  45.     }
  46.  
  47.     static void ProcessNpcVehicle(CVehicle *vehicle) {
  48.         if (CanEnableNeonOnThisVehicle(vehicle) && !VehNeon.Get(vehicle).processed) {
  49.             VehNeon.Get(vehicle).processed = true;
  50.             if (rand() % 3 == 1) {
  51.                 VehNeon.Get(vehicle).activated = true;
  52.                 VehNeon.Get(vehicle).color = rand() % 5;
  53.             }
  54.         }
  55.     }
  56.  
  57.     static void ProcessVehicles() {
  58.         KeyCheck::Update();
  59.         CVehicle *playaVeh = FindPlayerVehicle(0, false);
  60.         if (playaVeh
  61.             && (playaVeh->m_dwVehicleSubClass == VEHICLE_AUTOMOBILE
  62.                 || playaVeh->m_dwVehicleSubClass == VEHICLE_MTRUCK
  63.                 || playaVeh->m_dwVehicleSubClass == VEHICLE_QUAD)) {
  64.             if (KeyCheck::Check(VK_SHIFT)) {
  65.                 if (KeyCheck::CheckJustDown('1'))
  66.                     VehNeon.Get(playaVeh).Enable(NEON_YELLOW);
  67.                 else if (KeyCheck::CheckJustDown('2'))
  68.                     VehNeon.Get(playaVeh).Enable(NEON_GREEN);
  69.                 else if (KeyCheck::CheckJustDown('3'))
  70.                     VehNeon.Get(playaVeh).Enable(NEON_RED);
  71.                 else if (KeyCheck::CheckJustDown('4'))
  72.                     VehNeon.Get(playaVeh).Enable(NEON_BLUE);
  73.                 else if (KeyCheck::CheckJustDown('5'))
  74.                     VehNeon.Get(playaVeh).Enable(NEON_PURPLE);
  75.                 else if (KeyCheck::CheckJustDown('0'))
  76.                     VehNeon.Get(playaVeh).Disable();
  77.             }
  78.         }
  79.         for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  80.             CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  81.             if (vehicle && vehicle != playaVeh)
  82.                 ProcessNpcVehicle(vehicle);
  83.         }
  84.     }
  85.  
  86.     static void RenderNeonForVehicle(CVehicle *vehicle) {
  87.         if (vehicle->m_fHealth < 1.0f || vehicle->IsUpsideDown())
  88.             VehNeon.Get(vehicle).Disable();
  89.         if (VehNeon.Get(vehicle).activated && CClock::GetIsTimeInRange(21, 6)) {
  90.             unsigned char r, g, b;
  91.             switch (VehNeon.Get(vehicle).color) {
  92.             case NEON_YELLOW: r = 255; g = 200; b = 0;    break;
  93.             case NEON_GREEN:  r = 0;   g = 255; b = 0;    break;
  94.             case NEON_RED:    r = 255; g = 0;   b = 0;    break;
  95.             case NEON_BLUE:   r = 0;   g = 0;   b = 255;  break;
  96.             case NEON_PURPLE: r = 255; g = 0;   b = 255;  break;
  97.             }
  98.             if (CTimer::m_snTimeInMilliseconds % (TURN_ON_OFF_DELAY + 250) < TURN_ON_OFF_DELAY) {
  99.                 CVector Pos = CModelInfo::ms_modelInfoPtrs[vehicle->m_wModelIndex]->m_pColModel->m_boundBox.m_vSup;
  100.                 CVector center = vehicle->TransformFromObjectSpace(CVector(0.0f, 0.0f, 0.0f));
  101.                 CVector up = vehicle->TransformFromObjectSpace(CVector(0.0f, -Pos.y - 0.5f, 0.0f)) - center;
  102.                 CVector right = vehicle->TransformFromObjectSpace(CVector(Pos.x + 0.2f, 0.0f, 0.0f)) - center;
  103.                 CShadows::StoreShadowToBeRendered(2, pWhiteTex, &center, up.x, up.y, right.x, right.y, 255, r, g, b, 2.0f, false, 1.0f, 0, true);
  104.             }
  105.         }
  106.     }
  107.  
  108.     NeonLights() {
  109.         Events::gameProcessEvent += ProcessVehicles;
  110.         Events::vehicleRenderEvent += RenderNeonForVehicle;
  111.     }
  112. } neon;
  113.  
  114. VehicleExtendedData<NeonLights::Neon> NeonLights::VehNeon;


UPD:
Пример добавил.

Просьба показать вызов методов CMatrix.
Код: C++
  1. reinterpret_cast<CMatrix*>(&automobile->m_aCarNodes[CAR_MISC_A]->modelling)->SetRotateXOnly(angle);
Правильно?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 02, 2016, 04:51:06 pm
Чуть позже будут примеры.
И sdk обновлю.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 07, 2016, 11:02:54 pm
Проект обновил.

Код: C++
  1. CMatrix m(&automobile->m_aCarNodes[CAR_MISC_A]->modelling, false);
  2. m.SetRotateXOnly(angle);
  3. m.UpdateRW();
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 08, 2016, 11:01:17 am
Спасибо.
1) Добавил в sdk пример установки винила на транспорт https://github.com/DK22Pac/plugin-sdk/tree/master/examples/SA_VehicleRemap (https://github.com/DK22Pac/plugin-sdk/tree/master/examples/SA_VehicleRemap).

2) Хотел для VC разобрать некоторые аналогичные SA функции, но есть вопрос. В CVehicle.cpp в некоторых функциях вместо адреса exe стоит число в квадратных скобках. Здесь, например, [29]:
Код: C++
  1. // Converted from float CVehicle::GetDooorAngleOpenRatio(uint door) 0x871EF4
  2. float CVehicle::GetDooorAngleOpenRatio(unsigned int door)
  3. {
  4.    return ((float (__thiscall *)(CVehicle*, unsigned int))(*(void ***)this)[29])(this, door);
  5. }

Просьба пояснить этот момент. 
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Октябрь 08, 2016, 02:57:40 pm
Цитировать
[29]
Вот я тоже хотел узнать. Это разве не побайтовое смещение?
Прост я выдернул напрямую кусок псевдокода из IDA - он блокирует/разблокирует управление игроком. Всё работает, но что конкретно тут происходит - я не знаю:
Код: C++
  1. //вначале неким способом мы получаем __int16      *GetPadInt
  2. //потом следующие строчки служат для управления управлением, лол:
  3. GetPadInt[120] |= 0x20u; // Disable Player Controls
  4. GetPadInt[120] &= 0xFFDFu; // Enable Player Controls
  5. //что происходит на последних двух строчках^ - хз
Повторюсь - всё нормально работает, но надеюсь, что DK поможет разобраться, как это работает(а то в других случаях копирование псевдокода может не спасти ситуацию)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 08, 2016, 03:08:49 pm
Это вызов метода из таблицы виртуальных методов (https://ru.wikipedia.org/wiki/%D0%A2%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0_%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D0%BE%D0%B2) (virtual table, "vtable").

http://dkhramov.dp.ua/Comp/VirtualMethods (http://dkhramov.dp.ua/Comp/VirtualMethods)

А теперь - конкретнее:
void ***X = (void ***)thisприводим this (CVehicle *) к (void ***) (то же самое, что reinterpret_cast<void ***>(this))
void **Y = *XРазыменовываем указатель void *** ("читаем" значение по адресу (this + 0) - получаем указатель на таблицу виртуальных методов (void **, массив указателей на void *))
void *Z = Y[29]Получаем элемент с индексом 29 в этой таблице, получили указатель void *
auto F = ((float (__thiscall *)(CVehicle*, unsigned int))ZПриводим этот указатель к указателю на функцию нужного типа
F(this, door)И тут же вызываем эту функцию.

Код: C++
  1. void CallSimpleVirtualMethod(CVehicle *_this, unsigned int index) {
  2.     void ***pVtable = reinterpret_cast<void ***>(_this + 0); // указатель на виртуальную таблицу находится по смещению +0 в структуре CVehicle
  3.     void **vtable = *pVtable; // читаем значение, получаем адрес виртуальной таблицы
  4.     void *method_addr = vtable[index]; // читаем значение, получаем адрес метода
  5.     auto method = reinterpret_cast<float(__thiscall *)(CVehicle*)>(method_addr);
  6.     method(_this);
  7. }

В CLEO это выглядело бы так:
Код: C++
  1. 0@ = read_memory VEHICLE_STRUCT size 4 vp 0 // получили адрес виртуальной таблицы
  2. 1@ = 29 * 4 // смещение к нужному методу
  3. 0@ += 1@ // получаем адрес в таблице
  4. 0@ = read_memory 0@ size 4 vp 0 // получаем адрес метода
  5. call_method VEHICLE_STRUCT params 0 pop 0
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 08, 2016, 03:29:35 pm
Вот я тоже хотел узнать. Это разве не побайтовое смещение?
Если у тебя массив char (размер = 1 байт) - то да, побайтовое.
Прост я выдернул напрямую кусок псевдокода из IDA - он блокирует/разблокирует управление игроком. Всё работает, но что конкретно тут происходит - я не знаю:
Код: C++
  1. //вначале неким способом мы получаем __int16      *GetPadInt
  2. //потом следующие строчки служат для управления управлением, лол:
Как именно ты получаешь
Цитировать
вначале неким способом мы получаем __int16   *GetPadInt
?
Вероятно, это структура CPad, которую ты почему-то представляешь как массив указателей на int16 (2-байтовый integer), и изменяешь значение
Цитировать
GetPadInt[120] // получить элемент с индексом 120 в массиве GetPadInt
,
т.е.
Код: C++
  1. pad + 240

//что происходит на последних двух строчках^ - хз
Код: C++
  1. unsigned short value = 0;
  2. value |= 0x20 - включить 5-ый бит (оператор OR)
  3. value &= 0xFFDF - отключить 5-ый бит (оператор AND)
Почему именно 5-ый бит - открывай калькулятор в режиме "Программист" и разбирайся  :)

PS В С++ есть такая штука, как битовые поля.
Код: C++
  1. struct my_16bit_value {
  2.     unsigned short _bits1 : 5; // биты 0 - 4
  3.     unsigned short bit_5 : 1; // бит 5
  4.     unsigned short _bits2 : 10; // биты 6 - 15
  5.  
  6.     my_16bit_value() { // обнуляем
  7.         _bits1 = 0;
  8.         bit_5 = false;
  9.         _bits2 = 0;
  10.     }
  11. };
  12.  
  13. my_16bit_value value;
  14. value.bit_5 = true; // включить 5-ый бит
  15. value.bit_5 = false; // отключить 5-ый бит

Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 08, 2016, 05:45:58 pm
Это вызов метода из таблицы виртуальных методов (virtual table, "vtable").

А так можно записать?
Код: C++
  1. // Converted from float CVehicle::GetDooorAngleOpenRatio(uint door) 0x871EF4
  2. float CVehicle::GetDooorAngleOpenRatio(unsigned int door)
  3. {
  4.     return ((float (__thiscall *)(CVehicle*, unsigned int))0x871EF4)(this, door);
  5. }

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 08, 2016, 06:30:22 pm
Можно. Но не надо. Этот метод является виртуальным.
У каждого класса из иерархии CVehicle есть (или может быть) своя реализация метода GetDooorAngleOpenRatio, и вызывать его надо именно из виртуальной таблицы.

Обычный метод
Код: C++
  1. CBike *bike = new CBike(...);
  2. CVehicle *vehicle = bike;
  3. vehicle->GetDooorAngleOpenRatio(); // вызываем CVehicle::GetDooorAngleOpenRatio. Вызывается 0x871EF4
  4. CAutomobile *automobile = new CAutomobile(...);
  5. vehicle = automobile;
  6. vehicle->GetDooorAngleOpenRatio(); // вызываем CVehicle::GetDooorAngleOpenRatio. Вызывается 0x871EF4

Виртуальный метод
Код: C++
  1. CBike *bike = new CBike(...); // при конструктировании CBike, по офсету +0 записывается указатель на таблицу виртуальных методов CBike
  2. CVehicle *vehicle = bike;
  3. vehicle->GetDooorAngleOpenRatio(); // вызываем CBike::GetDooorAngleOpenRatio. Вызывается vehicle->таблица->GetDooorAngleOpenRatio
  4. CAutomobile *automobile = new CAutomobile(...); // при конструктировании CAutomobile, по офсету +0 записывается указатель на таблицу виртуальных методов CAutomobile
  5. vehicle = automobile;
  6. vehicle->GetDooorAngleOpenRatio(); // вызываем CAutomobile::GetDooorAngleOpenRatio. Вызывается vehicle->таблица->GetDooorAngleOpenRatio

(http://i.imgur.com/QND5qM5m.png) (http://i.imgur.com/QND5qM5.png) (http://i.imgur.com/aCwOokMm.png) (http://i.imgur.com/aCwOokM.png)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 08, 2016, 07:41:29 pm
Если я правильно понял, то тогда для VC, например, будет так:

// CVehicle.h
Код: C++
  1. // component index in m_apModelNodes array
  2. void GetComponentWorldPosition(int componentId, CVector& posnOut);

// CVehicle.cpp
Код: C++
  1. // Converted from void CVehicle::GetComponentWorldPosition(int componentId,CVector &posnOut) 0x69CA40
  2. void CVehicle::GetComponentWorldPosition(int componentId, CVector& posnOut)
  3. {
  4.     ((void (__thiscall *)(CVehicle*, int, CVector&))(*(void ***)this)[19])(this, componentId, posnOut);
  5. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 08, 2016, 08:01:51 pm
Я все обьявления и определения (методов класса) генерировал автоматом.
Могу и тебе эту программу подогнать  :)
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Октябрь 08, 2016, 09:18:55 pm
DK, я просто нашел в кучи всевдокода момент, когда происходит именно то, что мне нужно(отключение/включение управления), и так повезло, что от себя ничего практически добавлять не пришлось(иначе я бы с этим не справился):
Там объявлялась переменная именно __int16, я не стал ничего додумывать и у меня это так:
Код: C++
  1. __int16 *GetPadInt;
Ниже используется функция, возвращающая(как я понял) поинтер пада, поэтому я объявил эту функцию:
Код: C++
  1. auto    _GetPad         = (__int16* (_cdecl*)(signed int pad))0x4AB060;  // Returns Player Controls Pointer
И всё! Дальше по-сути чисто копипаста псевдокода с моими комментариями:
Код: C++
  1. GetPadInt = _GetPad(0); // get Player Controls Pointer
  2. GetPadInt[120] |= 0x20u; // Disable Player Controls
и
Код: C++
  1. GetPadInt = _GetPad(0); // get Player Controls Pointer
  2. GetPadInt[120] &= 0xFFDFu; // Enable Player Controls
Если бы паста не сработала, то у меня ничего бы не вышло, т.к. сам я еще так не разбирал эти побайтовые/побитовые смещения...
Просто я не думаю, что буду особо углубляться в программирование(хочу больше ковырять моделирование и анимацию), а на данном этапе мне требовалось лишь заставить это работать, и оно(к счастью) работает ;D
Цитировать
Почему именно 5-ый бит - открывай калькулятор в режиме "Программист" и разбирайся :)
Да вот тут опять загвоздка - я не понимаю, почему 5й, а не 6й бит(если считать справа налево), ведь 6й становится нулем:
https://gyazo.com/15f6431c36f38e5ceb3451e93cf1f352
И последний вопрос: если есть адрес массива float a, то являются ли следующие варианты идентичными:
Код: C++
  1. b=*a[2];
  2. b=*a+8;
?
Извиняюсь за флуд, просто случайно заметил, как зашла речь про то, непонимание чего меня мучило...
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 08, 2016, 10:07:49 pm
Да, эта функция возвращает указатель на CPad.
Код: C++
  1. CPad *CPad::GetPad(int padNumber)
Цитировать
Да вот тут опять загвоздка - я не понимаю, почему 5й, а не 6й бит(если считать справа налево), ведь 6й становится нулем:
5ый - потому, что биты обычно считают от нуля. Даже в калькуляторе это видно.
Цитировать
И последний вопрос: если есть адрес массива float a, то являются ли следующие варианты идентичными:
Нет.
Обе записи неверны.
Код: C++
  1. b=*a[2];
Если a - это массив float, то ты получаешь элемент с индексом 2 и читаешь значение по адресу, который лежит в этом элементе. Компилятор должен выдать ошибку.
Код: C++
  1. b=*a+8;
Тут читается значение первого элемента и к нему прибавляется 8.

Код: C++
  1. float a[3]; // обявляем массив из 3-х float.
  2. float first = a[0]; // получили первый элемент в массиве
  3. float first = *a; // получили первый элемент в массиве
  4.  
  5. float third = a[2]; // получили третий элемент в массиве
  6. float third = *(a + 2); // получили третий элемент в массиве
  7. float third = *(float *)((unsigned char *)a + 8); // получили третий элемент в массиве
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Октябрь 08, 2016, 10:18:43 pm
Аа, теперь всё ясно, спасибо.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 09, 2016, 06:47:49 am
Я все обьявления и определения (методов класса) генерировал автоматом.
Могу и тебе эту программу подогнать  :)
Было бы хорошо.  :)


UPD:
В CVehicleModelInfo.h некоторые функции объявлены как статические, например
Код: C++
  1. static void AddWheelUpgrade(int wheelSetNumber, int modelId);

при попытке определить такую функцию так
Код: C++
  1. // Converted from stdcall void CVehicleModelInfo::AddWheelUpgrade(int wheelSetNumber, int modelId) 0x4C8700
  2. void CVehicleModelInfo::AddWheelUpgrade(int wheelSetNumber, int modelId)
  3. {
  4.     ((void(__cdecl *)(CVehicleModelInfo*, int, int))0x4C8700)(this, wheelSetNumber, modelId);
  5. }

выходит "оператор this можно использовать только внутри не статической функции-члена"
Убрать static или как определять эту функцию?

И ещё просьба пояснить момент с определением __cdecl или __thiscall
IDA верно определяет этот момент или не всегда? Как самому в этом разобраться?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 09, 2016, 10:40:56 am
В CVehicleModelInfo.h некоторые функции объявлены как статические, например

выходит "оператор this можно использовать только внутри не статической функции-члена"

Всё верно. Статическая функция - это обычно __cdecl, а не __thiscall, и там this (указатель на обьект класса) не нужен.
Статическая функция не привязана к обьекту, она является общей для всех обьектов.
http://ru.stackoverflow.com/a/373738 (http://ru.stackoverflow.com/a/373738)
Убрать static или как определять эту функцию?

Нет. Надо вызывать как __cdecl, без передачи this (CVehicleModelInfo*)
И ещё просьба пояснить момент с определением __cdecl или __thiscall
IDA верно определяет этот момент или не всегда?

Почти всегда - верно.
Если у функции соглашение вызова __thiscall - это нестатический метод какого-то класса.
Если у функции соглашение вызова __cdecl - это либо не член класса, либо статический метод какого-то класса.
Код: C++
  1. void Func(){} // __cdecl
  2.  
  3. class A {
  4.     A() {} // thiscall
  5.     ~A() {} // thiscall
  6.     void SomeMethod() {} // thiscall
  7.     static void SomeStaticMethod() {} // cdecl
  8. };
Как самому в этом разобраться?

1. В первую очеред смотреть, что выдает декомпилятор.
2. Можно также глянуть в ассемблерный код. this всегда передается в регистре ecx, т.е. перед вызовом функции в ecx должен быть указатель на экземпляр класса.
Также, thiscall всегда сам за собой "чистит" стек. Если в thiscall-метод передается 1 параметр (кроме this), то при возврате функции, вместо обычного retn, будет такой опкод:
Код: C++
  1. retn 4 // Смещаем стек на 1 параметр (1 параметр = 4 байта)

_cheatWeaponSet
(http://i.imgur.com/CF4EQTK.png)

CPed::GiveWeapon
(http://i.imgur.com/HRR78Yf.png)

https://sannybuilder.com/forums/viewtopic.php?id=159 (https://sannybuilder.com/forums/viewtopic.php?id=159)

3. Обычно из названия функции можно понять - работает ли она с конкретным экземпляром класса, или является "общей".
Например,
Код: C++
  1. CPed::GiveWeapon - скорее всего, нестатический метод
  2. CPed::InitAllPeds - скорее всего, статический метод

Ко второму пункту я обращаюсь только в редких случаях.

PS Нашёл ещё одну познавательную статью от listener'а
https://sannybuilder.com/forums/viewtopic.php?id=845 (https://sannybuilder.com/forums/viewtopic.php?id=845)

UPD:
Кстати, обрати внимание, что в примерах, которые я показываю, я обьявляю функции внутри классов как статические. Это делается, потому что в "Эвенты" нельзя передавать thiscall-функции.
Код: C++
  1. class Test {
  2.     static void GameProcess() { // __cdecl
  3.         /*
  4.         Из статического метода мы не имеем доступа к нестатическим функциям/переменным
  5.         ...
  6.         */
  7.         value = 0;
  8.         value = GetRandomValue();
  9.     }
  10.  
  11.     static int value; // поэтому переменные, которые мы хочем использовать в GameProcess(), мы обьявляем тоже как статические
  12.     static int GetRandomValue() { return rand(); } // это же касается и функций.
  13.  
  14.     Test() {
  15.         Events::gameProcessEvent += GameProcess;
  16.     }
  17. } test;
  18.  
  19. int Test::value;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 09, 2016, 02:37:48 pm
Спасибо за пояснения.
Определил все функции, что были объявлены в CVehicleModelInfo.h
и добавил ещё
Код: C++
  1. int GetNumDoors();

Просьба проверить верно ли я понял вышеизложенное
Код: C++
  1. #include "CVehicleModelInfo.h"
  2.  
  3. RwTexture *CVehicleModelInfo::ms_pRemapTexture = (RwTexture *)0xB4E47C;
  4. RwTexture *CVehicleModelInfo::ms_pLightsTexture = (RwTexture *)0xB4E68C;
  5. RwTexture *CVehicleModelInfo::ms_pLightsOnTexture = (RwTexture *)0xB4E690;
  6. unsigned char *CVehicleModelInfo::ms_currentCol = (unsigned char *)0xB4E3F0;
  7. CRGBA *CVehicleModelInfo::ms_vehicleColourTable = (CRGBA *)0xB4E480;
  8.  
  9. void CVehicleModelInfo::ShutdownLightTexture()
  10. {
  11.     ((void(__cdecl *)())0x4C7470)();
  12. }
  13.  
  14. RwTexture * CVehicleModelInfo::FindTextureCB(char const * name)
  15. {
  16.     return ((RwTexture* (__cdecl *)(char const*))0x4C7510)(name);
  17. }
  18.  
  19. void CVehicleModelInfo::UseCommonVehicleTexDicationary()
  20. {
  21.     ((void(__cdecl *)())0x4C75A0)();
  22. }
  23.  
  24. void CVehicleModelInfo::StopUsingCommonVehicleTexDicationary()
  25. {
  26.     ((void(__cdecl *)())0x4C75C0)();
  27. }
  28.  
  29. RpAtomic * CVehicleModelInfo::MoveObjectsCB(RwObject * object, void * data)
  30. {
  31.     return ((RpAtomic* (__cdecl *)(RwObject*, void*))0x4C7700)(object, data);
  32. }
  33.  
  34. RpAtomic * CVehicleModelInfo::HideDamagedAtomicCB(RpAtomic * atomic, void * data)
  35. {
  36.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C7720)(atomic, data);
  37. }
  38.  
  39. RpAtomic * CVehicleModelInfo::HideAllComponentsAtomicCB(RpAtomic * atomic, void * data)
  40. {
  41.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C7790)(atomic, data);
  42. }
  43.  
  44. RpMaterial * CVehicleModelInfo::HasAlphaMaterialCB(RpMaterial * material, void * data)
  45. {
  46.     return ((RpMaterial* (__cdecl *)(RpMaterial*, void*))0x4C77C0)(material, data);
  47. }
  48.  
  49. RpAtomic * CVehicleModelInfo::SetAtomicRendererCB(RpAtomic * atomic, void * data)
  50. {
  51.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C77E0)(atomic, data);
  52. }
  53.  
  54. RpAtomic * CVehicleModelInfo::SetAtomicRendererCB_RealHeli(RpAtomic * atomic, void * data)
  55. {
  56.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C7870)(atomic, data);
  57. }
  58.  
  59. RpAtomic * CVehicleModelInfo::SetAtomicRendererCB_Plane(RpAtomic * atomic, void * data)
  60. {
  61.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C7930)(atomic, data);
  62. }
  63.  
  64. RpAtomic * CVehicleModelInfo::SetAtomicRendererCB_Boat(RpAtomic * atomic, void * data)
  65. {
  66.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C79A0)(atomic, data);
  67. }
  68.  
  69. RpAtomic * CVehicleModelInfo::SetAtomicRendererCB_Heli(RpAtomic * atomic, void * data)
  70. {
  71.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C7A30)(atomic, data);
  72. }
  73.  
  74. RpAtomic * CVehicleModelInfo::SetAtomicRendererCB_Train(RpAtomic * atomic, void * data)
  75. {
  76.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C7AA0)(atomic, data);
  77. }
  78.  
  79. void CVehicleModelInfo::SetAtomicRenderCallbacks()
  80. {
  81.     ((void(__thiscall *)(CVehicleModelInfo*))0x4C7B10)(this);
  82. }
  83.  
  84. RwObject * CVehicleModelInfo::SetAtomicFlagCB(RwObject * object, void * data)
  85. {
  86.     return ((RwObject* (__cdecl *)(RwObject*, void*))0x4C7B90)(object, data);
  87. }
  88.  
  89. // Converted from stdcall RwObject* CVehicleModelInfo::ClearAtomicFlagCB(RwObject *object, void *data) 0x4C7BB0
  90. RwObject* CVehicleModelInfo::ClearAtomicFlagCB(RwObject* object, void* data)
  91. {
  92.     return ((RwObject* (__cdecl *)(RwObject*, void*))0x4C7BB0)(object, data);
  93. }
  94.  
  95. // Converted from thiscall void CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *component, unsigned int flags) 0x4C7C10
  96. void CVehicleModelInfo::SetVehicleComponentFlags(RwFrame* component, unsigned int flags)
  97. {
  98.     ((void(__thiscall *)(CVehicleModelInfo*, RwFrame*, unsigned int))0x4C7C10)(this, component, flags);
  99. }
  100.  
  101. // Converted from thiscall void CVehicleModelInfo::GetWheelPosn(int wheel, CVector &outVec, bool local) 0x4C7D20
  102. void CVehicleModelInfo::GetWheelPosn(int wheel, CVector& outVec, bool local)
  103. {
  104.     ((void(__thiscall *)(CVehicleModelInfo*, CVector&, bool))0x4C7D20)(this, outVec, local);
  105. }
  106.  
  107. // Converted from thiscall bool CVehicleModelInfo::GetOriginalCompPosition(CVector &outVec, int component) 0x4C7DD0
  108. bool CVehicleModelInfo::GetOriginalCompPosition(CVector& outVec, int component)
  109. {
  110.     return ((bool(__thiscall *)(CVehicleModelInfo*, CVector&, int))0x4C7DD0)(this, outVec, component);
  111. }
  112.  
  113. // Converted from thiscall int CVehicleModelInfo::ChooseComponent(void) 0x4C8040
  114. int CVehicleModelInfo::ChooseComponent()
  115. {
  116.     return ((int(__thiscall *)(CVehicleModelInfo*))0x4C8040)(this);
  117. }
  118.  
  119. // Converted from thiscall int CVehicleModelInfo::ChooseSecondComponent(void) 0x4C8120
  120. int CVehicleModelInfo::ChooseSecondComponent()
  121. {
  122.     return ((int(__thiscall *)(CVehicleModelInfo*))0x4C8120)(this);
  123. }
  124.  
  125. // Converted from thiscall bool CVehicleModelInfo::IsUpgradeAvailable(VehicleUpgradePosn upgrade) 0x4C8200
  126. bool CVehicleModelInfo::IsUpgradeAvailable(VehicleUpgradePosn upgrade)
  127. {
  128.     return ((bool(__thiscall *)(CVehicleModelInfo*, VehicleUpgradePosn))0x4C8200)(this, upgrade);
  129. }
  130.  
  131. RpMaterial * CVehicleModelInfo::SetEditableMaterialsCB(RpMaterial * material, void * data)
  132. {
  133.     return ((RpMaterial* (__cdecl *)(RpMaterial*, void*))0x4C8220)(material, data);
  134. }
  135.  
  136. RpAtomic * CVehicleModelInfo::SetEditableMaterialsCB(RpAtomic * atomic, void * data)
  137. {
  138.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C83E0)(atomic, data);
  139. }
  140.  
  141. // Converted from stdcall void CVehicleModelInfo::SetEditableMaterials(RpClump *clump) 0x4C8430
  142. void CVehicleModelInfo::SetEditableMaterials(RpClump* clump)
  143. {
  144.     ((void(__cdecl *)(RpClump*))0x4C8430)(clump);
  145. }
  146.  
  147. // Converted from stdcall void CVehicleModelInfo::ResetEditableMaterials(RpClump *clump) 0x4C8460
  148. void CVehicleModelInfo::ResetEditableMaterials(RpClump* clump)
  149. {
  150.     ((void(__cdecl *)(RpClump*))0x4C8460)(clump);
  151. }
  152.  
  153. // Converted from thiscall void CVehicleModelInfo::SetVehicleColour(unsigned char prim, unsigned char sec, unsigned char tert, unsigned char quat) 0x4C84B0
  154. void CVehicleModelInfo::SetVehicleColour(unsigned char prim, unsigned char sec, unsigned char tert, unsigned char quat)
  155. {
  156.     ((void(__thiscall *)(CVehicleModelInfo*, unsigned char, unsigned char, unsigned char, unsigned char))0x4C84B0)(this, prim, sec, tert, quat);
  157. }
  158.  
  159. // Converted from thiscall void CVehicleModelInfo::ChooseVehicleColour(unsigned char &prim, unsigned char &sec, unsigned char &tert, unsigned char &quat, int variationShift) 0x4C8500
  160. void CVehicleModelInfo::ChooseVehicleColour(unsigned char& prim, unsigned char& sec, unsigned char& tert, unsigned char& quat, int variationShift)
  161. {
  162.     ((void(__thiscall *)(CVehicleModelInfo*, unsigned char&, unsigned char&, unsigned char&, unsigned char&, int))0x4C8500)(this, prim, sec, tert, quat, variationShift);
  163. }
  164.  
  165. // Converted from thiscall int CVehicleModelInfo::GetNumRemaps(void) 0x4C86B0
  166. int CVehicleModelInfo::GetNumRemaps()
  167. {
  168.     return ((int(__thiscall *)(CVehicleModelInfo*))0x4C86B0)(this);
  169. }
  170.  
  171. // Converted from thiscall void CVehicleModelInfo::AddRemap(int txd) 0x4C86D0
  172. void CVehicleModelInfo::AddRemap(int txd)
  173. {
  174.     ((void(__thiscall *)(CVehicleModelInfo*, int))0x4C86D0)(this, txd);
  175. }
  176.  
  177. // Converted from stdcall void CVehicleModelInfo::AddWheelUpgrade(int wheelSetNumber, int modelId) 0x4C8700
  178. void CVehicleModelInfo::AddWheelUpgrade(int wheelSetNumber, int modelId)
  179. {
  180.     ((void(__cdecl *)(int, int))0x4C8700)(wheelSetNumber, modelId);
  181. }
  182.  
  183. int CVehicleModelInfo::GetNumWheelUpgrades(int wheelSetNumber)
  184. {
  185.     return ((int(__cdecl *)(int))0x4C8740)(wheelSetNumber);
  186. }
  187.  
  188. void CVehicleModelInfo::GetWheelUpgrade(int wheelSetNumber, int wheelUpgradeNumber)
  189. {
  190.     ((void(__cdecl *)(int, int))0x4C8750)(wheelSetNumber, wheelUpgradeNumber);
  191. }
  192.  
  193. void CVehicleModelInfo::DeleteVehicleColourTextures()
  194. {
  195.     ((void(__cdecl *)())0x4C8770)();
  196. }
  197.  
  198. void CVehicleModelInfo::LoadEnvironmentMaps()
  199. {
  200.     ((void(__cdecl *)())0x4C8780)();
  201. }
  202.  
  203. void CVehicleModelInfo::ShutdownEnvironmentMaps()
  204. {
  205.     ((void(__cdecl *)())0x4C87D0)();
  206. }
  207.  
  208. RpMaterial* CVehicleModelInfo::GetMatFXEffectMaterialCB(RpMaterial* material, void* data)
  209. {
  210.     return ((RpMaterial* (__cdecl *)(RpMaterial*, void*))0x4C8810)(material, data);
  211. }
  212.  
  213. RpMaterial* CVehicleModelInfo::SetEnvironmentMapCB(RpMaterial* material, void* data)
  214. {
  215.     return ((RpMaterial* (__cdecl *)(RpMaterial*, void*))0x4C8840)(material, data);
  216. }
  217.  
  218. RpMaterial* CVehicleModelInfo::SetEnvMapCoeffCB(RpMaterial* material, void* data)
  219. {
  220.     return ((RpMaterial* (__cdecl *)(RpMaterial*, void*))0x4C88B0)(material, data);
  221. }
  222.  
  223. RpAtomic* CVehicleModelInfo::SetRenderPipelinesCB(RpAtomic* atomic, void* data)
  224. {
  225.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C88F4)(atomic, data);
  226. }
  227.  
  228. void CVehicleModelInfo::SetRenderPipelines()
  229. {
  230.     ((void(__thiscall *)(CVehicleModelInfo*))0x4C8900)(this);
  231. }
  232.  
  233. char* CVehicleModelInfo::GetCustomCarPlateText()
  234. {
  235.     return ((char*(__thiscall *)(CVehicleModelInfo*))0x4C8970)(this);
  236. }
  237.  
  238. void CVehicleModelInfo::SetCustomCarPlateText(char* text)
  239. {
  240.     ((void(__thiscall *)(CVehicleModelInfo*, char*))0x4C8980)(this, text);
  241. }
  242.  
  243. int CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(int modelId)
  244. {
  245.     return ((int(__cdecl *)(int))0x4C89B0)(modelId);
  246. }
  247.  
  248. void CVehicleModelInfo::ReduceMaterialsInVehicle()
  249. {
  250.     ((void(__thiscall *)(CVehicleModelInfo*))0x4C8BD0)(this);
  251. }
  252.  
  253. void CVehicleModelInfo::SetupLightFlags(CVehicle* vehicle)
  254. {
  255.     ((void(__thiscall *)(CVehicleModelInfo*, CVehicle*))0x4C8C90)(this, vehicle);
  256. }
  257.  
  258. RwFrame* CVehicleModelInfo::CollapseFramesCB(RwFrame* frame, void* data)
  259. {
  260.     return ((RwFrame* (__cdecl *)(RwFrame*, void*))0x4C8E30)(frame, data);
  261. }
  262.  
  263. void CVehicleModelInfo::PreprocessHierarchy()
  264. {
  265.     ((void(__thiscall *)(CVehicleModelInfo*))0x4C8E60)(this);
  266. }
  267.  
  268. RpAtomic* CVehicleModelInfo::SetEnvironmentMapAtomicCB(RpAtomic* atomic, void* data)
  269. {
  270.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C9410)(atomic, data);
  271. }
  272.  
  273. RpAtomic * CVehicleModelInfo::SetEnvMapCoeffAtomicCB(RpAtomic * atomic, void * data)
  274. {
  275.     return ((RpAtomic* (__cdecl *)(RpAtomic*, void*))0x4C9430)(atomic, data);
  276. }
  277.  
  278. void CVehicleModelInfo::SetCarCustomPlate()
  279. {
  280.     ((void(__thiscall *)(CVehicleModelInfo*))0x4C9450)(this);
  281. }
  282.  
  283. void CVehicleModelInfo::DisableEnvMap()
  284. {
  285.     ((void(__thiscall *)(CVehicleModelInfo*))0x4C97E0)(this);
  286. }
  287.  
  288. void CVehicleModelInfo::SetEnvMapCoeff(float coeff)
  289. {
  290.     ((void(__thiscall *)(CVehicleModelInfo*, float))0x4C9800)(this, coeff);
  291. }
  292.  
  293. int CVehicleModelInfo::GetNumDoors()
  294. {
  295.     return ((int(__thiscall *)(CVehicleModelInfo*))0x4C73C0)(this);
  296. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 14, 2016, 07:19:03 pm
Набросал код для цепляния прицепов к тягачам в трафике.
Есть вопрос по экстрам.
Надо считать с тягача установленные экстры и потом на модель прицепа установить такие же. понял, что считать уже установленные экстры на транспорте можно так:
Код: C++
  1. vehicle->m_anExtras[0]
  2. vehicle->m_anExtras[1]

А вот как установить эти номера экстр на модель перед созданием транспорта не понял. Нашёл в CVehicleModelInfo это:
Код: C++
  1. // extras ids for next-spawned car
  2. // static char ms_compsUsed[2];
  3. static char *ms_compsUsed;

Но как применить не знаю. Просьба пояснить.

Ещё вопрос - как проверить в каком месте кода ошибка, если игра "вылетает"?

trailer.dat
Код: C++
  1. #A - Id tractor
  2. #B - Id trailer first variant
  3. #C - Id trailer second variant
  4. #D - Id trailer third variant  
  5. #E - Id trailer fourth variant
  6. #F - Colours of the trailer as at the tractor (0-no, 1-yes)
  7. #G - Extras at the trailer as at the tractor (0-no, 1-yes)
  8.  
  9. #A,   B,   C,   D,   E,  F, G
  10.  
  11. trailer
  12. 403, 435, 450, 584, 591, 0, 0
  13. 485, 606, 607, 607, 606, 0, 0
  14. 514, 584, 584, 584, 584, 0, 0
  15. 515, 435, 450, 584, 591, 0, 0
  16. 525, 400, 401, 402, 404, 0, 0
  17. end

Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <fstream>
  4. #include <string>
  5. #include "game_sa\CGeneral.h"
  6. #include "game_sa\CStreaming.h"
  7. #include "game_sa\CTrailer.h"
  8. #include "game_sa\CWorld.h"
  9. #include "game_sa\CTheScripts.h"
  10. #include "game_sa\CModelInfo.h"
  11.  
  12. using namespace plugin;
  13. using namespace std;
  14.  
  15. class MyPlugin {
  16. public:
  17.     class ModelInfo {
  18.     public:
  19.         bool enabledTrailer;
  20.         ModelInfo(CVehicle *vehicle) { enabledTrailer = true; }
  21.     };
  22.  
  23.     static VehicleExtendedData<ModelInfo> modelInfo;
  24.  
  25.     struct MyData {
  26.         unsigned int ModelId;
  27.         unsigned int TrailerIdOne;
  28.         unsigned int TrailerIdTwo;
  29.         unsigned int TrailerIdThree;
  30.         unsigned int TrailerIdFour;
  31.         unsigned int TrailerColours;
  32.         unsigned int TrailerExtras;
  33.     };
  34.  
  35.     static vector<MyData>& GetDataVector() {
  36.         static vector<MyData> vec;
  37.         return vec;
  38.     }
  39.  
  40.     static void ReadSettingsFile() {
  41.         ifstream stream("trailer.dat");
  42.         for (string line; getline(stream, line); ) {
  43.             if (line[0] != ';' && line[0] != '#') {
  44.                 if (!line.compare("trailer")) {
  45.                     while (getline(stream, line) && line.compare("end")) {
  46.                         if (line[0] != ';' && line[0] != '#') {
  47.                             MyData entry;
  48.                             if (sscanf(line.c_str(), "%d, %d, %d, %d, %d, %d, %d", &entry.ModelId, &entry.TrailerIdOne, &entry.TrailerIdTwo, &entry.TrailerIdThree, &entry.TrailerIdFour, &entry.TrailerColours, &entry.TrailerExtras) == 7)
  49.                                 GetDataVector().push_back(entry);
  50.                         }
  51.                     }
  52.                 }
  53.             }
  54.         }
  55.     }
  56.  
  57.     static MyData *GetDataInfoForModel(unsigned int BaseModelId) {
  58.         for (unsigned int i = 0; i < GetDataVector().size(); i++) {
  59.             if (GetDataVector()[i].ModelId == BaseModelId)
  60.                 return &GetDataVector()[i];
  61.         }
  62.         return nullptr;
  63.     }
  64.  
  65.     static void SetTrailer(CVehicle *vehicle, unsigned int modelTrailer, unsigned int colour, unsigned int extra) {
  66.         CStreaming::RequestModel(modelTrailer, 0);
  67.         CStreaming::LoadAllRequestedModels(false);
  68.         if (CStreaming::ms_aInfoForModel[modelTrailer].m_loadState == LOADSTATE_LOADED) {
  69.             if (extra) {
  70.                 ; // здесь надо считать установленные экстры с vehicle
  71.                   // vehicle->m_anExtras[0]
  72.                   // vehicle->m_anExtras[1]
  73.                   // и на модель прицепа modelTrailer установить такие же экстры
  74.             }
  75.             CVehicle *trailer = nullptr;
  76.             if (CModelInfo::IsVehicleModelType(modelTrailer) == 11)
  77.                 trailer = new CTrailer(modelTrailer, 1);
  78.             else                    
  79.                 trailer = new CAutomobile(modelTrailer, 1, true);
  80.             if (trailer) {
  81.                 trailer->SetPosn(0.0f, 0.0f, 0.0f);
  82.                 trailer->m_nStatus = 4;
  83.                 CWorld::Add(trailer);
  84.                 trailer->SetTowLink(vehicle, true);
  85.                 CTheScripts::ClearSpaceForMissionEntity(trailer->GetPosition(), trailer);
  86.                 if (colour) {
  87.                     trailer->m_nPrimaryColor = vehicle->m_nPrimaryColor;
  88.                     trailer->m_nSecondaryColor = vehicle->m_nSecondaryColor;
  89.                     trailer->m_nTertiaryColor = vehicle->m_nTertiaryColor;
  90.                     trailer->m_nQuaternaryColor = vehicle->m_nQuaternaryColor;
  91.                 }
  92.                 if (CModelInfo::IsVehicleModelType(modelTrailer) == 11) {
  93.                     trailer->m_nFlags.bEngineOn = 1;
  94.                     trailer->m_nFlags.bIsLocked = 1;
  95.                 }
  96.                 else {
  97.                     trailer->m_nFlags.bEngineOn = 0;
  98.                     trailer->m_dwDoorLock = CARLOCK_LOCKED;
  99.                 }
  100.                    
  101.             }
  102.         }
  103.     }
  104.    
  105.     MyPlugin() {
  106.         ReadSettingsFile();
  107.         static unsigned int TrailerId;
  108.  
  109.         Events::gameProcessEvent += [] {
  110.             for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  111.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  112.                 if (vehicle) {
  113.                     if (CModelInfo::IsVehicleModelType(vehicle->m_wModelIndex) == 11
  114.                         && vehicle->m_nFlags.bIsLocked == 1 && !vehicle->m_pTractor) {
  115.                         vehicle->m_nFlags.bIsLocked = 0;
  116.                         if (!vehicle->IsVisible())
  117.                             vehicle->CanBeDeleted();
  118.                     }
  119.                     MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
  120.                     if (entryModel) {
  121.                         switch (CGeneral::GetRandomNumberInRange(0, 4)) {
  122.                         case 0: TrailerId = entryModel->TrailerIdOne; break;
  123.                         case 1: TrailerId = entryModel->TrailerIdTwo; break;
  124.                         case 2: TrailerId = entryModel->TrailerIdThree; break;
  125.                         case 3: TrailerId = entryModel->TrailerIdFour; break;
  126.                         }
  127.                         ModelInfo &info = modelInfo.Get(vehicle);
  128.                         if (info.enabledTrailer && vehicle->m_pDriver && !vehicle->m_pTrailer
  129.                             && (CModelInfo::IsVehicleModelType(TrailerId) == 11 || CModelInfo::IsVehicleModelType(TrailerId) == 0)) {
  130.                             vehicle->m_nFlags.bMadDriver = 0;
  131.                             SetTrailer(vehicle, TrailerId, entryModel->TrailerColours, entryModel->TrailerExtras);
  132.                         }
  133.                         info.enabledTrailer = false;
  134.                     }
  135.                 }
  136.             }
  137.         };
  138.  
  139.     }
  140. } myPlugin;
  141.  
  142. VehicleExtendedData<MyPlugin::ModelInfo> MyPlugin::modelInfo;
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 14, 2016, 09:22:15 pm
По аналогии с опкодом 0506
Код: C++
  1. case COMMAND_SET_CAR_MODEL_COMPONENTS:
  2.     this->CollectParameters(3); // параметр №1 не используется
  3.     CVehicleModelInfo::ms_compsToUse[0] = ScriptParams[1].i;
  4.     CVehicleModelInfo::ms_compsToUse[1] = ScriptParams[2].i;
  5.     return OR_CONTINUE;
Когда именно вылетает (на загрузке или в процессе игры)?
Файл открывается, данные считываются?

По CVehicleModelInfo - вроде всё правильно у тебя  :P
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 15, 2016, 09:59:26 am
По аналогии с опкодом 0506
Код: C++
  1. case COMMAND_SET_CAR_MODEL_COMPONENTS:
  2.     this->CollectParameters(3); // параметр №1 не используется
  3.     CVehicleModelInfo::ms_compsToUse[0] = ScriptParams[1].i;
  4.     CVehicleModelInfo::ms_compsToUse[1] = ScriptParams[2].i;
  5.     return OR_CONTINUE;
Подключать надо CRunningScript? Что-то не получается у меня. Добавь пожалуйста в тот код, что я показал.

Когда именно вылетает (на загрузке или в процессе игры)?
Файл открывается, данные считываются?
Да файл открывает и данные считываются. Но я имел ввиду не этот конкретно код, а в общем.
Вылетает в процессе игры.
Для клео скриптов были SCMLog и SCRLog Plugin для помощи в поиске ошибок при вылете игры. А в случае с плагинами, как находить из-за какого плагина был вылет и в каком месте кода ошибка?

По CVehicleModelInfo - вроде всё правильно у тебя
Сделал коммит.

Как будет время напиши пожалуйста детально, как ты переносишь всё в sdk. Хорошо бы, по-возможности, ты добавил в sdk для VC все нужные файлы .h и .cpp с подключениями, а я наполнял бы эти файлы по аналогии с sdk для SA. Ну а где будут непонятки, буду спрашивать. Хоть понемногу будет работа по VC продвигаться.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 15, 2016, 04:39:26 pm
Подключать надо CRunningScript? Что-то не получается у меня. Добавь пожалуйста в тот код, что я показал.

Нет.
Код: C++
  1. CVehicleModelInfo::ms_compsToUse[0] = vehicle->m_anExtras[0];
  2. CVehicleModelInfo::ms_compsToUse[1] = vehicle->m_anExtras[1];

А в случае с плагинами, как находить из-за какого плагина был вылет и в каком месте кода ошибка?

Если ты точно знаешь, в каком плагине проблема - собери его в Debug-режиме (важно, чтобы была включена генерация полной отладочной информации)
(http://i.imgur.com/yhaeC0t.png)
После вылета в диалоговом окне Windows нажми "отладка" и выбери дебаггер Visual Studio.
Если вылет происходит в "теле" плагина, ты сможешь увидеть строку, на которой происходит вылет.
Хотя, конечно, вылет может произойти и в коде игры, или даже в другом плагине/другой библиотеке.
Тогда нужно анализировать ассемблерный код (т.к. у нас нету исходников игры и/или других библиотек).

https://drive.google.com/file/d/0B3pQzS44FafdNm13bFdpVXVsNDg/view?usp=sharing (https://drive.google.com/file/d/0B3pQzS44FafdNm13bFdpVXVsNDg/view?usp=sharing)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 16, 2016, 10:00:01 am
Что-то я с этими экстрами запутался.  :(
В CVehicleModelInfo нет ms_compsToUse, есть
Код: C++
  1. // extras ids for next-spawned car
  2. // static char ms_compsUsed[2];
  3. static char *ms_compsUsed;

Сделал так

Код: C++
  1. static void SetTrailer(CVehicle *vehicle, unsigned int modelTrailer, unsigned int colour, unsigned int extra) {
  2.     CStreaming::RequestModel(modelTrailer, 0);
  3.     CStreaming::LoadAllRequestedModels(false);
  4.     if (CStreaming::ms_aInfoForModel[modelTrailer].m_loadState == LOADSTATE_LOADED) {
  5.         if (extra) {
  6.             CVehicleModelInfo::ms_compsUsed[0] = vehicle->m_anExtras[0];
  7.             CVehicleModelInfo::ms_compsUsed[1] = vehicle->m_anExtras[1];
  8.         }
  9.         CVehicle *trailer = nullptr;
  10.         if (CModelInfo::IsVehicleModelType(modelTrailer) == 11)
  11.             trailer = new CTrailer(modelTrailer, 1);
  12.         else
  13.             trailer = new CAutomobile(modelTrailer, 1, true);
  14.         if (trailer) {
  15.             trailer->SetPosn(0.0f, 0.0f, 0.0f);
  16.             trailer->m_nStatus = 4;
  17.             CWorld::Add(trailer);
  18.             trailer->SetTowLink(vehicle, true);
  19.             CTheScripts::ClearSpaceForMissionEntity(trailer->GetPosition(), trailer);
  20.             if (colour) {
  21.                 trailer->m_nPrimaryColor = vehicle->m_nPrimaryColor;
  22.                 trailer->m_nSecondaryColor = vehicle->m_nSecondaryColor;
  23.                 trailer->m_nTertiaryColor = vehicle->m_nTertiaryColor;
  24.                 trailer->m_nQuaternaryColor = vehicle->m_nQuaternaryColor;
  25.             }
  26.             if (CModelInfo::IsVehicleModelType(modelTrailer) == 11) {
  27.                 trailer->m_nFlags.bEngineOn = 1;
  28.                 trailer->m_nFlags.bIsLocked = 1;
  29.             }
  30.             else {
  31.                 trailer->m_nFlags.bEngineOn = 0;
  32.                 trailer->m_dwDoorLock = CARLOCK_LOCKED;
  33.             }
  34.  
  35.         }
  36.     }
  37. }


но студия ругается
Цитировать
1>------ Перестроение всех файлов начато: проект: TankerTruck, Конфигурация: Rel-XP Win32 ------
1>  Main.cpp
1>Main.obj : error LNK2001: неразрешенный внешний символ ""public: static char * CVehicleModelInfo::ms_compsUsed" (?ms_compsUsed@CVehicleModelInfo@@2PADA)"
1>D:\Games\GTA San Andreas\scripts\TankerTruck.asi : fatal error LNK1120: неразрешенных внешних элементов: 1
========== Перестроение всех проектов: успешно: 0, с ошибками: 1, пропущено: 0 ==========


В показанных ранее примерах в этих строчках
Код: C++
  1. CallMethod<NoRet, 0x506EA0, unsigned int, int, float, float>(0xB6BC90, audioEventId, volume, speed);
  2. Call<NoRet, 0x486B00, CVector const&, CEntity *>(trailer->GetPosition(), trailer);

теперь подчёркиваются красным
Call<NoRet и CallMethod<NoRet
Студия ругается, что идентификатор не определён и отсутствуют экземпляры шаблон функции...
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 16, 2016, 10:39:21 am
но студия ругается
Надо определить эти переменные в CVehicleModelInfo.cpp.

В показанных ранее примерах в этих строчках
Код: C++
  1. CallMethod<NoRet, 0x506EA0, unsigned int, int, float, float>(0xB6BC90, audioEventId, volume, speed);
  2. Call<NoRet, 0x486B00, CVector const&, CEntity *>(trailer->GetPosition(), trailer);

теперь подчёркиваются красным
Call<NoRet и CallMethod<NoRet
Студия ругается, что идентификатор не определён и отсутствуют экземпляры шаблон функции...
Вызов 0x486B00 уже можно заменить на
Код: C++
  1. CTheScripts::ClearSpaceForMissionEntity
А 0x506EA0 переделать так:
Код: C++
  1. CallMethod<0x506EA0>(0xB6BC90, audioEventId, volume, speed);
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 16, 2016, 03:20:02 pm
Определил
Код: C++
  1. char *CVehicleModelInfo::ms_compsUsed = (char *)0xB4E478;
Но что-то не работает. Уже установленные экстры считываются верно, а вот установить на модель прицепа определённые экстры не получается. Они просто ставятся рандомно и с экстрами тягача не совпадают.
Пробовал вместо такой записи
Код: C++
  1. CVehicleModelInfo::ms_compsUsed[0] = vehicle->m_anExtras[0];
  2. CVehicleModelInfo::ms_compsUsed[1] = vehicle->m_anExtras[1];
записать так
Код: C++
  1. CVehicleModelInfo *vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[modelTrailer]);
  2. vehModel->ms_compsUsed[0] = vehicle->m_anExtras[0];
  3. vehModel->ms_compsUsed[1] = vehicle->m_anExtras[1];
но результат тот же.

Код: C++
  1. #include "plugin.h"
  2. #include <vector>
  3. #include <fstream>
  4. #include <string>
  5. #include "game_sa\CGeneral.h"
  6. #include "game_sa\CStreaming.h"
  7. #include "game_sa\CTrailer.h"
  8. #include "game_sa\CWorld.h"
  9. #include "game_sa\CTheScripts.h"
  10. #include "game_sa\CModelInfo.h"
  11.  
  12. using namespace plugin;
  13. using namespace std;
  14.  
  15. class MyPlugin {
  16. public:
  17.     class ModelInfo {
  18.     public:
  19.         bool enabledTrailer;
  20.         ModelInfo(CVehicle *vehicle) { enabledTrailer = true; }
  21.     };
  22.  
  23.     static VehicleExtendedData<ModelInfo> modelInfo;
  24.  
  25.     struct MyData {
  26.         unsigned int ModelId;
  27.         unsigned int TrailerIdOne;
  28.         unsigned int TrailerIdTwo;
  29.         unsigned int TrailerIdThree;
  30.         unsigned int TrailerIdFour;
  31.         unsigned int TrailerColours;
  32.         unsigned int TrailerExtras;
  33.     };
  34.  
  35.     static vector<MyData>& GetDataVector() {
  36.         static vector<MyData> vec;
  37.         return vec;
  38.     }
  39.  
  40.     static void ReadSettingsFile() {
  41.         ifstream stream("trailer.dat");
  42.         for (string line; getline(stream, line); ) {
  43.             if (line[0] != ';' && line[0] != '#') {
  44.                 if (!line.compare("trailer")) {
  45.                     while (getline(stream, line) && line.compare("end")) {
  46.                         if (line[0] != ';' && line[0] != '#') {
  47.                             MyData entry;
  48.                             if (sscanf(line.c_str(), "%d, %d, %d, %d, %d, %d, %d", &entry.ModelId, &entry.TrailerIdOne, &entry.TrailerIdTwo, &entry.TrailerIdThree, &entry.TrailerIdFour, &entry.TrailerColours, &entry.TrailerExtras) == 7)
  49.                                 GetDataVector().push_back(entry);
  50.                         }
  51.                     }
  52.                 }
  53.             }
  54.         }
  55.     }
  56.  
  57.     static MyData *GetDataInfoForModel(unsigned int BaseModelId) {
  58.         for (unsigned int i = 0; i < GetDataVector().size(); i++) {
  59.             if (GetDataVector()[i].ModelId == BaseModelId)
  60.                 return &GetDataVector()[i];
  61.         }
  62.         return nullptr;
  63.     }
  64.  
  65.     static void SetTrailer(CVehicle *vehicle, unsigned int modelTrailer, unsigned int colour, unsigned int extra) {
  66.         CStreaming::RequestModel(modelTrailer, 0);
  67.         CStreaming::LoadAllRequestedModels(false);
  68.         if (CStreaming::ms_aInfoForModel[modelTrailer].m_loadState == LOADSTATE_LOADED) {
  69.             if (extra) {
  70.                 CVehicleModelInfo::ms_compsUsed[0] = vehicle->m_anExtras[0];
  71.                 CVehicleModelInfo::ms_compsUsed[1] = vehicle->m_anExtras[1];
  72.             }
  73.             CVehicle *trailer = nullptr;
  74.             if (CModelInfo::IsVehicleModelType(modelTrailer) == 11)
  75.                 trailer = new CTrailer(modelTrailer, 1);
  76.             else                    
  77.                 trailer = new CAutomobile(modelTrailer, 1, true);
  78.             if (trailer) {
  79.                 trailer->SetPosn(0.0f, 0.0f, 0.0f);
  80.                 trailer->m_nStatus = 4;
  81.                 CWorld::Add(trailer);
  82.                 trailer->SetTowLink(vehicle, true);
  83.                 CTheScripts::ClearSpaceForMissionEntity(trailer->GetPosition(), trailer);
  84.                 if (colour) {
  85.                     trailer->m_nPrimaryColor = vehicle->m_nPrimaryColor;
  86.                     trailer->m_nSecondaryColor = vehicle->m_nSecondaryColor;
  87.                     trailer->m_nTertiaryColor = vehicle->m_nTertiaryColor;
  88.                     trailer->m_nQuaternaryColor = vehicle->m_nQuaternaryColor;
  89.                 }
  90.                 if (CModelInfo::IsVehicleModelType(modelTrailer) == 11) {
  91.                     trailer->m_nFlags.bEngineOn = 1;
  92.                     trailer->m_nFlags.bIsLocked = 1;
  93.                 }
  94.                 else {
  95.                     trailer->m_nFlags.bEngineOn = 0;
  96.                     trailer->m_dwDoorLock = CARLOCK_LOCKED;
  97.                 }
  98.                    
  99.             }
  100.         }
  101.     }
  102.    
  103.     MyPlugin() {
  104.         ReadSettingsFile();
  105.         static unsigned int TrailerId;
  106.  
  107.         Events::gameProcessEvent += [] {
  108.             for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  109.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  110.                 if (vehicle) {
  111.                     if (CModelInfo::IsVehicleModelType(vehicle->m_wModelIndex) == 11
  112.                         && vehicle->m_nFlags.bIsLocked == 1 && !vehicle->m_pTractor) {
  113.                         vehicle->m_nFlags.bIsLocked = 0;
  114.                         if (!vehicle->IsVisible())
  115.                             vehicle->CanBeDeleted();
  116.                     }
  117.                     MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
  118.                     if (entryModel) {
  119.                         switch (CGeneral::GetRandomNumberInRange(0, 4)) {
  120.                         case 0: TrailerId = entryModel->TrailerIdOne; break;
  121.                         case 1: TrailerId = entryModel->TrailerIdTwo; break;
  122.                         case 2: TrailerId = entryModel->TrailerIdThree; break;
  123.                         case 3: TrailerId = entryModel->TrailerIdFour; break;
  124.                         }
  125.                         ModelInfo &info = modelInfo.Get(vehicle);
  126.                         if (info.enabledTrailer && vehicle->m_pDriver && !vehicle->m_pTrailer
  127.                             && (CModelInfo::IsVehicleModelType(TrailerId) == 11 || CModelInfo::IsVehicleModelType(TrailerId) == 0)) {
  128.                             vehicle->m_nFlags.bMadDriver = 0;
  129.                             SetTrailer(vehicle, TrailerId, entryModel->TrailerColours, entryModel->TrailerExtras);
  130.                         }
  131.                         info.enabledTrailer = false;
  132.                     }
  133.                 }
  134.             }
  135.         };
  136.  
  137.     }
  138. } myPlugin;
  139.  
  140. VehicleExtendedData<MyPlugin::ModelInfo> MyPlugin::modelInfo;
  141.  

Что делать?  :(
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 16, 2016, 05:02:06 pm
Там есть 2 разные переменные, compsUsed и compsToUse.
Надо именно во второе записывать.
Код: C++
  1. 8A6458                             ; CVehicleModelInfo::ms_compsToUse

Код: C++
  1. static char *ms_compsToUse;

Код: C++
  1. char *CVehicleModelInfo::ms_compsToUse = (char *)0x8A6458;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 16, 2016, 06:29:01 pm
Там есть 2 разные переменные, compsUsed и compsToUse.
Надо именно во второе записывать.
Вот теперь всё отлично.  :) Спасибо!

UPD:
Дополнил код:

trailer.dat
Код: C++
  1. #A - Id tractor
  2. #B - Id trailer first variant
  3. #C - Id trailer second variant
  4. #D - Id trailer third variant  
  5. #E - Id trailer fourth variant
  6. #F - Colours of the trailer as at the tractor (0-no, 1-yes)
  7. #G - Extras at the trailer as at the tractor (0-no, 1-yes)
  8. #H - Trailer Constant (0-no, 1-yes)
  9.  
  10. #B,C,D,E - For trailers "towtruck" it is possible to write not only ID models, but also a model class.
  11. # 0-normal, 1-poorfamily, 2-richfamily, 3-executive, 4-worker (look a file vehicles.ide)
  12.  
  13. #A,   B,   C,   D,   E,  F, G, H
  14.  
  15. trailer
  16. 403, 435, 450, 584, 591, 0, 0, 0
  17. 485, 606, 607, 607, 606, 0, 0, 0
  18. 514, 584, 584, 584, 584, 0, 0, 1
  19. 515, 435, 450, 584, 591, 0, 0, 0
  20. 525, 400, 0,   1,   2,   0, 0, 1
  21. end

Код: C++
  1. #include <vector>
  2. #include <fstream>
  3. #include <string>
  4. #include "game_sa\CGeneral.h"
  5. #include "game_sa\CStreaming.h"
  6. #include "game_sa\CTrailer.h"
  7. #include "game_sa\CWorld.h"
  8. #include "game_sa\CTheScripts.h"
  9. #include "game_sa\CModelInfo.h"
  10. #include "game_sa\common.h"
  11.  
  12. using namespace plugin;
  13. using namespace std;
  14.  
  15. unsigned int normalModelIds[] = { 400, 418, 419, 440, 458, 466, 467, 475, 479, 482, 483, 489, 491, 496, 500, 505, 507,
  16. 518, 526, 529, 540, 543, 545, 546, 547, 550, 554, 580, 582, 585, 589, 600, 603, 604, 605 };
  17.  
  18. unsigned int poorfamilyModelIds[] = { 401, 404, 410, 412, 436, 439, 492, 516, 517, 527, 542, 549, 567, 575, 576 };
  19.  
  20. unsigned int richfamilyModelIds[] = { 405, 421, 426, 445, 474, 477, 535, 551, 558, 559, 560, 561, 562, 565, 566, 579, 587 };
  21.  
  22. unsigned int executiveModelIds[] = { 402, 409, 411, 415, 429, 434, 451, 480, 506, 533, 534, 536, 541, 555, 602 };
  23.  
  24. unsigned int workerModelIds[] = { 408, 413, 414, 422, 423, 455, 456, 478, 498, 499, 508, 524, 530, 578, 609 };
  25.  
  26. class MyPlugin {
  27. public:
  28.     class ModelInfo {
  29.     public:
  30.         bool enabledTrailer;
  31.         ModelInfo(CVehicle *vehicle) { enabledTrailer = true; }
  32.     };
  33.  
  34.     static VehicleExtendedData<ModelInfo> modelInfo;
  35.  
  36.     struct MyData {
  37.         unsigned int ModelId;
  38.         unsigned int TrailerIdOne;
  39.         unsigned int TrailerIdTwo;
  40.         unsigned int TrailerIdThree;
  41.         unsigned int TrailerIdFour;
  42.         unsigned int TrailerColours;
  43.         unsigned int TrailerExtras;
  44.         unsigned int TrailerConst;
  45.     };
  46.  
  47.     static vector<MyData>& GetDataVector() {
  48.         static vector<MyData> vec;
  49.         return vec;
  50.     }
  51.  
  52.     static void ReadSettingsFile() {
  53.         ifstream stream("trailer.dat");
  54.         for (string line; getline(stream, line); ) {
  55.             if (line[0] != ';' && line[0] != '#') {
  56.                 if (!line.compare("trailer")) {
  57.                     while (getline(stream, line) && line.compare("end")) {
  58.                         if (line[0] != ';' && line[0] != '#') {
  59.                             MyData entry;
  60.                             if (sscanf(line.c_str(), "%d, %d, %d, %d, %d, %d, %d, %d", &entry.ModelId, &entry.TrailerIdOne, &entry.TrailerIdTwo, &entry.TrailerIdThree, &entry.TrailerIdFour, &entry.TrailerColours, &entry.TrailerExtras, &entry.TrailerConst) == 8)
  61.                                 GetDataVector().push_back(entry);
  62.                         }
  63.                     }
  64.                 }
  65.             }
  66.         }
  67.     }
  68.  
  69.     static MyData *GetDataInfoForModel(unsigned int BaseModelId) {
  70.         for (unsigned int i = 0; i < GetDataVector().size(); i++) {
  71.             if (GetDataVector()[i].ModelId == BaseModelId)
  72.                 return &GetDataVector()[i];
  73.         }
  74.         return nullptr;
  75.     }
  76.  
  77.     static void SetTrailer(CVehicle *vehicle, unsigned int modelTrailer, unsigned int colour, unsigned int extra) {
  78.         CStreaming::RequestModel(modelTrailer, 0);
  79.         CStreaming::LoadAllRequestedModels(false);
  80.         if (CStreaming::ms_aInfoForModel[modelTrailer].m_loadState == LOADSTATE_LOADED) {
  81.             if (extra && vehicle) {
  82.                 CVehicleModelInfo::ms_compsToUse[0] = vehicle->m_anExtras[0];
  83.                 CVehicleModelInfo::ms_compsToUse[1] = vehicle->m_anExtras[1];
  84.             }
  85.             CVehicle *trailer = nullptr;
  86.             if (CModelInfo::IsVehicleModelType(modelTrailer) == 11)
  87.                 trailer = new CTrailer(modelTrailer, 1);
  88.             else
  89.                 trailer = new CAutomobile(modelTrailer, 1, true);
  90.             if (trailer) {
  91.                 trailer->SetPosn(0.0f, 0.0f, 0.0f);
  92.                 trailer->m_nStatus = 4;
  93.                 CWorld::Add(trailer);
  94.                 if (vehicle) {
  95.                     trailer->SetTowLink(vehicle, true);
  96.                     if (colour) {
  97.                         trailer->m_nPrimaryColor = vehicle->m_nPrimaryColor;
  98.                         trailer->m_nSecondaryColor = vehicle->m_nSecondaryColor;
  99.                         trailer->m_nTertiaryColor = vehicle->m_nTertiaryColor;
  100.                         trailer->m_nQuaternaryColor = vehicle->m_nQuaternaryColor;
  101.                     }
  102.                 }
  103.                 CTheScripts::ClearSpaceForMissionEntity(trailer->GetPosition(), trailer);
  104.                 if (CModelInfo::IsVehicleModelType(modelTrailer) == 11) {
  105.                     trailer->m_nFlags.bEngineOn = 1;
  106.                     trailer->m_nFlags.bIsLocked = 1;
  107.                 }
  108.                 else {
  109.                     trailer->m_nFlags.bEngineOn = 0;
  110.                     trailer->m_dwDoorLock = CARLOCK_LOCKED;
  111.                     CAutomobile *automobile = reinterpret_cast<CAutomobile *>(trailer);
  112.                     unsigned int perRandomDamage = CGeneral::GetRandomNumberInRange(0, 3);
  113.                     if(perRandomDamage == 2)
  114.                         automobile->SetTotalDamage(1);
  115.                     else if (perRandomDamage == 1)
  116.                         automobile->SetRandomDamage(1);
  117.                 }
  118.             }
  119.         }
  120.     }
  121.  
  122.     MyPlugin() {
  123.         ReadSettingsFile();
  124.         static unsigned int Id;
  125.         static unsigned int TrailerId;
  126.         static unsigned int currentVariant = 0;
  127.  
  128.         Events::gameProcessEvent += [] {
  129.             for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  130.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  131.                 if (vehicle) {
  132.                     if (vehicle->m_nFlags.bIsLocked == 1) {
  133.                         if (FindPlayerPed()) {
  134.                             if ((DistanceBetweenPoints(FindPlayerCoors(0), vehicle->GetPosition()) > 200.0f)) {
  135.                                 if (vehicle->m_pTrailer) {
  136.                                     vehicle->m_pTrailer->m_nFlags.bIsLocked = 0;
  137.                                     vehicle->m_pTrailer->CanBeDeleted();
  138.                                 }
  139.                                 vehicle->m_nFlags.bIsLocked = 0;
  140.                                 vehicle->CanBeDeleted();
  141.                             }
  142.                             else if (FindPlayerPed()->m_pVehicle == vehicle) {
  143.                                 if (vehicle->m_pTrailer)
  144.                                     vehicle->m_pTrailer->m_nFlags.bIsLocked = 0;
  145.                                 vehicle->m_nFlags.bIsLocked = 0;
  146.                             }
  147.                         }
  148.                     }
  149.                     MyData *entryModel = GetDataInfoForModel(vehicle->m_wModelIndex);
  150.                     ModelInfo &info = modelInfo.Get(vehicle);
  151.                     if (entryModel && info.enabledTrailer) {
  152.                         if (!entryModel->TrailerConst) {
  153.                             if (currentVariant < 2)
  154.                                 currentVariant += 1;
  155.                             else
  156.                                 currentVariant = 0;
  157.                             if (currentVariant == 2)
  158.                                 info.enabledTrailer = false;
  159.                         }
  160.                         switch (CGeneral::GetRandomNumberInRange(0, 4)) {
  161.                         case 0: Id = entryModel->TrailerIdOne; break;
  162.                         case 1: Id = entryModel->TrailerIdTwo; break;
  163.                         case 2: Id = entryModel->TrailerIdThree; break;
  164.                         case 3: Id = entryModel->TrailerIdFour; break;
  165.                         }
  166.                         switch (Id) {
  167.                             CVehicleModelInfo *vehModel;
  168.                             bool enabledExit;
  169.                         case 0: {
  170.                             enabledExit = false;
  171.                             do {
  172.                                 TrailerId = normalModelIds[CGeneral::GetRandomNumberInRange(0, 35)];
  173.                                 vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[TrailerId]);
  174.                                 if (CModelInfo::IsVehicleModelType(TrailerId) == 0 && vehModel->m_nClass == 0)
  175.                                     enabledExit = true;
  176.                             } while (!enabledExit);
  177.                             break;
  178.                         }
  179.                         case 1: {
  180.                             enabledExit = false;
  181.                             do {
  182.                                 TrailerId = poorfamilyModelIds[CGeneral::GetRandomNumberInRange(0, 15)];
  183.                                 vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[TrailerId]);
  184.                                 if (CModelInfo::IsVehicleModelType(TrailerId) == 0 && vehModel->m_nClass == 1)
  185.                                     enabledExit = true;
  186.                             } while (!enabledExit);
  187.                             break;
  188.                         }
  189.                         case 2: {
  190.                             enabledExit = false;
  191.                             do {
  192.                                 TrailerId = richfamilyModelIds[CGeneral::GetRandomNumberInRange(0, 17)];
  193.                                 vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[TrailerId]);
  194.                                 if (CModelInfo::IsVehicleModelType(TrailerId) == 0 && vehModel->m_nClass == 2)
  195.                                     enabledExit = true;
  196.                             } while (!enabledExit);
  197.                             break;
  198.                         }
  199.                         case 3: {
  200.                             enabledExit = false;
  201.                             do {
  202.                                 TrailerId = executiveModelIds[CGeneral::GetRandomNumberInRange(0, 15)];
  203.                                 vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[TrailerId]);
  204.                                 if (CModelInfo::IsVehicleModelType(TrailerId) == 0 && vehModel->m_nClass == 3)
  205.                                     enabledExit = true;
  206.                             } while (!enabledExit);
  207.                             break;
  208.                         }
  209.                         case 4: {
  210.                             enabledExit = false;
  211.                             do {
  212.                                 TrailerId = workerModelIds[CGeneral::GetRandomNumberInRange(0, 15)];
  213.                                 vehModel = reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[TrailerId]);
  214.                                 if (CModelInfo::IsVehicleModelType(TrailerId) == 0 && vehModel->m_nClass == 4)
  215.                                     enabledExit = true;
  216.                             } while (!enabledExit);
  217.                             break;
  218.                         }
  219.                         default: TrailerId = Id; break;
  220.                         }
  221.                         if (info.enabledTrailer && vehicle->m_pDriver && !vehicle->m_pTrailer
  222.                             && (CModelInfo::IsVehicleModelType(TrailerId) == 11 || CModelInfo::IsVehicleModelType(TrailerId) == 0)) {
  223.                             vehicle->m_nFlags.bMadDriver = 0;
  224.                             vehicle->m_nFlags.bIsLocked = 1;
  225.                             SetTrailer(vehicle, TrailerId, entryModel->TrailerColours, entryModel->TrailerExtras);
  226.                         }
  227.                     }
  228.                     info.enabledTrailer = false;
  229.                 }
  230.             }
  231.         };
  232.  
  233.     }
  234. } myPlugin;
  235.  
  236. VehicleExtendedData<MyPlugin::ModelInfo> MyPlugin::modelInfo;
  237.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 12, 2016, 10:57:11 am
В VC и SA вот эти функции несколько различаются:
Код: C++
  1. static void PrintString(float x, float y, char *text);
  2. static void PrintString(float x, float y, unsigned short* text);

Как для VC будет вывод текста? (вот эти строчки для SA):
Код: C++
  1. char text[16];
  2. sprintf(text, "gear %d", vehicle->m_nCurrentGear);
  3. CFont::PrintString(5.0f, 5.0f, text);
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 12, 2016, 02:19:07 pm
Там надо unsigned short поменять на wchar_t.
Обнови проект.

Код: C++
  1. wchar_t text[16];
  2. swprintf(text, L"gear %d", vehicle->m_nCurrentGear);
  3. CFont::PrintString(x, y, text);
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 12, 2016, 05:41:05 pm
Там надо unsigned short поменять на wchar_t.
Обнови проект.
Пришлось в настройках прописать _CRT_NON_CONFORMING_SWPRINTFS, иначе мой тестовый плагин не собирался.

А вот с этими строчками игра зависает.  >:(
Код: C++
  1. CFont::SetColor(CRGBA(255, 255, 255, 255));
  2. CFont::SetDropColor(CRGBA(0, 0, 0, 255));
Название: Re: Написание плагина. Настройка проекта
Отправлено: FrogByte от Ноябрь 12, 2016, 06:41:20 pm
А вот с этими строчками игра зависает.  >:(
Код: C++
  1. CFont::SetColor(CRGBA(255, 255, 255, 255));
  2. CFont::SetDropColor(CRGBA(0, 0, 0, 255));

Тоже когда-то мучился с этим, оказывается тип параметра не сходится с тем, что из названия(в коде игры функция принимает указатель на CRGBA, а в названии просто CRGBA).

Так должно работать:
Код: C++
  1. // Converted from cdecl void CFont::SetDropColor(CRGBA color) 0x54FF30
  2. void CFont::SetDropColor(CRGBA color) {
  3.     plugin::Call<0x54FF30, CRGBA *>(&color);
  4. }

Код: C++
  1. // Converted from cdecl void CFont::SetBackgroundColor(CRGBA color) 0x5500A0
  2. void CFont::SetBackgroundColor(CRGBA color) {
  3.     plugin::Call<0x5500A0, CRGBA *>(&color);
  4. }

Код: C++
  1. // Converted from cdecl void CFont::SetColor(CRGBA color) 0x550170
  2. void CFont::SetColor(CRGBA color) {
  3.     plugin::Call<0x550170, CRGBA *>(&color);
  4. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 13, 2016, 08:54:05 am
Так должно работать
Ага так работает, спасибо.  ;)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 16, 2016, 03:48:16 pm
Для VC можно эти строчки записать "более правильно"?

Код: C++
  1. char *name = GetFrameNodeName(frame);
  2. wchar_t text[32];
  3. swprintf(text, L"%hs", name);
  4. CFont::PrintString(offset->x, offset->y, text);
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 16, 2016, 07:38:46 pm
Код: C++
  1. wchar_t text[32];
  2. AsciiToUnicode(GetFrameNodeName(frame), text);
  3. CFont::PrintString(offset->x, offset->y, text);
Можно создать аналог функции GetFrameNodeName, который будет возвращать строку в Юникоде.
Или аналог PrintString, который будет принимать ASCII строку.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Апрель 14, 2017, 10:43:17 am
Разобрал для GTA 3 CFont https://github.com/DK22Pac/plugin-sdk/commit/f957a26bb64cd1258c2c4837ab9b42b6d9b70e84 (https://github.com/DK22Pac/plugin-sdk/commit/f957a26bb64cd1258c2c4837ab9b42b6d9b70e84)

Где-то есть ошибка, поскольку цвет тексту устанавливал белый (пробовал ставить и другие цвета), но выводится всегда так (чёрным)
(http://savepic.ru/13562456m.png) (http://savepic.ru/13562456.png)

Код: C++
  1. #include "plugin_III.h"
  2. #include "game_III\common.h"
  3. #include "game_III\CFont.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class MyPlugin {
  8. public:
  9.     MyPlugin() {
  10.         Events::drawingEvent += [] {
  11.             CVehicle *vehicle = FindPlayerVehicle();
  12.             if (vehicle) {
  13.                 CFont::SetScale(0.5f, 1.0f);
  14.                 CFont::SetColor(CRGBA(255, 255, 255, 255));
  15.                 CFont::SetJustifyOn();
  16.                 CFont::SetFontStyle(1);
  17.                 CFont::SetPropOn();
  18.                 CFont::SetWrapx(600.0f);
  19.                
  20.                 wchar_t text[32];
  21.                 swprintf(text, L"Current Gear %d", vehicle->m_nCurrentGear);
  22.                 CFont::PrintString(10.0f, 10.0f, text);
  23.                 swprintf(text, L"Gas Pedal %.1f", vehicle->m_fGasPedal);
  24.                 CFont::PrintString(10.0f, 30.0f, text);
  25.                 swprintf(text, L"Break Pedal %.1f", vehicle->m_fBreakPedal);
  26.                 CFont::PrintString(10.0f, 50.0f, text);
  27.             }
  28.         };
  29.     }
  30. } myPlugin;

Просьба подсказать в чём ошибка.
Название: Re: Написание плагина. Настройка проекта
Отправлено: mfisto от Апрель 14, 2017, 04:06:52 pm
Там есть косяк один древний, тебе надо выводить не 255, а чуть поменьше, тогда будет все в порядке.
Либо не 0. Короче, задавай что-то между 0 и 255 везде и в альфе тоже.
Название: Re: Написание плагина. Настройка проекта
Отправлено: ilufir от Апрель 14, 2017, 09:45:26 pm
Это даже не баг. Проблема в том, что этот шрифт - pager - черный всегда. Потому что это такая текстура.
Название: Re: Написание плагина. Настройка проекта
Отправлено: mfisto от Апрель 14, 2017, 10:27:39 pm
Тогда, наверняка, из-за этого. Я просто знаю, что если задавать цвет 0 0 0 (либо 255 255 255, просто забыл что вернее) какому-то шрифту (либо всем) то, он вообще пропадает. Вообщем, в scm-кодинге у меня по крайней мере было так для тройки.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Апрель 15, 2017, 12:25:31 pm
Проблема решилась сменой стиля
Код: C++
  1. CFont::SetFontStyle(0);
или
Код: C++
  1. CFont::SetFontStyle(2);
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 08, 2017, 06:59:52 am
Дмитрий, ранее в этой теме ты показывал пример, как заменить небольшую функцию на свою. Если функция большая, то такое сделать проблематично. Можно ли заменить подобным образом локальную функцию, т.е. часть большой функции? Интересует, например (GTA III) вот это дело - добавление моделей с возможностью выполнять миссию такси
.text:00446A93   loc_446A93:                             ; CODE XREF: CRunningScript::ProcessCommands700To799(int)+22j
.text:00446A93                                           ; DATA XREF: .data:off_5EF4D0o
.text:00446A93 0                 lea     eax, [edi+10h]  ; jumptable 004458C2 case 34
.text:00446A96 0                 mov     ecx, edi
.text:00446A98 0                 push    1
.text:00446A9A 0                 push    eax
.text:00446A9B 0                 call    _ZN14CRunningScript17CollectParametersEPjs ; CRunningScript::CollectParameters(uint *,short)
.text:00446AA0 0                 mov     ecx, ds:ScriptParams
.text:00446AA6 0                 xor     al, al
.text:00446AA8 0                 imul    ecx, 4Fh
.text:00446AAB 0                 mov     esi, ds:_ZN6CWorld7PlayersE[ecx*4] ; CWorld::Players
.text:00446AB2 0                 cmp     byte ptr [esi+314h], 0
.text:00446AB9 0                 jz      short loc_446ADC
.text:00446ABB 0                 mov     edx, [esi+310h]
.text:00446AC1 0                 movsx   ebx, word ptr [edx+5Ch]
.text:00446AC5 0                 cmp     ebx, 6Eh
.text:00446AC8 0                 jz      short loc_446ADA
.text:00446ACA 0                 cmp     ebx, 80h
.text:00446AD0 0                 jz      short loc_446ADA
.text:00446AD2 0                 cmp     ebx, 94h
.text:00446AD8 0                 jnz     short loc_446ADC


Код: C++
  1. case 0x2DEu:
  2.       CRunningScript::CollectParameters(a1, (CRunningScript *)(a1 + 16), (unsigned int *)1, v215);
  3.       flag = 0;
  4.       player = (CPlayerPed *)*(&CWorld::Players + 79 * ScriptParams);
  5.       if ( player->ped.m_bInVehicle )
  6.       {
  7.         modelIndex = *(_WORD *)(player->ped.m_pVehicle + offsetof(CEntity, m_nModelIndex));
  8.         if ( modelIndex == MODEL_TAXI || modelIndex == MODEL_CABBIE || modelIndex == MODEL_BORGNINE )
  9.           flag = 1;
  10.       }
  11.       CRunningScript::UpdateCompareFlag((CRunningScript *)v5, flag);
  12.       break;

Или тут проще "заменить" конкретные адреса
.text:00446AC5                  cmp     ebx, 6Eh
.text:00446ACA                  cmp     ebx, 80h
.text:00446AD2                  cmp     ebx, 94h

Просьба показать как это реализовать в sdk.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 10, 2017, 01:58:00 am
Конкретно этот случай - это опкод, и тут есть свои особенности.

Есть много вариантов, опишу основные.

1. Используя CLEO SDK, написать замену опкоду 02DE.
+ самый рациональный способ. Тебе надо заменить стандартный опкод - в CLEO SDK это продумано - ты используешь CLEO SDK.
+ чистый и понятный код.
обязательно наличие библиотеки CLEO 2.0 (или выше).
надо писать весь код опкода.

2. Заменить весь (или почти весь) код опкода.
Сделать вызов своей функции, с 0x446A93. Функция при этом должна быть обьявлена как fastcall (чтобы в ecx получить структуру скрипта (CRunningScript).
В этой функции пишем весь код опкода, от получения параметров (CollectParameters) до записи результата (UpdateCompareFlag).
Кусок с 0x446A98 по 0x446AE4 заполняем no-op'ами.
Код: C++
  1. void __fastcall OpcodePlayerDrivingTaxiVehicle(CRunningScript *script) {
  2.     script->CollectParameters(&script->m_nIp, 1);
  3.     bool isTaxiModel = false;
  4.     // ...
  5.     script->UpdateCompareFlag(isTaxiModel);
  6. }
  7.  
  8. ...
  9.  
  10. patch::RedirectCall(0x446A93, OpcodePlayerDrivingTaxiVehicle);
  11. patch::Nop(0x446A98, 0x4C); // или сделать jump на 0x446AE4
+ более-менее чистый и понятный код.
надо писать весь код опкода.

3. Внедрять свой код по конкретному адресу, и заменить кое-какой кусок опкода (тот, где идет проверка id).
Тут тоже много вариантов.

3.1. Путём патчинга видоизменяем код в exe.
Проверка id начинается тут: 0x446AC5. id у нас записан в регистре ebx. начиная с адреса 0x446AC5, мы можем видоизменить код, чтобы он выглядел так:
Код: C++
  1. push ebx
  2. call CheckIfTaxiModel
  3. jmp 0x446ADC
Но тут также важно проследить, чтобы после вызова функции CheckIfTaxiModel не изменился регистр edi (в этом регистре хранится структура CRunningScript). Если будут проблемы - можно также перед вызовом функции добавить pushad, а после - popad.
Функция CheckIfTaxiModel должна принимать один параметр и возвращать true/false. Соглашение вызова - stdcall (можно сделать cdecl, и добавить 'add esp, 4' после вызова).
Код: C++
  1. bool __stdcall CheckIfTaxiModel(int id) {
  2.     bool isTaxiModel = false;
  3.     // ...
  4.     return isTaxiModel;
  5. }
  6.  
  7. ...
  8.  
  9. patch::SetUChar(0x446AC5, 0x53); // команда 'push ebx'
  10. patch::RedirectCall(0x446AC6, CheckIfTaxiModel); // call
  11. patch::RedirectJump(0x446ACB, 0x446ADC); // jump
+ не надо переписывать код опкода полностью - напишем только функцию, которая сверяет id и возвращает результат.
часть кода будет не совсем "прозрачной", а его написание может вызвать трудности (по сути, надо будет продумывать запись ассемблерных инструкций).
надо следить за регистрами.

3.2. Пишем функцию - ассемблерный код.
Код: C++
  1. void __declspec(naked) MyHook_446AC5() { // инжект по адресу 0x446AC5, в ebx записан id модели
  2. __asm {
  3.     cmp ebx, 110
  4.     jz SET_TRUE
  5.     cmp ebx, 128
  6.     jz SET_TRUE
  7.     cmp ebx, 148
  8.     jz SET_TRUE
  9.     cmp ebx, <какой-то id>
  10.     jz SET_TRUE
  11.     jmp END_CHECK
  12. SET_TRUE:
  13.     mov al, 1
  14. END_CHECK:
  15.     mov ecx, 0x446ADC
  16.     jmp ecx
  17. }
  18. }
  19.  
  20. ...
  21.  
  22. patch::RedirectJump(0x446AC5, MyHook_446AC5);

+ не надо переписывать код опкода полностью - пишем только код, который сверяет id.
надо писать ассемблерный код.
в коде будет присутствовать ассемблерный код.

3.3. Новый вид инжекта в plugin-sdk
Код: C++
  1. void MyCheckIfTaxiModel(int modelId, bool &result) {
  2.     result = false;
  3.     // ...    
  4. }
  5.  
  6. ...
  7.  
  8. InstallHook<0x446AC5, 0x17, reg<ebx>, reg<eax&>>(MyCheckIfTaxiModel);
  9. //          точка внедрения
  10. //                    размер кода, который мы пропускаем
  11. //                          получаемые параметры
  12. //                          регистр ebx - id модели
  13. //                                    регистр eax - для записи (&)
пока что только в разработке.

PS То, что показано в пункте 3.3 - это, так скажем, "обертка" над тем, что показано в пункте 3.1.

PPS Вариант 3.1.
Код: C++
  1. #include "plugin_III.h"
  2. #include "extensions\ScriptCommands.h"
  3.  
  4. using namespace plugin;
  5. using namespace plugin::test;
  6.  
  7. class OpcodeTaxi {
  8. public:
  9.     static bool __stdcall CheckIfTaxiModel(int id) {
  10.         switch (id) {
  11.         case 110:
  12.         case 128:
  13.         case 148:
  14.         case 146:
  15.             return true;
  16.         }
  17.         return false;
  18.     }
  19.  
  20.     OpcodeTaxi() {
  21.         patch::SetUChar(0x446AC5, 0x53); // команда 'push ebx'
  22.         patch::RedirectCall(0x446AC6, CheckIfTaxiModel); // call
  23.         patch::RedirectJump(0x446ACB, reinterpret_cast<void *>(0x446ADC)); // jump
  24.  
  25.         Events::processScriptsEvent += [] {
  26.             if (ScriptCommand<IS_PLAYER_IN_TAXI>(0))
  27.                 ScriptCommand<PRINT_NOW>("FEC_INC", 150, 1);
  28.         };
  29.     }
  30. } myPlugin;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 10, 2017, 03:30:15 pm
Спасибо!
С учётом того, чтобы можно было добавить каждому свои модели изменил код так. Верно?
Код: C++
  1. #include "plugin_III.h"
  2. #include "extensions\ScriptCommands.h"
  3. #include <vector>
  4. #include <string>
  5. #include <sstream>
  6. #include <fstream>
  7. #include "game_III\common.h"
  8.  
  9. using namespace plugin;
  10. using namespace plugin::test;
  11. using namespace std;
  12.  
  13. vector<unsigned int> taxiIDs;
  14.  
  15. class OpcodeTaxi {
  16. public:
  17.    
  18.     static void ReadSettingsFile() {
  19.         ifstream stream("taxi.dat");
  20.         for (string line; getline(stream, line); ) {
  21.             if (line[0] != ';' && line[0] != '#') {
  22.                 if (!line.compare("taxi")) {
  23.                     while (line.compare("end") && getline(stream, line)) {
  24.                         if (line[0] != ';' && line[0] != '#') {
  25.                             stringstream ss(line);
  26.                             int i;
  27.                             while (ss >> i) {
  28.                                 taxiIDs.push_back(i);
  29.                                 if (ss.peek() == ',')
  30.                                     ss.ignore();
  31.                             }
  32.                         }
  33.                     }
  34.                 }
  35.             }
  36.         }
  37.     }
  38.  
  39.     static bool __stdcall CheckIfTaxiModel(unsigned int modelId) {
  40.         for (unsigned int i : taxiIDs) {
  41.             if (i == modelId)
  42.                 return true;
  43.         }
  44.         return false;
  45.     }
  46.  
  47.     OpcodeTaxi() {
  48.         ReadSettingsFile();
  49.         patch::SetUChar(0x446AC5, 0x53); // команда 'push ebx'
  50.         patch::RedirectCall(0x446AC6, CheckIfTaxiModel); // call
  51.         patch::RedirectJump(0x446ACB, reinterpret_cast<void *>(0x446ADC)); // jump
  52.  
  53.         Events::processScriptsEvent += [] {
  54.             CVehicle *vehicle = FindPlayerVehicle();
  55.             if (vehicle && vehicle->m_nVehicleSubType == VEHICLE_AUTOMOBILE) {
  56.                 CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  57.                 CheckIfTaxiModel(automobile->m_nModelIndex);
  58.             };
  59.            
  60.             // или так
  61.             /*for (int i = 0; i < CPools::ms_pVehiclePool->m_Size; i++) {
  62.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  63.                 if (vehicle && vehicle->m_nVehicleSubType == VEHICLE_AUTOMOBILE) {
  64.                     CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  65.                     CheckIfTaxiModel(automobile->m_nModelIndex);
  66.                 };
  67.             };*/
  68.         };
  69.     }
  70. } myPlugin;

Работает исправно, но огонёк такси не работает на добавленных моделях. Команда
Код: C++
  1. ScriptCommand<SET_TAXI_LIGHTS>(1);
не срабатывает даже на стандартных такси, хотя соответствующий опкод в клео скрипте на стандартных такси срабатывает, а на дополнительных меняется значение флага m_nTaxiLightFlag (CAutomobile+0x4D9), но огонька такси при этом нет.

Функции
Код: C++
  1. CAutomobile::SetTaxiLight
и
Код: C++
  1. CAutomobile::SetAllTaxiLights
тоже не срабатывают.

Там ещё после CAutomobile::SetAllTaxiLights есть такое дело
Код: C++
  1. case 0x220:
  2.       CRunningScript::CollectParameters(this, (CRunningScript *)(this + 16), (unsigned int *)1, (__int16)v206);
  3.       CPool_CVehicle_CAutomobile_GetAt(ScriptParams);
  4.       flag = 0;
  5.       if ( *(_BYTE *)(v101 + offsetof(CAutomobile, m_nTaxiLightFlag)) & 7 )
  6.         flag = 1;
  7.       CRunningScript::UpdateCompareFlag((CRunningScript *)v3, flag);
  8.       result = 0;
  9.       break;

Может это? Больше не знаю где искать.  :(

Как это исправить (чтобы огнёк такси работал на дополнительных такси)?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 10, 2017, 04:14:56 pm
Что-то я тебе не совсем понимаю.
CheckIfTaxiModel - это проверка. Зачем её вызывать таким образом?
Код: C++
  1.             CVehicle *vehicle = FindPlayerVehicle();
  2.             if (vehicle && vehicle->m_nVehicleSubType == VEHICLE_AUTOMOBILE) {
  3.                 CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  4.                 CheckIfTaxiModel(automobile->m_nModelIndex);
  5.             };
Код: C++
  1.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  2.                 if (vehicle && vehicle->m_nVehicleSubType == VEHICLE_AUTOMOBILE) {
  3.                     CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  4.                     CheckIfTaxiModel(automobile->m_nModelIndex);
  5.                 };

0220 - это опкод 0220:   car $car_handle has_car_bomb
В опкоде SET_TAXI_LIGHTS не один параметр, а два.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 10, 2017, 06:45:40 pm
Что-то я тебе не совсем понимаю.
CheckIfTaxiModel - это проверка. Зачем её вызывать таким образом?
А так?
Код: C++
  1. #include "plugin_III.h"
  2. #include "extensions\ScriptCommands.h"
  3. #include <vector>
  4. #include <string>
  5. #include <sstream>
  6. #include <fstream>
  7.  
  8. using namespace plugin;
  9. using namespace plugin::test;
  10. using namespace std;
  11.  
  12. vector<unsigned int> taxiIDs;
  13.  
  14. class OpcodeTaxi {
  15. public:
  16.    
  17.     static void ReadSettingsFile() {
  18.         ifstream stream("taxi.dat");
  19.         for (string line; getline(stream, line); ) {
  20.             if (line[0] != ';' && line[0] != '#') {
  21.                 if (!line.compare("taxi")) {
  22.                     while (line.compare("end") && getline(stream, line)) {
  23.                         if (line[0] != ';' && line[0] != '#') {
  24.                             stringstream ss(line);
  25.                             int i;
  26.                             while (ss >> i) {
  27.                                 taxiIDs.push_back(i);
  28.                                 if (ss.peek() == ',')
  29.                                     ss.ignore();
  30.                             }
  31.                         }
  32.                     }
  33.                 }
  34.             }
  35.         }
  36.     }
  37.  
  38.     static bool __stdcall CheckIfTaxiModel(unsigned int id) {
  39.         for (unsigned int i = 0; i < taxiIDs.size(); i++) {
  40.             id = taxiIDs[i];
  41.             return true;
  42.         }
  43.         return false;
  44.     }
  45.  
  46.     OpcodeTaxi() {
  47.         ReadSettingsFile();
  48.         patch::SetUChar(0x446AC5, 0x53); // команда 'push ebx'
  49.         patch::RedirectCall(0x446AC6, CheckIfTaxiModel); // call
  50.         patch::RedirectJump(0x446ACB, reinterpret_cast<void *>(0x446ADC)); // jump
  51.  
  52.     }
  53. } myPlugin;

В опкоде SET_TAXI_LIGHTS не один параметр, а два.
Код: C++
  1. ScriptCommand<SET_TAXI_LIGHTS>(automobile, 1);
Ошибка при компиляции. Если ставить vehicle - то же самое. Что я делаю не так? Подскажи пожалуйста.

И вопрос по рабочим огонькам дополнительных такси в силе. Где искать? Как реализовать?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 12, 2017, 03:38:21 pm
Ты понимаешь, как работает опкод IS_PLAYER_IN_TAXI ?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 12, 2017, 06:40:04 pm
Ты понимаешь, как работает опкод IS_PLAYER_IN_TAXI ?
Устанавливается флаг в ноль.
Проверяется игрок в авто или нет. Если в авто, то проверяется модель авто.
Если модель является MODEL_TAXI, MODEL_CABBIE или MODEL_BORGNINE, то флаг ставится в 1. Т.е. игрок в такси, иначе флаг остаётся 0, т.е. игрок не в такси.
Обновляется флаг.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 13, 2017, 09:56:28 am
Путаница произошла из-за невнимательности. Я почему-то пропустил это
Цитировать
Проверка id начинается тут: 0x446AC5. id у нас записан в регистре ebx. начиная с адреса 0x446AC5, мы можем видоизменить код
Прошу прощения за проявленные тормоза.  ;D

Получается значит так
Код: C++
  1. #include "plugin_III.h"
  2. #include "extensions\ScriptCommands.h"
  3. #include <vector>
  4. #include <string>
  5. #include <sstream>
  6. #include <fstream>
  7.  
  8. using namespace plugin;
  9. using namespace plugin::test;
  10. using namespace std;
  11.  
  12. vector<unsigned int> taxiIDs;
  13.  
  14. class OpcodeTaxi {
  15. public:
  16.    
  17.     static void ReadSettingsFile() {
  18.         ifstream stream("taxi.dat");
  19.         for (string line; getline(stream, line); ) {
  20.             if (line[0] != ';' && line[0] != '#') {
  21.                 if (!line.compare("taxi")) {
  22.                     while (line.compare("end") && getline(stream, line)) {
  23.                         if (line[0] != ';' && line[0] != '#') {
  24.                             stringstream ss(line);
  25.                             int i;
  26.                             while (ss >> i) {
  27.                                 taxiIDs.push_back(i);
  28.                                 if (ss.peek() == ',')
  29.                                     ss.ignore();
  30.                             }
  31.                         }
  32.                     }
  33.                 }
  34.             }
  35.         }
  36.     }
  37.  
  38.     static bool __stdcall CheckIfTaxiModel(unsigned int id) {
  39.         for (unsigned int i : taxiIDs) {
  40.             if (i == id)
  41.                 return true;
  42.         }
  43.         return false;
  44.     }
  45.  
  46.     OpcodeTaxi() {
  47.         ReadSettingsFile();
  48.         patch::SetUChar(0x446AC5, 0x53); // команда 'push ebx'
  49.         patch::RedirectCall(0x446AC6, CheckIfTaxiModel); // call
  50.         patch::RedirectJump(0x446ACB, reinterpret_cast<void *>(0x446ADC)); // jump
  51.     }
  52. } myPlugin;


По команде SET_TAXI_LIGHTS и нерабочим огонькам на добавленных такси вопрос остаётся.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 13, 2017, 02:53:48 pm
В опкод надо передавать хендл, а не указатель.
По "огонькам" - думаю, надо посмотреть в месте, где создается корона.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 13, 2017, 05:31:39 pm
В опкод надо передавать хендл, а не указатель.
Просьба показать пример, а то я сейчас опять наворочу чего попало, потом стыдно будет.  :(

По "огонькам" - думаю, надо посмотреть в месте, где создается корона.
В коронах я не нашёл. Но есть ещё опкод IS_TAXI. Может он на это влияет. Хотел сделать подобно показанному тобой примеру, но там id в eax, а номера для команды 'push eax' не знаю.
.text:00444CA5                 cmp     eax, 6Eh
.text:00444CA8                 jz      short loc_444CB8
.text:00444CAA                 cmp     eax, 80h
.text:00444CAF                 jz      short loc_444CB8
.text:00444CB1                 cmp     eax, 94h
.text:00444CB6                 jnz     short loc_444CBA
.text:00444CB8
.text:00444CB8 loc_444CB8:                             ; CODE XREF: CRunningScript::ProcessCommands600To699(int)+188j
.text:00444CB8                                         ; CRunningScript::ProcessCommands600To699(int)+18Fj
.text:00444CB8                 mov     dl, 1
.text:00444CBA
.text:00444CBA loc_444CBA:                             ; CODE XREF: CRunningScript::ProcessCommands600To699(int)+196j
.text:00444CBA                 mov     ecx, ebp        ; this

automobile->SetTaxiLight срабатывает для стандартных такси (для дополнительных только меняет флаг, а огонька нет), почему до этого не работало - загадка, хотя делал так же.  ???
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 16, 2017, 03:02:59 pm
Код: C++
  1. ScriptCommand<SET_TAXI_LIGHTS>(CPools::GetVehicleRef(automobile), 1);

Цитировать
Хотел сделать подобно показанному тобой примеру, но там id в eax, а номера для команды 'push eax' не знаю.

Options > General... > Disassembly > Display disassembly line parts > Number of opcode bytes (non-graph) - поставить 8.

Не знаю, где ты искал. Вот, что у меня:

(http://i.imgur.com/aWMpJGc.png)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 16, 2017, 05:05:30 pm
Спасибо.
Получается это 0x537D1F
А каким образом добавить дополнительным такси огоньки?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Июнь 16, 2017, 07:05:57 pm
Можно сделать так: заменяем эти инструкции на свой код:
Код: C++
  1. 0x5373D7       movsx eax, word ptr [ebp+5Ch] // 4 байта
  2. 0x5373DB       lea edx, [eax-61h] // 3 байта

Код: C++
  1. void __declspec(naked) Patch_5373D7() {
  2.     __asm {
  3.         movsx eax, word ptr [ebp+5Ch]
  4.         pushad
  5.         push eax
  6.         call GetTranslatedTaxiModel // записываем в eax новый id модели - если сравниваемая модель - такси, то получим MODEL_TAXI
  7.         add esp, 4
  8.         popad
  9.         lea edx, [eax-61h]
  10.         mov edi, 0x5373DE
  11.         jmp edi
  12.     }
  13. }

Код: C++
  1. int GetTranslatedTaxiModel(int model) {
  2.     if (IsTaxiModel(model)) // какая-то функция, которая возвращает true/false
  3.         return MODEL_TAXI;
  4.     return model;
  5. }

Т.е., перед выполнением switch-а, подставляем в сравниваемый id MODEL_TAXI, если модель - такси.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 17, 2017, 01:10:24 pm
Спасибо за очередные пояснения.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 13, 2017, 07:24:14 am
Ранее был показан пример http://forum.gtabuilder.ru/index.php?topic=337.msg2337#msg2337 (http://forum.gtabuilder.ru/index.php?topic=337.msg2337#msg2337), как  использовать VehicleExtendedData.
Код: C++
  1. class VehicleComponents { // Класс, который представляет наши данные (можно сказать, что эти данные "прикрепляются" к структуре транспорта)

Допустим я хочу реализовать работу дополнительных компонентов транспорта (дворники, руль, тормозные колодки, кузов самосвала, сдвижные двери микроавтобуса и т.д.) в плагине. Допустим мне нужно 50-100 компонентов и некоторое количество переменных, которые отслеживают состояние компонентов (открыт/закрыт, поднят/нет и т.д.) прикрепить подобным образом к структуре.

Есть ли какие-то ограничения по количеству, объёму этих данных, которые прикрепляются таким образом к структуре транспорта в одном плагине? А если подобных плагинов несколько? В общем суть вопроса - есть ли ограничения?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 13, 2017, 08:22:39 pm
Нет, ограничений нет.

Я бы сделал так:
Код: C++
  1. class ComponentBase {
  2.     CVehicle *myVehicle;
  3.     RwFrame *rwFrame;
  4.     // any other shared data ...
  5. public:
  6.     virtual void Update() = delete;
  7. };
  8.  
  9. class BrakePad : public ComponentBase {
  10.     // any data
  11. public:
  12.     void Update() {
  13.         // implementation
  14.     }
  15.  
  16.     BrakePad(CVehicle *_vehicle, RwFrame *_frame) : myVehicle(_vehicle), rwFrame(_frame) {}
  17. };
  18.  
  19. class DumpTipper : public ComponentBase {
  20.     // any data
  21. public:
  22.     void Update() {
  23.         // implementation
  24.     }
  25.  
  26.     // constructor and other methods
  27. };
  28.  
  29. // ... other component classes
  30.  
  31. class ComponentsExtension {
  32. public:
  33.     std::vector<ComponentBase *> components;
  34.  
  35.     ComponentsExtension(CVehicle *) {}
  36.  
  37.     ~ComponentsExtension() {
  38.         Clear();
  39.     }
  40.  
  41.     void Clear() {
  42.         for (auto &comp : ext.components) {
  43.               delete comp ;
  44.          }
  45.          components.clear();
  46.     }
  47.  
  48.     static void UpdateAllComponents(ComponentsExtension &ext) { // call this function in update flow
  49.          for (auto &comp : ext.components) {
  50.               comp->Update();
  51.          }
  52.     }
  53. };
  54.  
  55. // ...
  56.  
  57. extern VehicleExtendedData<ComponentsExtension> compsExt;
  58.  
  59. // ...
  60.  
  61. Events::vehicleRenderEvent.before += [](CVehicle *vehicle) { // or maybe some custom event?
  62.     ComponentsExtension::UpdateAllComponents(compsExt.Get(vehicle));
  63. }
  64.  
  65. // ...
  66.  
  67. Events::vehicleSetModelEvent += [](CVehicle *vehicle, int) {
  68.      ComponentsExtension &ext = compsExt.Get(vehicle);
  69.      if (ext.components.size() > 0)
  70.          ext.Clear();
  71.      RwFrame *breakPadFrame= CClumpModelInfo::FindFrameFromName(vehicle->m_pRwClump, "BrakePad");
  72.      if (breakPadFrame) {
  73.           ext.components.push_back(new BreakPad(vehicle, breakPadFrame);
  74.      }
  75.      // ...
  76. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 14, 2017, 02:56:40 pm
Цитировать
Нет, ограничений нет.
Это хорошо.

Цитировать
Я бы сделал так:
Это для меня не совсем понятно.
Я начал делать, как в показанном ранее примере:

Код: C++
  1. #include <plugin_III.h>
  2. #include "game_III\CClumpModelInfo.h"
  3. #include "game_III\common.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class AdditionalComponents {
  8. public:
  9.     enum eWiperState {
  10.         STATE_LEFT,
  11.         STATE_RIGHT
  12.     };
  13.  
  14.     static eWiperState m_currentWiperState;
  15.     static float wiperAngle;
  16.  
  17.     class VehicleComponents { // Класс, который представляет наши данные (можно сказать, что эти данные "прикрепляются" к структуре транспорта)
  18.     public:
  19.         RwFrame *m_pBootSliding;
  20.         RwFrame *m_pSteerWheel;
  21.         RwFrame *m_pWiperOneR;
  22.         RwFrame *m_pWiperOneL;
  23.         bool wiperState;
  24.  
  25.         VehicleComponents(CVehicle *) { // Конструктор этого класса будет вызван при вызове конструктора транспорта (CVehicle::CVehicle)
  26.             m_pBootSliding = m_pSteerWheel = m_pWiperOneR = m_pWiperOneL = nullptr;  // устанавливаем все указатели в 0
  27.             wiperState = false;
  28.         }
  29.     };
  30.  
  31.     AdditionalComponents() {
  32.         static VehicleExtendedData<VehicleComponents> vehComps; // Создаем экземпляр нашего расширения. vehComps - это переменная, через которую мы будем
  33.                                                                 // обращаться к нашим данным (используя метод Get(CVehicle *транспорт) )
  34.  
  35.         Events::vehicleSetModelEvent += [](CVehicle *vehicle, int modelIndex) { // Выполняем нашу функцию, когда игра устанавливает модель транспорту
  36.             if (vehicle->m_pRwClump) { // Находим компоненты в иерархии и записываем их в наш класс
  37.                 vehComps.Get(vehicle).m_pBootSliding = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "boot_sliding");
  38.                 vehComps.Get(vehicle).m_pSteerWheel = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "steerwheel");
  39.                 vehComps.Get(vehicle).m_pWiperOneR = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "wiper_or");
  40.                 vehComps.Get(vehicle).m_pWiperOneL = CClumpModelInfo::GetFrameFromName(vehicle->m_pRwClump, "wiper_ol");
  41.             }
  42.             else {
  43.                 vehComps.Get(vehicle).m_pBootSliding = vehComps.Get(vehicle).m_pSteerWheel = vehComps.Get(vehicle).m_pWiperOneR = vehComps.Get(vehicle).m_pWiperOneL = nullptr;
  44.             }
  45.         };
  46.  
  47.         Events::gameProcessEvent += [] {
  48.             for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {
  49.                 CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  50.                 if (vehicle && vehicle->GetIsOnScreen() && vehicle->m_nVehicleClass == VEHICLE_AUTOMOBILE) {
  51.                     CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  52.                     if (vehComps.Get(vehicle).m_pBootSliding) {
  53.                         //
  54.                     }
  55.                     if (vehComps.Get(vehicle).m_pSteerWheel) {
  56.                         //
  57.                     }
  58.                     if (vehComps.Get(vehicle).m_pWiperOneR && vehComps.Get(vehicle).m_pWiperOneL) {
  59.                         //  
  60.                     }
  61.                 }
  62.             }
  63.  
  64.         };
  65.     }
  66. } AdditionalComponents;
  67.  
  68. AdditionalComponents::eWiperState AdditionalComponents::m_currentWiperState = STATE_LEFT;
  69. float AdditionalComponents::wiperAngle = 0.0f;
  70.  

Как определить для GTA3:
1) Включён или выключен двигатель на транспорте?
2) Как определить угол на который повернуто колесо (переднее левое и переднее правое) для установки такого же угла тормозной колодке?

И вопрос, который был написан в ЛС, всё ещё актуален.  :( 

Название: Re: Написание плагина. Настройка проекта
Отправлено: mfisto от Сентябрь 16, 2017, 02:19:39 pm
по поводу двигателя: покопай опкод 02D4, я так для Vice делал.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 17, 2017, 08:42:08 am
по поводу двигателя: покопай опкод 02D4, я так для Vice делал.
Спасибо. Там получается так:
Код: C++
  1. if (vehicle->m_nVehicleFlags & 0x10)
  2.    // двигатель включен
  3. else
  4.    // выключен

Есть ещё вопрос в дополнение к оставшимся выше - если авто загнать в мастерскую с открытым компонентом, то после перекраски и ремонта компонент становится закрытым, но значение угла поворота automobile->m_aDoors[1].m_fAngle этого компонента остаётся от состояния открытого и не перезаписывается принудительно automobile->m_aDoors[1].m_fAngle = 0.0f;. Только после повторного открытия (на самом деле он начинает закрываться с с точки максимального открытого состояния, т.е. со значения automobile->m_aDoors[1].m_fAngle) этого компонента значение становится правильным. Как это исправить?

(http://savepic.net/9941778m.jpg) (http://savepic.net/9941778.htm) (http://savepic.net/9932562m.jpg) (http://savepic.net/9932562.htm)
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Сентябрь 25, 2017, 12:04:27 am
Вопросы очень специфические - надо в базе искать и разбирать, готового ответа у меня нету.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 26, 2017, 05:59:24 pm
Подскажите пожалуйста, как лучше реализовать возможность для пользователей назначать своё сочетание клавиш в текстовом файле для управление тем или иным действием в плагине. Набросал такой пример:
файл .dat
#A - key: dumper up_down, manhole open_closed
#B - key: dumper up,      manhole open
#C - key: dumper down,    manhole closed
#D - key: cement on/off
#E - 
#F -
#G -
#H -

#A,   B,   C,   D,   E,  F, G, H

keys
110, 104, 98,  46,
end

Код: C++
  1. #include "plugin_III.h"
  2. #include "game_III\CMessages.h"
  3. #include <vector>
  4. #include <string>
  5. #include <sstream>
  6. #include <fstream>
  7.  
  8. using namespace plugin;
  9.  
  10. std::vector<unsigned int> Key;
  11.  
  12. class MyPlugin {
  13. public:
  14.     static void ReadSettingsFile() {
  15.         std::ifstream stream("AdditionalComponents.dat");
  16.         for (std::string line; getline(stream, line); ) {
  17.             if (line[0] != ';' && line[0] != '#') {
  18.                 if (!line.compare("keys")) {
  19.                     while (line.compare("end") && getline(stream, line)) {
  20.                         if (line[0] != ';' && line[0] != '#') {
  21.                             std::stringstream ss(line);
  22.                             int i;
  23.                             while (ss >> i) {
  24.                                 Key.push_back(i);
  25.                                 if (ss.peek() == ',')
  26.                                     ss.ignore();
  27.                             }
  28.                         }
  29.                     }
  30.                 }
  31.             }
  32.         }
  33.     }
  34.    
  35.     MyPlugin() {
  36.         ReadSettingsFile();
  37.  
  38.         Events::drawingEvent += [] {
  39.             if (KeyPressed(Key[0]))
  40.                 CMessages::AddMessageJumpQ(L"Key[0]", 2000, 0);
  41.             else if (KeyPressed(Key[1]))
  42.                 CMessages::AddMessageJumpQ(L"Key[1]", 2000, 0);
  43.         };
  44.     }
  45. } myPlugin;

Можно как-то улучшить? Оптимизировать? Или вообще по-другому это реализуется? Можно пример?
А если сделать с использованием .ini как это реализовать? Какой способ лучше?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 01, 2017, 01:09:56 am
mycontrols.dat
Код: C
  1. KEY_OPEN_CLOSE  110   ; dumper up_down, manhole open_closed
  2. KEY_OPEN        104   ; dumper up,      manhole open
  3. KEY_CLOSE       98    ; dumper down,    manhole closed
  4. KEY_ON_OFF      46    ; cement on/off  

MySettings.h
Код: C++
  1. #pragma once
  2.  
  3. class MySettings {
  4. public:
  5.      MySettings();
  6.      
  7.      int keyOpenClose, keyOpen, keyClose, keyOnOff;
  8. };
  9.  
  10. extern MySettings settings;

MySettings.cpp
Код: C++
  1. #include "MySettings.h"
  2. #include plugin_header
  3.  
  4. MySettings settings;
  5.  
  6. MySettings::MySettings() {
  7.     plugin::config_file conf(PLUGIN_PATH("mycontrols.dat");
  8.    
  9.     keyOpenClose = conf["KEY_OPEN_CLOSE"].asInt(110);
  10.     keyOpen      = conf["KEY_OPEN"].asInt(104);
  11.     keyClose     = conf["KEY_CLOSE"].asInt(98);
  12.     keyOnOff     = conf["KEY_ON_OFF"].asInt(46);
  13. }

Main.cpp
Код: C++
  1. #include plugin_header
  2. #include "MySettings.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class Test {
  7. public:
  8.     Test() {
  9.         Events::gameProcessEvent += [] { // AddMessageJumpQ не рисует "напрямую" (в отличии от методов CFont), поэтому в drawing добавлять не надо
  10.             if (KeyPressed(settings.keyOpenClose))
  11.                 CMessages::AddMessageJumpQ(L"KEY_OPEN_CLOSE pressed", 2000, 0);
  12.         };
  13.     }
  14. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 01, 2017, 12:56:18 pm
Спасибо!
Здесь добавил public: иначе в основном коде не было доступа к settings.keyOpenClose
Код: C++
  1. class MySettings {
  2. public:
  3. //......
  4.  

И ещё вопрос:
Код: C++
  1. #include "MySettings.h"
  2. #include plugin_header

подключение идёт в MySettings.cpp и в Main.cpp

Надо ли в этом случае в MySettings.cpp добавить перед этими строчками директиву #pragma once ?
Код: C++
  1. #pragma once
  2. #include "MySettings.h"
  3. #include plugin_header
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 01, 2017, 08:46:41 pm
Да.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 11, 2017, 09:05:25 am
Подскажите пожалуйста какой Event добавить в sdk, чтобы можно было выводить текстуру или текст в меню паузы игры?

update:
Нашёл, добавил в sdk для GTA3

Текст выводится, вот с текстурой проблема. С помощью CSprite2d не получается вывести.  >:(
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 13, 2017, 10:48:02 am
Понадобилось в плагине для GTA3 найти координаты с офсетом относительно транспорта (и игрока).
Посмотрел в CLEO-SDK, как реализован соответствующий опкод
//0407=7,store_coords_to %5d% %6d% %7d% from_car %1d% with_offset %2d% %3d% %4d%

Затруднение возникло с последним аргументом в функции RwV3dTransformPoints
Код: C++
  1. RwV3d* RwV3dTransformPoints(RwV3d* pointsOut, const RwV3d* pointsIn, RwInt32 numPoints, const RwMatrix* matrix);

Покажите пожалуйста примеры вызова для координат относительно транспорта игрока и самого игрока. 
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 15, 2017, 09:13:36 am
Не знаю, где именно ты это заметил. В опкоде 0407 вызывается Multiply3x3.

А вообще, можно так сделать
Код: C++
  1. CVector result = matrix * offset;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 15, 2017, 09:37:09 am
Спасибо! Попробую.
Для GTA3 там же опкод под таким номером другой. Взял из III.CLEO-SDK
CustomOpcodes.cpp
Код: C++
  1. //0407=7,store_coords_to %5d% %6d% %7d% from_car %1d% with_offset %2d% %3d% %4d%
  2. eOpcodeResult CustomOpcodes::STORE_COORDS_FROM_CAR_WITH_OFFSET(CScript *script)
  3. {
  4.         script->Collect(4);
  5.         void* car = game.Pools.pfVehiclePoolGetStruct(*game.Pools.pVehiclePool, game.Scripts.Params[0].nVar);
  6.  
  7.         CVector offset;
  8.         offset.x = game.Scripts.Params[1].fVar;
  9.         offset.y = game.Scripts.Params[2].fVar;
  10.         offset.z = game.Scripts.Params[3].fVar;
  11.  
  12.         game.Misc.RwV3dTransformPoints(&offset, &offset, 1, (uintptr_t*)((uintptr_t)car + 4));
  13.  
  14.         game.Scripts.Params[0].fVar = offset.x;
  15.         game.Scripts.Params[1].fVar = offset.y;
  16.         game.Scripts.Params[2].fVar = offset.z;
  17.  
  18.         script->Store(3);
  19.         return OR_CONTINUE;
  20. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 15, 2017, 10:02:48 am
В CLEO и CLEO-SDK не используется plugin-sdk, зачем его брать за пример?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 15, 2017, 12:37:09 pm
Не знал, как сделать и решил посмотреть, как реализовано там.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Октябрь 16, 2017, 09:53:14 am
Устройство опкодов можно посмотреть в базе.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 03, 2017, 02:23:16 pm
Реализовал работу поворотников для GTA3, взяв за основу пример UniversalTurnlights для SA. Возникли затруднения с реализацией поворотников для авто в трафике, а именно с этой частью:
Код: C++
  1. static CVector2D GetCarPathLinkPosition(CCarPathLinkAddress &address) {
  2.         if (address.m_wAreaId != -1 && address.m_wCarPathLinkId != -1 && ThePaths.m_pPathNodes[address.m_wAreaId]) {
  3.             return CVector2D(static_cast<float>(ThePaths.m_pNaviNodes[address.m_wAreaId][address.m_wCarPathLinkId].m_posn.x) / 8.0f,
  4.                 static_cast<float>(ThePaths.m_pNaviNodes[address.m_wAreaId][address.m_wCarPathLinkId].m_posn.y) / 8.0f);
  5.         }
  6.         return CVector2D(0.0f, 0.0f);
  7.     }

Если ещё точнее, то с этим:
Код: C++
  1. ThePaths.m_pPathNodes и ThePaths.m_pNaviNodes

Кто-нибудь разбирал пути для GTA3?
Дмитрий, помнится ты когда-то начал перенос мода IVF для GTA3. До разбора этого момента дело дошло? Если разобрал, то добавь пожалуйста в sdk, как будет время.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 10, 2017, 04:42:56 am
Нет. Надо в базе искать.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 12, 2017, 02:58:28 pm
Когда-то Den_spb показывал код для SA, чтобы менять модель авто не создавая при этом новую:
03C0: 1@ = actor $PLAYER_ACTOR car
0A97: 2@ = car 1@ struct
0AA6: call_method 0x6D6A40 struct 2@ params 1 pop 0 %какой-либо ид машины из vehicles.dat%
Как писал Денис
Цитировать
Но метод работает только при следующих условиях:
1.Предварительно загружена новая модель.
2.Старая и новая модели однотипны (например, 4-дверное авто заменить на 2-дверное не получится, только 4-дверное на 4-дверное).

Там были проблемы с колёсами. Сейчас что-то вспомнил про это и подумал, что надо для авто вызывать CAutomobile::SetModelIndex, а для другого типа транспорта соответственно свой метод. Тогда никаких проблем нет. А если менять модель на ту же самую, то и загрузка модели не нужна. Способ хорошо подходит для просмотра и замены экстр на транспорте.

Вот код в виде клео скрипта для VC
{$CLEO .cs} // VC 1.0
6@ = -1

while true
wait 0
    if
      0256: player $PLAYER_CHAR defined
    then
        if and
          05EE: key_pressed 52 //  4
          Actor.Driving($PLAYER_ACTOR)
          84C9: not player $player_char driving_flying_vehicle
          847E: not player $player_char driving_a_motorbike
          84A8: not player $PLAYER_CHAR driving_boat
        then
            03C0: 0@ = actor $PLAYER_ACTOR car
            0441: 1@ = car 0@ model
            0506: set_car_model 1@ next_variation 6@ 6@
            05E7: 2@ = car 0@ struct
            05E3: call_method 0x59E590 struct 2@ params 1 pop 0 1@ // CAutomobile::SetModelIndex
            0085: 7@ = 6@
            7@ += 1
            01E3: show_text_1number_styled GXT 'NUMBER' number 7@ time 2000 style 4 
            if
              not 6@ >= 5
            then
                6@ += 1
            else
                6@ = -1
            end
            repeat
              wait 0
            until 85EE: not key_pressed 52 // 4
        end
    end
end 

Хотел перенести на основу plugin-sdk, но не вышло пока. Вот эти строчки не знаю, как реализовать
05E7: 2@ = car 0@ struct
05E3: call_method 0x59E590 struct 2@ params 1 pop 0 1@
Название: Re: Написание плагина. Настройка проекта
Отправлено: xanser от Ноябрь 13, 2017, 05:14:47 am
Хотел перенести на основу plugin-sdk, но не вышло пока. Вот эти строчки не знаю, как реализовать
05E7: 2@ = car 0@ struct
05E3: call_method 0x59E590 struct 2@ params 1 pop 0 1@
Вроде это самое простое, у меня так, на plugin-sdk по аналогии.
Код: C++
  1. void CAutomobile::SetModelIndex(int id) {
  2.         ((void(__thiscall *)(CAutomobile *, int))0x59E590)(this, id);
  3. }
  4.  
  5. ((CAutomobile *)(PlayerPed->Vehicle))->SetModelIndex(149);
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 13, 2017, 10:41:03 am
Вроде это самое простое, у меня так, на plugin-sdk по аналогии.
Нет. Это виртуальная функция. Вызывать надо из vtable.

kenking, в SDK ведь есть метод SetModelIndex, что тогда не так?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 13, 2017, 10:43:03 am
Как оказалось я сам себя запутал. В клео я сделал для VC. В плагин переносил для GTA3. А в sdk для GTA3 я неверно сделал таблицу виртуальных методов для CEntity. Это исправил. Сейчас метод работает. НО при выходе из игры, игра зависает (если использовать этот метод) и потом выходит ошибка. В VC тоже самое. Причём в VC не всегда. Вроде бы, если другой такой модели в трафике нет при выходе из игры, то всё нормально, иначе зависание. Может это и совпадение.

Код для GTA3
Код: C++
  1. #include "plugin_III.h"
  2. #include "game_III\common.h"
  3. #include "extensions\KeyCheck.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class MyPlugin {
  8. public:
  9.  
  10.     MyPlugin() {
  11.         Events::gameProcessEvent += [] {
  12.             CVehicle *vehicle = FindPlayerVehicle();
  13.             if (vehicle && vehicle->m_nVehicleClass == VEHICLE_AUTOMOBILE) {
  14.                 CAutomobile *automobile = reinterpret_cast<CAutomobile *>(vehicle);
  15.                 KeyCheck::Update();
  16.                 if (KeyCheck::CheckWithDelay(53, 1000))
  17.                     automobile->SetModelIndex(automobile->m_nModelIndex);
  18.             }
  19.         };
  20.     }
  21. } myPlugin;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 13, 2017, 02:54:09 pm
Ещё один "сюрприз" - после добавления в sdk для GTA3 остальных функций CCoronas, в коде плагина выходит следующая ошибка

(https://img-fotki.yandex.ru/get/370294/98251335.0/0_130e50_a975ea90_L.png) (https://fotki.yandex.ru/users/kenking/view/1248848/)

Как исправить?

Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 14, 2017, 01:43:21 pm
Компилятор не может определить, какую функцию вызывать.
Надо вручную указать, что 0, который ты передаешь - это unsigned char.
Код: C++
  1. static_cast<unsigned char>(0)
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 15, 2017, 07:50:39 am
Спасибо! Теперь нормально.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 20, 2017, 05:27:19 pm
Решил опробовать ScriptCommand
Код: C++
  1. Events::processScriptsEvent += [] {
  2.     CVehicle *vehicle = FindPlayerVehicle();
  3.     if (vehicle)
  4.         float angleZ = ScriptCommand<GET_CAR_HEADING>(CPools::GetVehicleRef(vehicle));
  5. };
Но не тут-то было...  :(

Цитировать
1>III_test_sdk.cpp
1>D:\Projects\plugin-sdk\plugin_III\extensions\ScriptCommands.h(60): error C2664: "void plugin::test::ScriptCode::operator <<(unsigned int *)": невозможно преобразовать аргумент 1 из "CVehicle *" в "char"
1>D:\Projects\plugin-sdk\plugin_III\extensions\ScriptCommands.h(60): note: Не существует контекста, в котором такое преобразование возможно
1>D:\Projects\plugin-sdk\plugin_III\extensions\ScriptCommands.h(84): note: см. ссылку на создание экземпляров функции шаблон при компиляции "void plugin::test::ScriptCode::Pack<CVehicle*>(T)"
1>        with
1>        [
1>            T=CVehicle *
1>        ]
1>III_test_sdk.cpp(21): note: см. ссылку на создание экземпляров функции шаблон при компиляции "bool plugin::test::ScriptCommand<plugin::test::GET_CAR_HEADING,CVehicle*>(CVehicle *)"
1>Сборка проекта "III_test.vcxproj" завершена с ошибкой.
========== Перестроение всех проектов: успешно: 0, с ошибками: 1, пропущено: 0 ==========

Попытка установить угол транспорту окончилась также. Что делаю не так?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 20, 2017, 06:04:29 pm
В GTA3 неправильно обьявлен метод
Код: C++
  1. CVehicle* CPools::GetVehicleRef(CVehicle* vehicle)
Он должен возвращать int (хендл).

Функция ScriptCommand всегда возвращает bool (для опкодов-проверок).
Надо вызывать так
Код: C++
  1. float angleZ = 0.0f;
  2. ScriptCommand<GET_CAR_HEADING>(CPools::GetVehicleRef(vehicle), &angleZ);
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 21, 2017, 09:34:05 am
В GTA3 неправильно обьявлен метод
Код: C++
  1. CVehicle* CPools::GetVehicleRef(CVehicle* vehicle)
Он должен возвращать int (хендл).
Упс... там для CObject и CPed по-ходу тоже было неправильно. Исправил. https://github.com/DK22Pac/plugin-sdk/commit/fd30dab12f942bad5cf997244e5e128718858d11 (https://github.com/DK22Pac/plugin-sdk/commit/fd30dab12f942bad5cf997244e5e128718858d11)
Надеюсь, что теперь правильно.

Надо вызывать так
Код: C++
  1. float angleZ = 0.0f;
  2. ScriptCommand<GET_CAR_HEADING>(CPools::GetVehicleRef(vehicle), &angleZ);
Спасибо. Теперь работает.

Попробовал разобрать этот опкод, но что-то значение получается другое. В чём ошибка?

Код: C++
  1. CVehicle *vehicle = FindPlayerVehicle();
  2. if (vehicle) {
  3.     float ang = atan2(vehicle->m_matrix.up.y, -vehicle->m_matrix.up.x);
  4.     float ang2 = 180.0f * ang * 0.31830987f;
  5.     if (ang2 >= 0.0f)
  6.         ang2 = ang2 + 360.0f;
  7.     if (ang2 > 360.0f)
  8.          ang2 = ang2 - 360.0f;
  9. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 24, 2017, 04:16:33 pm
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\ScriptCommands.h"
  3. #include "common.h"
  4. #include "CMessages.h"
  5.  
  6. using namespace plugin;
  7. using namespace plugin::test;
  8.  
  9. class Gta3CarAngle {
  10. public:
  11.     Gta3CarAngle() {
  12.         Events::gameProcessEvent += [] {
  13.             CVehicle *vehicle = FindPlayerVehicle();
  14.  
  15.             if (!vehicle)
  16.                 return;
  17.  
  18.             float angle = atan2(-vehicle->m_matrix.up.x, vehicle->m_matrix.up.y) * 57.295776f;
  19.             if (angle < 0.0f)
  20.                 angle += 360.0f;
  21.             if (angle > 360.0f)
  22.                 angle -= 360.0f;
  23.  
  24.             float angleCommand = 0.0f;
  25.             ScriptCommand<GET_CAR_HEADING>(CPools::GetVehicleRef(vehicle), &angleCommand);
  26.  
  27.             static char message[256];
  28.             snprintf(message, 256, "Angle: %g Angle (command): %g", angle, angleCommand);
  29.  
  30.             CMessages::AddMessageJumpQ(message, 200, false);
  31.         };
  32.     }
  33. } gta3CarAngle;
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 24, 2017, 07:05:17 pm
Спасибо! Так значение сходится. Странно у меня IDA показывает именно >=
case 0x174u:
      CRunningScript::CollectParameters(a1, (CRunningScript *)(a1 + 16), (unsigned int *)1, v163);
      v115 = (CVehicle *)CPool_CVehicle_CAutomobile_GetAt(CPools::ms_pVehiclePool, ScriptParams);
      v116 = atan2(
               *(float *)&v115->physical.entity.m_placement.matrix.matrix.top.y,
               -*(float *)&v115->physical.entity.m_placement.matrix.matrix.top.x);
      *(float *)&v205 = flt_5EEDE0 * v116 * flt_5EEDE4;
      if ( *(float *)&v205 >= (double)flt_5EEDDC )
        *(float *)&v205 = *(float *)&v205 + flt_5EEDE8;
      if ( *(float *)&v205 > (double)flt_5EEDE8 )
        *(float *)&v205 = *(float *)&v205 - flt_5EEDE8;
      ScriptParams = v205;
      CRunningScript::StoreParameters((CRunningScript *)(v4 + 16), (unsigned int *)1, v169);
      result = 0;
      break;

Если я хочу добавить в sdk функцию, которой нет для GTA3, вот эту
Код: C++
  1. thiscall float CPlaceable::GetHeading(void);

то надо добавить в CPlaceable.h
Код: C++
  1. inline float GetHeading() {
  2.     float angle = atan2(-this->m_matrix.up.x, this->m_matrix.up.y) * 57.295776f;
  3.     if (angle < 0.0f)
  4.         angle += 360.0f;
  5.     if (angle > 360.0f)
  6.         angle -= 360.0f;
  7.     return angle;              
  8. }

Верно?
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Декабрь 05, 2017, 01:34:44 am
Наверное да. Но в SA такая функция по-другому выглядит.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 08, 2017, 04:55:42 pm
Решил перенести пример создания транспорта для SA на GTA III, но транспорт не создаётся. Выяснил, что модель не загружается, причём с любым выставленным флагом. Подскажите пожалуйста, что не так? Код:
Код: C++
  1. #include "plugin_III.h"
  2. #include "game_III\common.h"
  3. #include "game_III\CStreaming.h"
  4. #include "game_III\CModelInfo.h"
  5. #include "game_III\CBoat.h"
  6. #include "game_III\CWorld.h"
  7. #include "game_III\CTheScripts.h"
  8. #include "game_III\CTimer.h"
  9. #include "game_III\CMessages.h"
  10.  
  11. using namespace plugin;
  12.  
  13. class CreateCarExample {
  14. public:
  15.     static unsigned int m_nLastSpawnedTime;
  16.  
  17.     static void SetPosition(CVehicle * vehicle, CVector &pos) {
  18.         vehicle->m_matrix.pos = pos;
  19.     }
  20.  
  21.     static void SetOrientation(CVehicle * vehicle, float x, float y, float z) {
  22.         CVector pos = vehicle->m_matrix.pos;
  23.         vehicle->m_matrix.SetRotate(x, y, z);
  24.         vehicle->m_matrix.pos = pos;
  25.     }
  26.  
  27.     static CVehicle *SpawnVehicle(unsigned int modelIndex, CVector position, float orientation) {
  28.         unsigned char oldFlags = CStreaming::ms_aInfoForModel[modelIndex].m_nFlags;
  29.         CStreaming::RequestModel(modelIndex, GAME_REQUIRED);
  30.         CStreaming::LoadAllRequestedModels(false);
  31.         if (CStreaming::ms_aInfoForModel[modelIndex].m_nLoadState == LOADSTATE_LOADED) {
  32.             CMessages::AddMessageJumpQ(L"model loaded", 1000, 0);
  33.             if (!(oldFlags & GAME_REQUIRED)) {
  34.                 CStreaming::SetModelIsDeletable(modelIndex);
  35.                 CStreaming::SetModelTxdIsDeletable(modelIndex);
  36.             }
  37.             CVehicle *vehicle = nullptr;
  38.             switch (reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[modelIndex])->m_nVehicleType) {
  39.             case VEHICLE_BOAT:
  40.                 vehicle = new CBoat(modelIndex, 1);
  41.                 break;
  42.             default:
  43.                 vehicle = new CAutomobile(modelIndex, 1);
  44.                 break;
  45.             }
  46.             if (vehicle) {
  47.                 SetPosition(vehicle, position);
  48.                 SetOrientation(vehicle, 0.0f, 0.0f, orientation);
  49.                 vehicle->m_nDoorLock = CARLOCK_UNLOCKED;
  50.                 CWorld::Add(vehicle);
  51.                 CTheScripts::ClearSpaceForMissionEntity(position, vehicle);
  52.                 if (vehicle->m_nVehicleClass != VEHICLE_BOAT)
  53.                     reinterpret_cast<CAutomobile *>(vehicle)->PlaceOnRoadProperly();
  54.                 return vehicle;
  55.             }
  56.         }
  57.         return nullptr;
  58.     }
  59.  
  60.     static void ProcessSpawn() {
  61.         if (KeyPressed(VK_TAB) && CTimer::m_snTimeInMilliseconds > (m_nLastSpawnedTime + 1000)) {
  62.             CPed *player = FindPlayerPed();
  63.             if (player) {
  64.                 //CVector position = FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 5.0f, 0.0f));
  65.                 CVector offset = { 0.0f, 5.0f, 0.0f };
  66.                 CVector position = player->m_matrix * offset;
  67.                 CAutomobile *automobile = reinterpret_cast<CAutomobile *>(SpawnVehicle(91, position, FindPlayerPed()->m_fRotationCur + 1.5707964f));
  68.                 if (automobile) {
  69.                     m_nLastSpawnedTime = CTimer::m_snTimeInMilliseconds;
  70.                     CMessages::AddMessageJumpQ(L"vehicle create", 1000, 0);
  71.                 }
  72.             }
  73.         }
  74.     }
  75.  
  76.     CreateCarExample() {
  77.         Events::gameProcessEvent.Add(ProcessSpawn);
  78.     }
  79. } example;
  80.  
  81. unsigned int CreateCarExample::m_nLastSpawnedTime = 0;
  82.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 30, 2017, 05:02:57 pm
 ;) Нашёл причину - в sdk я добавил CStreaming::ms_aInfoForModel с неправильным начальным адресом. Исправил.
И ещё обязательно
Код: C++
  1. vehicle->m_nState = 4;
иначе после создания авто сразу исчезает.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 30, 2017, 07:26:42 pm
 :D Переделал код спаунера транспорта для GTA3 (без аудио)
Код: C++
  1. #include <string>
  2. #include "plugin_III.h"
  3. #include "extensions\KeyCheck.h"
  4. #include "game_III\common.h"
  5. #include "game_III\CModelInfo.h"
  6. #include "game_III\CTimer.h"
  7. #include "game_III\CFont.h"
  8. #include "game_III\CSprite2d.h"
  9. #include "game_III\CStreaming.h"
  10. #include "game_III\CBoat.h"
  11. #include "game_III\CWorld.h"
  12. #include "game_III\CTheScripts.h"
  13. #include "game_III\eVehicleModel.h"
  14.  
  15. using namespace plugin;
  16.  
  17. class MoreVehiclesSpawner {
  18. public:
  19.     static std::string typedBuffer;
  20.     static std::string errorMessage;
  21.     static std::string errorMessageBuffer;
  22.     static unsigned int errorMessageTimer;
  23.     static bool enabled;
  24.  
  25.     static CVehicle *SpawnVehicle(unsigned int modelIndex, CVector position, float orientation) {
  26.         unsigned char oldFlags = CStreaming::ms_aInfoForModel[modelIndex].m_nFlags;
  27.         CStreaming::RequestModel(modelIndex, GAME_REQUIRED);
  28.         CStreaming::LoadAllRequestedModels(false);
  29.         if (CStreaming::ms_aInfoForModel[modelIndex].m_nLoadState == LOADSTATE_LOADED) {
  30.             if (!(oldFlags & GAME_REQUIRED)) {
  31.                 CStreaming::SetModelIsDeletable(modelIndex);
  32.                 CStreaming::SetModelTxdIsDeletable(modelIndex);
  33.             }
  34.             CVehicle *vehicle = nullptr;
  35.             switch (reinterpret_cast<CVehicleModelInfo *>(CModelInfo::ms_modelInfoPtrs[modelIndex])->m_nVehicleType) {
  36.             case VEHICLE_BOAT:
  37.                 vehicle = new CBoat(modelIndex, 1);
  38.                 break;
  39.             default:
  40.                 vehicle = new CAutomobile(modelIndex, 1);
  41.                 break;
  42.             }
  43.             if (vehicle) {
  44.                 // Размещаем транспорт в игровом мире
  45.                 vehicle->SetPosition(position);
  46.                 vehicle->SetOrientation(0.0f, 0.0f, orientation);
  47.                 vehicle->m_nState = 4;
  48.                 if (modelIndex == MODEL_RCBANDIT)
  49.                     vehicle->m_nDoorLock = CARLOCK_LOCKED;
  50.                 else
  51.                     vehicle->m_nDoorLock = CARLOCK_UNLOCKED;
  52.                 CWorld::Add(vehicle);
  53.                 CTheScripts::ClearSpaceForMissionEntity(position, vehicle);
  54.                 if (vehicle->m_nVehicleClass != VEHICLE_BOAT)
  55.                     reinterpret_cast<CAutomobile *>(vehicle)->PlaceOnRoadProperly();
  56.                 return vehicle;
  57.             }
  58.         }
  59.         return nullptr;
  60.     }
  61.  
  62.     static void Update() {
  63.         KeyCheck::Update(); // апдейтим состояния клавиш
  64.         if (FindPlayerPed()) {
  65.             if (KeyCheck::CheckJustDown(VK_TAB)) { // Если нажата Tab - включаем или выключаем консоль
  66.                 enabled = !enabled;
  67.                 typedBuffer.clear();
  68.                 errorMessageBuffer.clear();
  69.             }
  70.             if (enabled) {
  71.                 errorMessage.clear();
  72.                 if (KeyCheck::CheckWithDelay(VK_BACK, 200)) { // Если нажат Backspace - убираем последний символ в строке
  73.                     if (typedBuffer.size() > 0) {
  74.                         typedBuffer.pop_back();
  75.                     }
  76.                 }
  77.                 else {
  78.                     for (int i = 0; i <= 9; i++) {
  79.                         if (KeyCheck::CheckWithDelay(i + 48, 200)) {
  80.                             if (typedBuffer.size() == 4)
  81.                                 errorMessage = "Too many digits!";
  82.                             else {
  83.                                 typedBuffer.push_back(i + 48); // Добавляем символ в конец строки
  84.                             }
  85.                             break;
  86.                         }
  87.                     }
  88.                 }
  89.                 if (KeyCheck::CheckJustDown(45)) { // Если нажата Insert - спавним транспорт
  90.                     if (typedBuffer.size() > 0) {
  91.                         unsigned int modelId = std::stoi(typedBuffer);
  92.                         if (modelId < 5501) {
  93.                             int modelType = CModelInfo::IsVehicleModelType(modelId);
  94.                             if (modelType != -1) {
  95.                                 if (modelType == 0 || modelType == 1) {
  96.                                     CVehicle *vehicle = SpawnVehicle(modelId, FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 5.0f, 0.0f)), FindPlayerPed()->m_fRotationCur + 1.5707964f);
  97.                                     errorMessageBuffer.clear(); // убираем надпись об ошибке (если она была на экране)
  98.                                 }
  99.                                 else
  100.                                     errorMessage = "Can't spawn a train, heli and plane model";
  101.                             }
  102.                             else
  103.                                 errorMessage = "This model is not a vehicle!";
  104.                         }
  105.                         else
  106.                             errorMessage = "ID is too big!";
  107.                     }
  108.                     else
  109.                         errorMessage = "Please enter model Id!";
  110.                 }
  111.             }
  112.         }
  113.         else
  114.             enabled = false;
  115.     }
  116.  
  117.     static void Render() {
  118.         if (enabled) {
  119.             CSprite2d::DrawRect(CRect(100.0f, 100.0f, 470.0f, 200.0f), CRGBA(0, 0, 0, 100));
  120.             CSprite2d::DrawRect(CRect(250.0f, 140.0f, 320.0f, 142.0f), CRGBA(255, 255, 255, 255));
  121.            
  122.             CFont::SetScale(0.8f, 1.9f);
  123.             CFont::SetColor(CRGBA(255, 255, 255, 255));
  124.             CFont::SetJustifyOn();
  125.             CFont::SetFontStyle(0);
  126.             CFont::SetPropOn();
  127.             CFont::SetWrapx(600.0f);
  128.             CFont::PrintString(105.0f, 105.0f, "Model ID:");
  129.             if (typedBuffer.size() > 0)
  130.                 CFont::PrintString(250.0f, 105.0f, const_cast<char*>(typedBuffer.c_str()));
  131.             if (errorMessage.size() > 0) {
  132.                 errorMessageBuffer = errorMessage;
  133.                 errorMessageTimer = CTimer::m_snTimeInMilliseconds;
  134.             }
  135.             if (errorMessageBuffer.size() > 0 && CTimer::m_snTimeInMilliseconds < (errorMessageTimer + 2000)) {
  136.                 CFont::SetColor(CRGBA(255, 0, 0, 255));
  137.                 CFont::PrintString(105.0f, 150.0f, const_cast<char*>(errorMessageBuffer.c_str()));
  138.             }
  139.         }
  140.     }
  141.  
  142.     MoreVehiclesSpawner() {
  143.         Events::gameProcessEvent += Update;
  144.         Events::drawingEvent += Render;
  145.     };
  146. } moreVehiclesSpawner;
  147.  
  148. std::string MoreVehiclesSpawner::typedBuffer;
  149. std::string MoreVehiclesSpawner::errorMessage;
  150. std::string MoreVehiclesSpawner::errorMessageBuffer;
  151. unsigned int MoreVehiclesSpawner::errorMessageTimer = 0;
  152. bool MoreVehiclesSpawner::enabled = false;
  153.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 16, 2018, 01:00:23 pm
Решил заменить для GTA3 функцию ChooseComponent на функцию аналогичную для SA, поскольку для GTA3 эта функция в укороченном варианте. С заменой функций на свои до сих пор не совсем разобрался. Написал такой код:
Код: C++
  1. #include "plugin.h"
  2.  
  3. using namespace plugin;
  4.  
  5. int randomId, v2, v4, result;
  6.  
  7. class NewChooseComponent {
  8. public:
  9.     static int __cdecl CountCompsInRule(signed int compRulesBits) {
  10.         return plugin::CallAndReturn<int, 0x520990, signed int>(compRulesBits);
  11.     }
  12.    
  13.     static unsigned int __cdecl GetRandomNumberInRange(int min, int max) {
  14.         return plugin::CallAndReturn<unsigned int, 0x54A4C0, int, int>(min, max);
  15.     }
  16.  
  17.     static int Choose(int type, signed int compRulesBits) {
  18.         switch (type) {
  19.         case 1:
  20.         case 2:
  21.             v2 = CountCompsInRule(compRulesBits);
  22.             result = (compRulesBits >> 4 * GetRandomNumberInRange(0, v2)) & 0xF;
  23.             break;
  24.         case 3:
  25.             v4 = CountCompsInRule(compRulesBits);
  26.             randomId = GetRandomNumberInRange(-1, v4);
  27.             if (randomId == -1) {
  28.                 result = -1;
  29.                 break;
  30.             }
  31.             result = (compRulesBits >> 4 * randomId) & 0xF;
  32.             break;
  33.         case 4:
  34.             result = GetRandomNumberInRange(0, 6);
  35.             break;
  36.         default:
  37.             result = -1;
  38.             break;
  39.         }
  40.         return result;
  41.     }
  42.  
  43.     NewChooseComponent() {
  44.         patch::RedirectJump(0x5209C0, Choose);
  45.     };
  46. } NewChooseComponents;
  47.  

Поскольку в sdk не добавлена функция CountCompsInRule и зачем-то убрали, добавленные ранее, функции
Код: C++
  1. // returns random float in range [min;max)
  2. static float GetRandomNumberInRange(float min, float max);
  3. // returns random int in range [min;max)
  4. static unsigned int GetRandomNumberInRange(int min, int max);
  5. // returns random int in range 0-32767
  6. static unsigned int GetRandomNumber();

попробовал добавить нужные функции непосредственно в код плагина. Не уверен, что сделал это верно. Просьба подсказать, хотя при сборке плагина показывается ошибка в другом месте:
Цитировать
1>------ Перестроение всех файлов начато: проект: III_NewChooseComponent, Конфигурация: GTA3 Release Win32 ------
1>D:\Programs\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\CL.exe /c /I"D:\Projects\plugin-sdk\plugin_iii\\" /I"D:\Projects\plugin-sdk\plugin_iii\game_iii\\" /I"D:\Projects\plugin-sdk\shared\\" /Zi /nologo /W3 /WX- /diagnostics:classic /sdl /O2 /Oi /Oy- /GL /D _NDEBUG /D _USING_V110_SDK71_ /D _CRT_SECURE_NO_WARNINGS /D _CRT_NON_CONFORMING_SWPRINTFS /D GTA3 /D "GTAGAME_NAME=\"3\"" /D "GTAGAME_ABBR=\"3\"" /D "GTAGAME_ABBRLOW=\"3\"" /D "GTAGAME_PROTAGONISTNAME=\"Claude\"" /D "GTAGAME_CITYNAME=\"Liberty City\"" /D PLUGIN_SGV_10EN /D _USING_V110_SDK71_ /D _WINDLL /D _MBCS /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /std:c++latest /Fo"D:\Projects\GTA-Projects\III_NewChooseComponent\.obj\GTA3\Release\\" /Fd"D:\Projects\GTA-Projects\III_NewChooseComponent\.obj\GTA3\Release\vc141.pdb" /Gd /TP /analyze- /errorReport:prompt /Zc:threadSafeInit- III_NewChooseComponent.cpp
1>III_NewChooseComponent.cpp
1>D:\Programs\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\link.exe /ERRORREPORT:PROMPT /OUT:"D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.asi" /NOLOGO /LIBPATH:"D:\Projects\plugin-sdk\output\lib\\" plugin_iii.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /PDB:"D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.pdb" /SUBSYSTEM:WINDOWS,"5.01" /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.lib" /MACHINE:X86 /SAFESEH /DLL "D:\Projects\GTA-Projects\III_NewChooseComponent\.obj\GTA3\Release\III_NewChooseComponent.obj"
1>III_NewChooseComponent.obj : error LNK2001: неразрешенный внешний символ ""public: static void __cdecl plugin::patch::RedirectJump(int,void *,bool)" (?RedirectJump@patch@plugin@@SAXHPAX_N@Z)"
1>D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.asi : fatal error LNK1120: неразрешенных внешних элементов: 1
1>Сборка проекта "III_NewChooseComponent.vcxproj" завершена с ошибкой.
========== Перестроение всех проектов: успешно: 0, с ошибками: 1, пропущено: 0 ==========


Что не так с RedirectJump? Делал по примеру SpawnTruckCheat в посте № 55 этой темы. Просьба подсказать в чём ошибка.
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Октябрь 16, 2018, 02:11:00 pm
Я нужные функции, которых нет в SDK, добавлял перед "using namespace plugin;" так:

Код: C++
  1. auto    StoreShadowToBeRenderedd = (void(__cdecl *)(unsigned char type, unsigned int texture, CVector* posn, float topX, float topY, float rightX, float rightY, short intensity, unsigned char red, unsigned char green, unsigned char blue, float zDistance, bool drawOnWater, float scale, int realTimeShadow, bool drawOnBuildings))0x56E6C0;
  2.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 18, 2018, 11:43:07 am
Обновил sdk. Пересобрал сам плагин. Подправил немного код своего плагина.
Код: C++
  1. #include "plugin.h"
  2.  
  3. unsigned int nGetRandomNumberInRange(int min, int max) {
  4.     ((unsigned int(__cdecl *)(int, int))0x54A4C0)(min, max);
  5. }
  6.  
  7. int nCountCompsInRule(signed int compRulesBits) {
  8.     ((int(__cdecl *)(signed int))0x520990)(compRulesBits);
  9. }
  10.  
  11. using namespace plugin;
  12.  
  13. int randomId, numberId, result;
  14.  
  15. class NewChooseComponent {
  16. public:
  17.     static int Choose(int type, signed int compRulesBits) {
  18.         switch (type) {
  19.         case 1:
  20.         case 2:
  21.             numberId = nCountCompsInRule(compRulesBits);
  22.             result = (compRulesBits >> 4 * nGetRandomNumberInRange(0, numberId)) & 0xF;
  23.             break;
  24.         case 3:
  25.             numberId = nCountCompsInRule(compRulesBits);
  26.             randomId = nGetRandomNumberInRange(-1, numberId);
  27.             if (randomId == -1) {
  28.                 result = -1;
  29.                 break;
  30.             }
  31.             result = (compRulesBits >> 4 * randomId) & 0xF;
  32.             break;
  33.         case 4:
  34.             result = nGetRandomNumberInRange(0, 6);
  35.             break;
  36.         default:
  37.             result = -1;
  38.             break;
  39.         }
  40.         return result;
  41.     }
  42.  
  43.     NewChooseComponent() {
  44.         patch::RedirectJump(0x5209C0, Choose);
  45.     };
  46. } NewChooseComponents;
  47.  

Теперь при сборке выходит другая ошибка:
Цитировать
1>------ Перестроение всех файлов начато: проект: III_NewChooseComponent, Конфигурация: GTA3 Release Win32 ------
1>D:\Programs\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\CL.exe /c /I"D:\Projects\plugin-sdk\plugin_iii\\" /I"D:\Projects\plugin-sdk\plugin_iii\game_iii\\" /I"D:\Projects\plugin-sdk\shared\\" /Zi /nologo /W3 /WX- /diagnostics:classic /sdl /O2 /Oi /Oy- /GL /D _NDEBUG /D _USING_V110_SDK71_ /D _CRT_SECURE_NO_WARNINGS /D _CRT_NON_CONFORMING_SWPRINTFS /D GTA3 /D "GTAGAME_NAME=\"3\"" /D "GTAGAME_ABBR=\"3\"" /D "GTAGAME_ABBRLOW=\"3\"" /D "GTAGAME_PROTAGONISTNAME=\"Claude\"" /D "GTAGAME_CITYNAME=\"Liberty City\"" /D PLUGIN_SGV_10EN /D _USING_V110_SDK71_ /D _WINDLL /D _MBCS /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /std:c++latest /Fo"D:\Projects\GTA-Projects\III_NewChooseComponent\.obj\GTA3\Release\\" /Fd"D:\Projects\GTA-Projects\III_NewChooseComponent\.obj\GTA3\Release\vc141.pdb" /Gd /TP /analyze- /errorReport:prompt /Zc:threadSafeInit- III_NewChooseComponent.cpp
1>III_NewChooseComponent.cpp
1>D:\Programs\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.10.25017\bin\HostX86\x86\link.exe /ERRORREPORT:PROMPT /OUT:"D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.asi" /NOLOGO /LIBPATH:"D:\Projects\plugin-sdk\output\lib\\" plugin_iii.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /PDB:"D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.pdb" /SUBSYSTEM:WINDOWS,"5.01" /OPT:REF /OPT:ICF /LTCG /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.lib" /MACHINE:X86 /SAFESEH /DLL "D:\Projects\GTA-Projects\III_NewChooseComponent\.obj\GTA3\Release\III_NewChooseComponent.obj"
1>plugin_iii.lib(Patch.obj) : error LNK2001: неразрешенный внешний символ ""int __cdecl plugin::GetGlobalAddress(int)" (?GetGlobalAddress@plugin@@YAHH@Z)"
1>D:\Games\Grand Theft Auto III\scripts\III_NewChooseComponent.III.asi : fatal error LNK1120: неразрешенных внешних элементов: 1
1>Сборка проекта "III_NewChooseComponent.vcxproj" завершена с ошибкой.
========== Перестроение всех проектов: успешно: 0, с ошибками: 1, пропущено: 0 ==========

UPDATE:
Спасибо DK за подсказку. Ошибка исчезла после обновление проекта. Готовый код плагина здесь https://github.com/kenkingGitHub/GTA-Projects/blob/master/NewChooseComponent/NewChooseComponent.cpp (https://github.com/kenkingGitHub/GTA-Projects/blob/master/NewChooseComponent/NewChooseComponent.cpp)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Октябрь 30, 2018, 09:36:21 pm
Здравствуйте решил попробовать plugin-sdk. Очень крутая вещь, при глубоких знаниях с++, можно творит настоящие чудеса.
  Объясню свой вопрос для GTA San Andreas есть moonloder, на нем писать одно удовольствие, поменял немного в скрипте кое-что, просто перезагрузить скрипт не выходя из игры, такой пустяк экономить очень много  времени. Хотел у вас спросить про плагин который позволяет перегружать другой плагин налету,  не выходя  при этом из игры.  Это ускорит освоения написание плагинов. А то Выходи из игры, потом  снова заходи, потеря времени.

 вот мой первый плагин.

Код: C++
  1.  
  2. #include "plugin_vc.h"
  3. #include "common.h"
  4. #include "CTimer.h"
  5. #include "CStreaming.h"
  6. #include "CHud.h"
  7.  
  8. using namespace plugin;
  9.  
  10. class PlayerWeapon {
  11. public:
  12.     PlayerWeapon() {
  13.         static int keyPressTime = 0;
  14.         Events::gameProcessEvent += [] {
  15.             CPed *playa = FindPlayerPed();
  16.             if (playa && KeyPressed(VK_TAB) && CTimer::m_snTimeInMilliseconds - keyPressTime > 500) {
  17.                 keyPressTime = CTimer::m_snTimeInMilliseconds;
  18.                 CHud::SetHelpMessage("eee", true, false, false);
  19.  
  20.  
  21.             }
  22.         };
  23.     }
  24. } playerWeapon;
  25.  
  26.  

Скажите пожалуйста Будьте так добры, что-то не так всем Ясно понимаю, Почему  имя  оружие и его id. Не подходит для получения оружия.
Если Вас не затруднит, Скажите пожалуйста  какие id  писать?
Код: C++
  1. CStreaming::RequestModel(MODEL_M4, 2);
  2. CStreaming::LoadAllRequestedModels(false);
  3. playa->GiveWeapon(WEAPON_M4, 10, true);
  4. playa->SetCurrentWeapon(WEAPON_M4);
  5. CStreaming::SetModelIsDeletable(MODEL_M4);
  6.  


Исправил тег на cpp
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 31, 2018, 08:58:01 am
Цитировать
Почему  имя  оружие и его id. Не подходит для получения оружия.
Если Вас не затруднит, Скажите пожалуйста  какие id  писать?
В каком смысле не подходят? Смотри перечисления
Код: C++
  1. eWeaponModel
  2. eWeaponType

Для кода в сообщениях используй [code=cpp
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 19, 2018, 11:59:15 pm
Спасибо большое за ваш ответ уважаемый kenking. перечисления в смысле emum именованные константы? Прошу прощения, но разобраться в чём-то новом, бывает в начале очень трудно.  Главное как говорится, чтобы лед тронулся)))).  Сейчас, конечно за мои вопросы по cleo  мне стыдно. Теперь кажется всё Элементарно, чем тогда.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 20, 2018, 08:32:33 am
Цитировать
перечисления в смысле emum именованные константы?
Да, в смысле enum.

Цитировать
Сейчас, конечно за мои вопросы по cleo  мне стыдно. Теперь кажется всё Элементарно, чем тогда.
Лучше спросить и разобраться в вопросе, чем не спросить и дальше не знать ответа.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 23, 2018, 04:09:34 am
Здравствуйте всем. Немного подтянул свои знания по c++. Приступил  к написанию  простого плагина  по выводу сообщение оно выводится, но хотел бы у вас спросить, как сделать чтобы оно какое-то время оставалось на экране,  а ни сразу исчезало?
Код: C++
  1. #include "plugin_vc.h"
  2. #include "common.h"
  3. #include "CTimer.h"
  4. #include "CStreaming.h"
  5. #include "CHud.h"
  6.  
  7. using namespace plugin;
  8.  
  9. class msg {
  10. public:
  11.         msg() {
  12.                 static int keyPressTime = 0;
  13.                 Events::gameProcessEvent += [] {
  14.                         CPed *playa = FindPlayerPed();
  15.                         if (playa && KeyPressed(VK_TAB) && CTimer::m_snTimeInMilliseconds - keyPressTime > 500) {
  16.                                 keyPressTime = CTimer::m_snTimeInMilliseconds;
  17.                                 CHud::SetMessage("kj");
  18.                         }
  19.                 };
  20.         }
  21. } msg;
  22.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 23, 2018, 12:26:38 pm
Код: C++
  1. #include "CMessages.h"
  2. CMessages::AddMessageJumpQ(L"kj", 5000, 0);
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 23, 2018, 07:57:18 pm
Спасибо большое за ваш ответ уважаемый kenking.  Сообщения выводиться на экран  так CMessages::AddMessageJumpQ( "kj", 1000, 0);  после обновления.  Использую enum,  с ним  удобнее.
Код: C++
  1. if (playa && KeyPressed(key::M) && CTimer::m_snTimeInMilliseconds - keyPressTime > 500) {
  2. keyPressTime = CTimer::m_snTimeInMilliseconds;
  3. CMessages::AddMessageJumpQ( "model loaded", 1000, 0);
  4.  
Хотел у вас спросить как можно получить координаты игрока? Конечно  этот вопрос для Вас кажется банальным.  Просто я не нашел подробную документацию о sdk plugun.  Старался сам найти, но увы.  Хочется освоить  эту  крутую вещь, вижу ее огромный потенциал.

Хотел вывести координаты игрока на экран не получается, помогите, пожалуйста, советом.

Код: C++
  1. #include "plugin_vc.h"
  2. #include "common.h"
  3. #include "CTimer.h"
  4. #include "CStreaming.h"
  5. #include "CHud.h"
  6. #include "CMessages.h"
  7. using namespace plugin;
  8. enum key {
  9.         F1 = 112, F2 = 113, F3 = 114, F4 = 115,
  10.         F5 = 116, F6 = 117, F7 = 118, F8 = 119, F9 = 120, F10 = 121,
  11.         F11 = 122, F12 = 123, NUM_LOCK = 144, SCROLL_LOCK = 145,
  12.         SEMI_COLON = 186, EQUAL_SIGN = 187, COMMA = 188, DASH = 189,
  13.         PERIOD = 190, FORWARD_SLASH = 191, GRAVE_ACCENT = 192,
  14.         OPEN_BRACKET = 219, BACK_SLASH = 220, CLOSE_BRAKET = 221,
  15.         SINGLE_QUOTE = 222, BACKSPACE = 8, TAB = 9, ENTER = 13,
  16.         SHIFT = 16, CTRL = 17, ALT = 18, PAUSE_BREAK = 19,
  17.         CAPS_LOCK = 20, ESCAPE = 27,
  18.         PAGE_UP = 33, PAGE_DOWN = 34,
  19.         END = 35, HOME = 36, LEFT_ARROW = 37, UP_ARROW = 38,
  20.         RIGHT_ARROW = 39, DOWN_ARROW = 40, INSERT = 45, DELETE_ = 46,
  21.         _0 = 48, _1 = 49, _2 = 50, _3 = 51, _4 = 52, _5 = 53,
  22.         _6 = 54, _7 = 55, _8 = 56, _9 = 57, A = 65, B = 66, C = 67,
  23.         D = 68, E = 69, F = 70, G = 71, H = 72, I = 73, J = 74,
  24.         K = 75, L = 76, M = 77, N = 78, O = 79, P = 80, Q = 81, R = 82,
  25.         S = 83, T = 84, U = 85, V = 86, W = 87, X = 88, Y = 89, Z = 90,
  26.         LEFT_WINDOW = 91, RIGHT_WINDOW = 92, SELECT_KEY = 93,
  27.         NUMPAD0 = 96, NUMPAD1 = 97, NUMPAD2 = 98, NUMPAD3 = 99,
  28.         NUMPAD4 = 100, NUMPAD5 = 101, NUMPAD6 = 102, NUMPAD7 = 103,
  29.         NUMPAD8 = 104, NUMPAD9 = 105, MULTIPLY = 106, ADD = 107,
  30.         SUBTRACT = 109, DECIMAL_POINT = 110, DIVIDE = 111,
  31. };
  32. class msg {
  33. public:
  34.         msg() {
  35.                 static int keyPressTime = 0;
  36.                 Events::gameProcessEvent += [] {
  37.                         CPed *playa = FindPlayerPed();
  38.                         if (playa && KeyPressed(key::M) && CTimer::m_snTimeInMilliseconds - keyPressTime > 500) {
  39.                                 keyPressTime = CTimer::m_snTimeInMilliseconds;      
  40.                                 CVector position = FindPlayerPed(-1)->TransformFromObjectSpace(CVector(0.0f, 5.0f, 0.0f)); // получаем координаты по офсету от игрока ; get coords on offset from player
  41.  
  42.                                 CMessages::AddMessageJumpQ(position, 1000, 0);
  43.                                 //CHud::SetMessage("kj");
  44.                         }
  45.                 };
  46.         }
  47. } msg;
  48.  
  49.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 24, 2018, 01:12:18 am
Для клавиш с буквами алфавита можно использовать символ буквы (заглавной).
Например:
Код: C++
  1. if (KeyPressed('M'))
Для других клавиш есть константы VK_*, например:
VK_TAB - Tab
VK_CONTROL - Ctrl
VK_MENU - Alt
Весь список можно посмотреть здесь (https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes).

Код: C++
  1. class msg {
  2. ...
  3. } msg;
У тебя название класса и переменной одинаковые. Так лучше не делать. Если ты создаешь плагин через Мастер создания проекта, и даешь ему название msg, то мастер назовёт переменную как _msg.

как можно получить координаты игрока?
Есть статическая функция FindPlayerCoors. В Vice City она не принимает никаких входных параметров и возвращает позицию игрока. Перед её вызовом надо проверять, что игрок существует.

Также, у класса CEntity есть метод GetPosition. Этот метод доступен для всех классов, которые наследуют CEntity - т.е. CPed, CVehicle, CObject и другие.

Метод TransformFromObjectSpace можно применять для получения координат со смещением от центра обьекта. Но этот метод ещё не добавлен в версию для Vice City. В качестве замены - для получения координат со смещением можно умножить матрицу игрока на вектор с координатами смещения.

В функцию AddMessageJumpQ надо передавать указатель на C-строку (массив из char или wchar_t). Если хочешь вывести координаты - надо их отформатировать в строку (для этого есть функции plugin::FormatStatic (для получения C-строки) и plugin::Format (для получения std-строки)).

Код: C++
  1. #include "plugin.h"
  2.  
  3. using namespace plugin;
  4.  
  5. class PlayerCoors {
  6. public:
  7.     PlayerCoors() {
  8.         Events::drawingEvent += [] {
  9.             CPed *player = FindPlayerPed();
  10.             if (player) {
  11.                 CVector coors = player->m_placement * CVector(0.0f, 5.0f, 0.0f);
  12.                 gamefont::PrintAt3d(coors, Format("%.2f %.2f %.2f", coors.x, coors.y, coors.z),
  13.                     0, 0, FONT_DEFAULT, 2, 2, color::Pink, true, gamefont::AlignCenter);
  14.             }
  15.         };
  16.     }
  17. } playerCoors;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 24, 2018, 08:39:14 pm
Здравствуйте уважаемый Дмитрий. Большое вам спасибо за ваше подробное объяснение очень вам признателен. Поймите меня правильно,  одно дело учить с++  по книгам, решая  простенькие задачи, как  создать функцию которая принимает целые и дробные числа. И столкнуться с реальным применение знаний на практике. moonloder было бывает легче,  там были  аналоги опкодов, которые являются простыми функциями, тут всё несколько сложнее,  но гораздо интереснее.  Больше возможности для фантазии. Когда кто-то даёт тебе совет, проблема решается быстрее. Благодарю вас за подсказку по поводу клавиш. Пришло в голову использовать emun.

Редко встретишь такого внимательного человека, вот что значит опыт! Буду называть класс и переменную разными  именам, чтобы не было ошибки.

Функция FindPlayerCoors возвращает координаты игрока в виде объекта класса,  если FindPlayerPed  вернула true, то есть игрок найден.

Сейчас наверно,вы будете смеяться над моей тупостью. я попробовал подключить библиотеку string не получается.
Потом пытался получить координаты так string x,y,z=FindPlayerCoors(); понимаю насколько это глупо. Потом хотел их преобразовать .
Код: Text
  1. string x,y,z=FindPlayerCoors();
  2. string coord = plugin::FormatStatic("%.2f %.2f %.2f", x, y, z)
  3. CMessages::AddMessageJumpQ(coord, 1000, 0);
  4.  

 Затем решил  преобразовать  координаты  Матрицы  игрока в строку через массив char.  Поскольку возвращает  объекты класса.
Код: Text
  1. CVector coors = player->m_placement * CVector(0.0f, 5.0f, 0.0f);
  2. Format("%.2f %.2f %.2f", coors.x, coors.y, coors.z);
  3. char a[] = coors.x;
  4. CMessages::AddMessageJumpQ(a, 1000, 0);
  5.  

Понимаете Уважаемый Дмитрий, хочу вывести  координаты  игрока  через функцию CMessages::AddMessageJumpQ();
 Зачем  вообще  хочу разобраться в этом? Cleo не дает воплотить свои идеи в жизнь из-за своей ограниченности.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 24, 2018, 09:13:46 pm
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\KeyCheck.h"
  3. #include "CMessages.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class PlayerCoors {
  8. public:
  9.     PlayerCoors() {
  10.         Events::drawingEvent += [] {
  11.             CPed *player = FindPlayerPed();
  12.             KeyCheck::Update();
  13.             if (KeyCheck::CheckWithDelay('M', 200) && player) {
  14.                 static char message[256];
  15.                 snprintf(message, 256, "x = %.2f; y = %.2f; z = %.2f;", player->GetPosition().x, player->GetPosition().y, player->GetPosition().z);
  16.                 CMessages::AddMessageJumpQ(message, 5000, 3, false);
  17.             }
  18.         };
  19.     }
  20. } playerCoors;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 25, 2018, 06:54:40 pm
Здравствуйте, уважаемый kenking, большое спасибо, что Вы мне ответили. Благодаря Вам, правильно выводятся координаты. Но, я решил сделать функцию, которая возвращает три координаты (х, у, z), но почему-то не получается передать player по указателю. Подскажите, пожалуйста, просто хочется упростить получение координат.
вот мой код.
Код: C++
  1. using namespace plugin;
  2. char getcoordes(CPed *player) {
  3.         static char x[256];
  4.         snprintf(x, 256, "%.2f;", player->GetPosition().x);
  5.         static char y[256];
  6.         snprintf(y, 256, "%.2f;", player->GetPosition().y);
  7.         static char z[256];
  8.         snprintf(z, 256, "%.2f;", player->GetPosition().z);
  9.         return x, y, z;
  10. };
  11. class PlayerCoors {
  12. public:
  13.         PlayerCoors() {
  14.                 Events::drawingEvent += [] {
  15.                         CPed *player = FindPlayerPed();
  16.                         if (KeyPressed('M') && player) {
  17.                                 char x, char y, char z = getcoordes(*player);
  18.                                 char mes[] = "x " << x << "y " << y << "z " << z;
  19.                                 CMessages::AddMessageJumpQ(mes, 5000, 3);
  20.                         }
  21.                 };
  22.         }
  23. } playerCoors;
  24.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 25, 2018, 07:31:21 pm
Цитировать
просто хочется упростить получение координат.
Так ты не упрощаешь, а усложняешь. Функция GetPosition() как раз и возвращает координаты в виде вектора. Почитай про функции в С++ в том числе про возвращаемые значения и передачу параметров в функции по указателю и по ссылке.
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Ноябрь 25, 2018, 10:36:24 pm
string x,y,z=FindPlayerCoors();
То, что ты пытался сделать, называется Structured Binding (https://en.cppreference.com/w/cpp/language/structured_binding), и там надо использовать строго фиксированный синтаксис:
Код: C++
  1. auto [переменные] = Функция_которая_возвращает_обьект
Т.е. получится вот так:
Код: C++
  1. auto [x, y, z] = FindPlayerCoors();

Код: C++
  1. #include "plugin.h"
  2. #include "CMessages.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class PlayerCoors {
  7. public:
  8.     PlayerCoors() {
  9.         Events::gameProcessEvent += [] {
  10.             if (FindPlayerPed()) {
  11.                 auto [x, y, z] = FindPlayerCoors();
  12.                 CMessages::AddMessageJumpQ(FormatStatic("%.2f %.2f %.2f", x, y, z), 1000, 0);
  13.             }
  14.         };
  15.     }
  16. } playerCoors;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 27, 2018, 09:59:26 pm
Цитировать
просто хочется упростить получение координат.
Так ты не упрощаешь, а усложняешь. Функция GetPosition() как раз и возвращает координаты в виде вектора. Почитай про функции в С++ в том числе про возвращаемые значения и передачу параметров в функции по указателю и по ссылке.
Здравствуйте уважаемый kenking. Простите, пожалуйста,  не сразу вам смог ответить.  Вот что у меня получилось,  координаты выводится.

Код: C++
  1. using namespace plugin;
  2.  
  3. char * getcoordes(CPed *player) {
  4.         static char x[256];
  5.         snprintf(x, 256, "x = %.2f;y = %.2f;z = %.2f;", player->GetPosition().x, player->GetPosition().y, player->GetPosition().z);
  6.         return x;      
  7. };
  8. class PlayerCoors {
  9. public:
  10.         PlayerCoors() {
  11.                 Events::drawingEvent += [] {
  12.                         CPed *player = FindPlayerPed();
  13.                         if (KeyPressed('M') && player) {
  14.                                 char *s = getcoordes(player);//
  15.                                 CMessages::AddMessageJumpQ(s, 5000, 3);                 }
  16.                 };
  17.         }
  18. } playerCoors;
  19.  
DK,  вы   написали ещё круче,  чем я  мог подумать,  браво!
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 29, 2018, 07:04:00 pm
Здравствуйте всем. Немного стал  понимать plugin sdk от DK для Vice City.  Поучилось дать игроку оружие. Хочу немного упростить,  сделать функцию , которая  принимает имя оружие , количество патронов. Но к сожалению не получается, подскажите пожалуйста как решить эту проблему, конечно Я понимаю,  что в меня полетят палки, Но  чем больше людей будет уметь писать плагины, Чем лучше.

Код: C++
  1. #include <string>
  2. #include "plugin.h"
  3. #include "common.h"
  4. #include "CStreaming.h"
  5. #include "eWeaponModel.h"
  6. #include "CMessages.h"
  7.  
  8. using namespace plugin;
  9. void givweap(CPed *player, std::string model, int ammo) {
  10.         std::string mane = "MODEL_" + model;
  11.         std::string type = "WEAPONTYPE_" + model;
  12.         CStreaming::RequestModel(mane, 0);// загрузить модель оружие
  13.         CStreaming::LoadAllRequestedModels(false);
  14.         player->GiveWeapon(type, ammo, true);
  15.         player->SetCurrentWeapon(type);
  16.         CStreaming::SetModelIsDeletable(name);// модели оружия смотрите eWeaponModel.h
  17.  
  18. };
  19. class weapon {
  20. public:
  21.         bool m_bPressed;
  22.         weapon() {
  23.                 static bool bPressedM = false;
  24.                 Events::gameProcessEvent += [] {
  25.                         if ((KeyPressed('M')) && (!bPressedM)) {
  26.                                 bPressedM = true;
  27.                                 CPed *player = FindPlayerPed();
  28.                                 if (!player) return;
  29.                                 givweap(player,"TEC9",12);// функция дать оружие и патроны
  30.                 }
  31.                         // Если отпустили.
  32.                         if (!KeyPressed('M')) bPressedM = false;
  33.  
  34.                 };
  35.  
  36.         }
  37.  
  38. } giveweapon;
  39.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 07, 2018, 07:43:27 pm
Здравствуйте уважаемые люди. все  думал как решить эту проблему?  Нашел, конечно громоздкое решение.
Может кому поможет.
Код: C++
  1. #include<string>
  2. #include "plugin_vc.h"
  3. #include "common.h"
  4. #include "CStreaming.h"// загрузка моделей.
  5. #include "eWeaponModel.h" // имя моделей имя.
  6. #include "eWeaponType.h"// тип моделей оружие.
  7.  
  8. using namespace std;
  9.  
  10. using namespace plugin;
  11. void weapongive(CPed *player, string name, int ammo) {
  12.         if (name == "TEC9") {
  13.                 CStreaming::RequestModel(MODEL_TEC9, 0);// загрузить модель оружие
  14.                 CStreaming::LoadAllRequestedModels(false);// Ставить модель в очередь
  15.                 player->GiveWeapon(WEAPONTYPE_TEC9, ammo, true);// дает оружие
  16.                 player->SetCurrentWeapon(WEAPONTYPE_TEC9);// устанавливает его в руке.
  17.                 CStreaming::SetModelIsDeletable(MODEL_TEC9);// удаляет модель
  18. }       if (name == "UZI") {//модели оружия смотрите eWeaponModel.h
  19.                 CStreaming::RequestModel(MODEL_UZI, 0);// загрузить модель оружие
  20.                 CStreaming::LoadAllRequestedModels(false);
  21.                 player->GiveWeapon(WEAPONTYPE_UZI, ammo, true);
  22.                 player->SetCurrentWeapon(WEAPONTYPE_UZI);
  23.                 CStreaming::SetModelIsDeletable(MODEL_UZI);// модели оружия смотрите eWeaponModel.h
  24.         }
  25. }
  26.  
  27.  
  28. class weapon {
  29. public:
  30. weapon() {      Events::drawingEvent += [] {
  31.         if (KeyPressed('M')) {
  32.                 CPed *player = FindPlayerPed();
  33.                 if (!player) return;// находим игрока
  34.                 weapongive(player,"UZI", 10);//передаем указатель на игрока, имя оружие и кол-во патронов
  35.                 }
  36.         };
  37.         }
  38. } weapons;
  39.  

Скажите пожалуйста, В каком файле посмотреть функция проверок, мне необходимо проверка  игрок в машине?  Как дать денег игроку?
Броню и здоровые мы даём  вот так
   player->m_fHealth = 150;//здоровье
   player->m_fArmour = 200;// броня





Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 08, 2018, 10:11:37 am
Код: C++
  1. player->m_bInVehicle

Код: C++
  1. CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 5000;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 09, 2018, 12:45:54 am
Спасибо большое вам за ответ уважаемый kenking. Просто разбирался в sdk, как там все устроено. Вот какой плагин получится
Код: C++
  1. #include "plugin_vc.h"
  2. #include "common.h"
  3. #include "CMessages.h"
  4. #include "CWorld.h"
  5.  
  6. using namespace plugin;
  7.  
  8. bool isPedInVehicle(CPed * player) {
  9.         return player->m_bInVehicle && player->m_pVehicle != NULL;
  10. }
  11. class incar {//имя класса
  12. public:
  13.         incar() {      
  14.               Events::gameProcessEvent += [] {////обработчик событий игры
  15.                    CPed *player = FindPlayerPed();// найти игрока
  16.                    if (!player) return;//проверка найден игрок найти игрока
  17.                    if (KeyPressed('M')) {//если м нажата
  18.                            if (isPedInVehicle(player)) {// в авто игрок?
  19.                                    CVehicle *p = player->m_pVehicle;// получить указатель на хенлд авто
  20.                                    p->m_fHealth = 1000;// здоровье авто  
  21.                                    p->m_nPrimaryColor = 0;// уст 1 цвет авто.
  22.                                    p->m_nSecondaryColor = 0;// 2 цвет авто.
  23.                                    CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 5000;// дать денег
  24.                                    
  25.                                    static char x[256];
  26.                                    snprintf(x, 256, "x = %.2f;y = %.2f;z = %.2f;", p->GetPosition().x, p->GetPosition().y, p->GetPosition().z);
  27.                                    CMessages::AddMessageJumpQ(x, 3000, 0);// сообщение на экран
  28.                            }
  29.                            else { CMessages::AddMessageJumpQ("No in vehicle seet!", 3000, 0); }
  30.            }    };
  31.        
  32. }
  33. } incars;
  34.  

Хотел у вас спросить.
Как найти случайную машину?
Как заставить машину ехать в определенные координаты?
Как проверить находится ли машина в заданных координатах?


все это нужно для будущего плагина для воспроизведения маршрута движения



Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 09, 2018, 10:29:32 am
Цитировать
Вот какой плагин получится
Как ты любишь усложнять. Зачем писать функцию isPedInVehicle, если player->m_bInVehicle и так показывает, что игрок в авто?
Код: C++
  1. #include "plugin.h"
  2. #include "CWorld.h"
  3. #include "extensions\KeyCheck.h"
  4. #include "CMessages.h"
  5.  
  6. using namespace plugin;
  7.  
  8. class Test {
  9. public:
  10.     Test() {
  11.         Events::gameProcessEvent += [] {
  12.             CPed *player = FindPlayerPed();
  13.             KeyCheck::Update();
  14.             if (player && player->m_bInVehicle && player->m_pVehicle && KeyCheck::CheckWithDelay('M', 200)) {
  15.                 player->m_pVehicle->m_fHealth = 1000.0f;
  16.                 player->m_pVehicle->m_nPrimaryColor = 0;
  17.                 player->m_pVehicle->m_nSecondaryColor = 0;
  18.                 static char message[256];
  19.                 snprintf(message, 256, "x = %.2f; y = %.2f; z = %.2f;", player->m_pVehicle->GetPosition().x, player->m_pVehicle->GetPosition().y, player->m_pVehicle->GetPosition().z);
  20.                 CMessages::AddMessageJumpQ(message, 3000, false);
  21.                 CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 5000;
  22.             }
  23.         };
  24.     }
  25. } test;

Или так:
Код: C++
  1. #include "plugin.h"
  2. #include "CWorld.h"
  3. #include "extensions\KeyCheck.h"
  4. #include "CMessages.h"
  5.  
  6. using namespace plugin;
  7.  
  8. class Test {
  9. public:
  10.     Test() {
  11.         Events::gameProcessEvent += [] {
  12.             CVehicle *vehicle = FindPlayerVehicle();
  13.             KeyCheck::Update();
  14.             if (vehicle && KeyCheck::CheckWithDelay('M', 200)) {
  15.                 vehicle->m_fHealth = 1000.0f;
  16.                 vehicle->m_nPrimaryColor = 0;
  17.                 vehicle->m_nSecondaryColor = 0;
  18.                 static char message[256];
  19.                 snprintf(message, 256, "x = %.2f; y = %.2f; z = %.2f;", vehicle->GetPosition().x, vehicle->GetPosition().y, vehicle->GetPosition().z);
  20.                 CMessages::AddMessageJumpQ(message, 3000, false);
  21.                 CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 5000;
  22.             }
  23.         };
  24.     }
  25. } test;

Цитировать
Как найти случайную машину?
Как проверить находится ли машина в заданных координатах?
Код: C++
  1. #include "plugin.h"
  2. #include "CFont.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class Test {
  7. public:
  8.     Test() {
  9.         Events::drawingEvent += [] {
  10.             CPed *player = FindPlayerPed();
  11.             if (player) {
  12.                 for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {
  13.                     CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  14.                     if (vehicle && (DistanceBetweenPoints(player->GetPosition(), vehicle->GetPosition()) < 5.0f)) {
  15.                         CFont::SetScale(0.5f, 1.0f);
  16.                         CFont::SetColor(CRGBA(255, 255, 255, 255));
  17.                         CFont::SetJustifyOn();
  18.                         CFont::SetFontStyle(1);
  19.                         CFont::SetPropOn();
  20.                         CFont::SetWrapx(600.0f);
  21.                         wchar_t text[64];
  22.                         swprintf(text, L"ID vehicle %.d", vehicle->m_nModelIndex);
  23.                         CFont::PrintString(10.0f, 10.0f, text);
  24.                     }
  25.                 }
  26.             }
  27.         };
  28.     }
  29. } test;

Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 09, 2018, 03:16:58 pm
Спасибо большое за ваш ответ уважаемый kenking. Но новички  часто усложняю простые вещи.  Думаю всё приходит с опытом,  чем больше пишешь, тем лучше получается. Возможно через год буду сам в шоке от своего кода, просто нужно время и практика. Скажите пожалуйста вы используете KeyCheck  чем он отличается  от KeyPressed('M')?.  С ним часто возникают проблемы.  Хочется проверять клавиши  так нажал  и только когда отпустишь она вернула true, Чтобы избежать повторного нажатия и клавиша будет нажата только  1 раз.  Допустим при нажатии клавиши  даётся игроку  500$  я немного  дольше подержал  и бах у меня 5 миллионов. Это настоящая проблема.
Спасибо большое за вас Благодарю вас что ответили на  на вопрос,   буду разбирать в этом. Думал что есть  аналог опкода 05F0: 3@ = random_vehicle_near_point 0@ 1@ 2@ in_radius 10.0 find_next 1 pass_wrecked 0 //IF and SET
А тут всё по-другому.
Странно, но игра вылетает, если приближаюсь к любому авто.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 10, 2018, 09:48:52 am
Цитировать
KeyCheck
http://forum.gtabuilder.ru/index.php?topic=337.msg2356#msg2356 (http://forum.gtabuilder.ru/index.php?topic=337.msg2356#msg2356)

Цитировать
KeyPressed('M')?.  С ним часто возникают проблемы.  Хочется проверять клавиши  так нажал  и только когда отпустишь она вернула true, Чтобы избежать повторного нажатия и клавиша будет нажата только  1 раз.  Допустим при нажатии клавиши  даётся игроку  500$  я немного  дольше подержал  и бах у меня 5 миллионов. Это настоящая проблема.
Здесь http://forum.gtabuilder.ru/index.php?topic=337.msg3355#msg3355 (http://forum.gtabuilder.ru/index.php?topic=337.msg3355#msg3355) в своём коде ты правильно используешь KeyPressed, а в предыдущем сообщении http://forum.gtabuilder.ru/index.php?topic=337.msg3422#msg3422 (http://forum.gtabuilder.ru/index.php?topic=337.msg3422#msg3422) уже не правильно.

Цитировать
Думал что есть  аналог опкода 05F0: 3@ = random_vehicle_near_point 0@ 1@ 2@ in_radius 10.0 find_next 1 pass_wrecked 0 //IF and SET
А тут всё по-другому.
Так там похоже сделано, просто действия "завёрнуты" в опкод и ты их не видишь.

Цитировать
Странно, но игра вылетает, если приближаюсь к любому авто.

(http://thumbs2.imagebam.com/2e/75/8d/b7bb601057994144.jpg) (http://www.imagebam.com/image/b7bb601057994144)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 10, 2018, 08:57:52 pm
Спасибо вам большое уважаемый  kenking  за ваш ответ, выдали мне очень полезные ссылки.  Понимаете когда начинаешь изучать что-то новое всегда возникают трудности. Но я чётко понимаю огромным потенциал  создание плагинов. Конечно путь будет очень тернист,  Но это того стоит.  Одно дело решать задачи из учебников,  совсем другое  столкнуться с реальным проектом, при работе с которым, получаешь колоссальный, бесценный опыт.  Конечно им делишься с другими людьми.
Вот что у меня получилось,  но ищет как-то плохо.  Скажите пожалуйста, Почему поиск работает как-то рандомно? Очень интересно ваше мнение.
Код: C++
  1. #include "plugin.h"
  2. #include "CWorld.h"
  3. #include "extensions\KeyCheck.h"
  4. #include "CMessages.h"
  5.  
  6. #include "CFont.h"
  7.  
  8. #include "CAutomobile.h"
  9. #include "CModelInfo.h"
  10. using namespace plugin;
  11.  
  12. class Message {//имя класса
  13. public:
  14.  Message() {Events::gameProcessEvent += [] {//обработчик событий игры
  15.         KeyCheck::Update();
  16.         if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  17.         CPed *player = FindPlayerPed();// найти игрока
  18.         if (!player) return;// проверка найден игрок
  19.         for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {// перебираем путь
  20.          CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  21.          if (vehicle != NULL) {// если авто есть
  22.          if (vehicle && (DistanceBetweenPoints(player->GetPosition(), vehicle->GetPosition()) < 5.0f)) {
  23.                 CMessages::AddMessageJumpQ("this is car", 500, 0);//выводит сообщение на экран
  24.          }
  25.         else {  CMessages::AddMessageJumpQ("not found car", 500, 0);
  26.          break;
  27.          }
  28.          }      };
  29.         }
  30.         };
  31.         }
  32. } message;
  33.  
  34.  
https://www.youtube.com/watch?v=6f-KGoP8_Mo&feature=youtu.be (ftp://www.youtube.com/watch?v=6f-KGoP8_Mo&feature=youtu.be)
Так лучше работает
Код: C++
  1.  
  2. class Message {//имя класса
  3. public:
  4.  Message() {Events::gameProcessEvent += [] {//обработчик событий игры
  5.         KeyCheck::Update();
  6.         if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  7.         CPed *player = FindPlayerPed();// найти игрока
  8.         if (!player) return;// проверка найден игрок
  9.         for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {// перебираем путь
  10.          CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  11.          if (vehicle != NULL ) {// если авто есть
  12.          if (vehicle && (DistanceBetweenPoints(player->GetPosition(), vehicle->GetPosition()) < 20.0f) && vehicle->m_fHealth > 50) {
  13.                 CMessages::AddMessageJumpQ("this is car", 1000, 0);//выводит сообщение на экран
  14.                 vehicle->m_wBombTimer = 160;// взрыв по таймеру
  15.                 break;      
  16.          }
  17.         else {  CMessages::AddMessageJumpQ("not found car", 1000, 0);
  18.          }
  19.          }      };
  20.         }
  21.         };
  22.         }
  23. } message;
  24.  
  25.  

https://www.youtube.com/watch?v=1Y6XSOLO_Vk&feature=youtu.be  (ftp://www.youtube.com/watch?v=1Y6XSOLO_Vk&feature=youtu.be)

все заработало как надо.
Код: C++
  1. void randomfindcar(CPed *p, float r) {
  2.  for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {// перебираем путь
  3.                 CVehicle *v = CPools::ms_pVehiclePool->GetAt(i);// если авто есть
  4.                 if (v != NULL && v && DistanceBetweenPoints(p->GetPosition(), v->GetPosition()) < r && v->m_fHealth > 50) {
  5.                                 CMessages::AddMessageJumpQ("this is car", 1000, 0);//выводит сообщение на экран
  6.                                 v->m_wBombTimer = 160;// взрыв по таймеру
  7.                         break;}
  8.                 else {  CMessages::AddMessageJumpQ("not found car", 1000, 0);}
  9.  }
  10. };
  11.  
  12.  
  13. class Message {//имя класса
  14. public:
  15.  Message() {Events::gameProcessEvent += [] {//обработчик событий игры
  16.         KeyCheck::Update();
  17.         if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  18.         CPed *player = FindPlayerPed();// найти игрока
  19.         if (!player) return;// проверка найден игрок
  20.         randomfindcar(player, 20.0);}
  21.         };
  22.         }
  23. } message;
  24.  
  25.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: DK от Декабрь 12, 2018, 11:08:43 am
Если надо найти один рандомный транспорт - то надо весь созданный транспорт записать в список, и из списка выбрать рандомный элемент.
Код: C++
  1. CVehicle *GetRandomVehicle(CVector const &posn, float radius) {
  2.     std::vector<CVehicle *> vehicles;
  3.     for (auto vehicle : CPools::ms_pVehiclePool) {
  4.         if (DistanceBetweenPoints(vehicle->GetPosition(), posn) <= radius)
  5.             vehicles.push_back(vehicle);
  6.     }
  7.     return vehicles.empty() ? nullptr : vehicles[plugin::Random(0, vehicles.size() - 1)];
  8. }
Функцию можно оптимизировать, - выделяя память под список только один раз
Код: C++
  1. CVehicle *GetRandomVehicle(CVector const &posn, float radius) {
  2.     static std::vector<CVehicle *> vehicles(CPools::ms_pVehiclePool->m_nCapacity);
  3.     unsigned int counter = 0;
  4.     for (auto vehicle : CPools::ms_pVehiclePool) {
  5.         if (DistanceBetweenPoints(vehicle->GetPosition(), posn) <= radius)
  6.             vehicles[counter++] = vehicle;
  7.     }
  8.     return counter == 0 ? nullptr : vehicles[plugin::Random(0, counter - 1)];
  9. }
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 12, 2018, 06:55:34 pm
 Здравствуйте, уважаемый Дмитрий! Спасибо большое, что несмотря на Вашу огромную загруженность, нашли время мне ответить. Основная прелесть С++ в том, что одну и ту же задачу можно решить множеством способов. Вы предоставили два варианта функций. Подскажите, пожалуйста, как именно их вызывать? Дело в том, что я занимаюсь выкладыванием простых примеров на основе Вашего плагина в группу https://vk.com/gtabuilder. Чтобы расшевелить интерес у аудитории, показать им что это не так сложно, чем кажется. Год назад только от одного слова С++ у меня начинался ступор. Думал: "у меня же нет Нобелевской премии, чтобы в нем разбираться?". Два месяца почитал книги и уже основы понимаю. Думал, будет тяжелее.

 Скажите пожалуйста, как заставить автомобиль ехать на определенные координаты и проверить, находится ли он в этих координатах?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 13, 2018, 08:34:45 am
Цитировать
Вы предоставили два варианта функций. Подскажите, пожалуйста, как именно их вызывать?
Смотри аргументы функции и возвращаемое значение.

Цитировать
Зачем?
Вот
Цитировать
Если надо найти один рандомный транспорт

Цитировать
проверить, находится ли он в этих координатах?
Сравнение дистанции между двумя точками с радиусом как раз и есть эта проверка.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 13, 2018, 01:22:45 pm
Благодарю вас,  что уделяйте мне ваше время уважаемый  kenking.  Мне очень хочется чтобы больше людей писали плагины.  Бывает нелегко разобраться в этом, в книгах Мы изучали  работу с числами и строками, тут немного другое, поэтому сложнее,  но интересно. писал раньше  на cleo, но у с++  гораздо больше возможностей, всё-таки  пишешь плагин всё равно в стиле cleo, по внутренней привычке.  Например, так В функцию CVehicle *v = randomfindcar(player, 20.0);;//передаем указатель на игрока, размер диаметра радиуса через дробное число, возвращаем указатель на найденный автомобиль. Чтобы  машина ехала на определенные координаты, думал, что нужно использовать
    CAutoPilot m_autopilot; но как?  Буду очень вам признателен если вы  подскажите мне.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 13, 2018, 06:57:49 pm
Цитировать
Чтобы  машина ехала на определенные координаты, думал, что нужно использовать
    CAutoPilot m_autopilot; но как?  Буду очень вам признателен если вы  подскажите мне.
Чтобы разобраться, надо смотреть в базе, как устроен соответствующий опкод 00A7: car 0@ drive_to 103.1 -832.3 9.317

Если я правильно его разобрал, то получается так:
Код: C++
  1. #include "plugin.h"
  2. #include "CWorld.h"
  3. #include "CTimer.h"
  4. #include "CVehicle.h"
  5. #include "CCarCtrl.h"
  6.  
  7. using namespace plugin;
  8.  
  9. class Test {
  10. public:
  11.     Test() {
  12.         Events::gameProcessEvent += [] {
  13.             CPed *player = FindPlayerPed();
  14.             if (player) {
  15.                 for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {
  16.                     CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  17.                     if (vehicle && (DistanceBetweenPoints(player->GetPosition(), vehicle->GetPosition()) < 5.0f)) {
  18.                         CVector offset = { 0.0f, 10.0f, 0.0f };
  19.                         CVector point = vehicle->m_placement * offset;
  20.                        
  21.                         //опкод 00A7:
  22.                         if (point.z <= -100.0f)
  23.                             point.z = CWorld::FindGroundZForCoord(point.x, point.y);
  24.                         point.z = vehicle->GetDistanceFromCentreOfMassToBaseOfModel() + point.z;
  25.                         if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(vehicle, point))
  26.                             vehicle->m_autopilot.m_nCarMission = 9;
  27.                         else
  28.                             vehicle->m_autopilot.m_nCarMission = 8;
  29.                         vehicle->m_nType |= 0x18;
  30.                         vehicle->m_nVehicleFlags.bIsEngineOn = 1;
  31.                         if (vehicle->m_autopilot.m_nCruiseSpeed <= 6)
  32.                             vehicle->m_autopilot.m_nCruiseSpeed = 6;
  33.                         else
  34.                             vehicle->m_autopilot.m_nCruiseSpeed = vehicle->m_autopilot.m_nCruiseSpeed;
  35.                         vehicle->m_autopilot.m_nTimeToStartMission = CTimer::m_snTimeInMilliseconds;
  36.  
  37.                     }
  38.                 }
  39.             }
  40.         };
  41.     }
  42. } test;

Но! CAutoPilot не полностью разобран в sdk и в CCarCtrl::JoinCarWithRoadSystemGotoCoors ошибочный лишний третий параметр.

Поэтому пока это не исправили в sdk, можно использовать скриптовую команду:
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\ScriptCommands.h"
  3. #include "eScriptCommands.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class Test {
  8. public:
  9.     Test() {
  10.         Events::gameProcessEvent += [] {
  11.             CPed *player = FindPlayerPed();
  12.             if (player) {
  13.                 for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {
  14.                     CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  15.                     if (vehicle && (DistanceBetweenPoints(player->GetPosition(), vehicle->GetPosition()) < 5.0f)) {
  16.                         CVector offset = {0.0f, 10.0f, 0.0f};
  17.                         CVector point = vehicle->m_placement * offset;
  18.                         Command<COMMAND_CAR_GOTO_COORDINATES>(CPools::GetVehicleRef(vehicle), point.x, point.y, point.z);
  19.                     }
  20.                 }
  21.             }
  22.         };
  23.     }
  24. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 21, 2018, 04:19:41 pm
Здравствуйте уважаемый kenking, благодарю Вас за ответ. Очень долго его обдумывал, чтобы правильно понять. Очень жаль, что CАutoPilot пока не разобран в SDK , у него огромное будущее и колоссальные возможности. В моих экспериментах использование цикла while приводит к зависанию. А почему? Ведь он очень удобен. Я написал функцию в виде класса. Но почему-то она зависает. Я комментировал почти каждую строчку кода, чтобы было понятно. Но все равно не пойму где ошибка?
 
При нажатии кнопки М, мы передаем в конструктор класса. Первым параметром имя файла с расширением и указатель на хендл авто в котором сидит игрок. Потом вызываем метод writte, но как записать координаты без использования цикла while? В метод getcord мы передаём ссылку на очередь и ассоциативный массив. Потом вводим его по ключам x,y,z значения. Но в теории все хорошо, а на практике при записи все зависает, при выводе ничего не выводится. Я  тут уже неделю голову ломаю. Надеюсь на Ваш совет.
Код: C++
  1. #include<string>
  2. #include<fstream>
  3. #include<queue>
  4. #include<map>
  5. #include "plugin.h"
  6. #include "common.h"
  7. #include "CWorld.h"
  8. #include "extensions\KeyCheck.h"
  9. #include "CMessages.h"
  10. #include "CAutomobile.h"
  11. #include "CModelInfo.h"
  12. using namespace plugin;
  13.  
  14. using namespace std;
  15.  
  16. queue<double>q = {};// очередь для хранение всех значение координат из файла.
  17. map<string, double> pos;// ассоциативный массив
  18. //bool readf проверка прочитан файл координат?
  19. class fille {bool readf = false;  static char cord[255];
  20. public: string path;// адрес файла
  21. fstream f;
  22. fille(string path, CVehicle *v) {CVehicle *v1 =  v;
  23.  
  24. f.open(path, fstream::in | fstream::app | fstream::out);
  25. if (f.is_open()) { }}// файл открыть.
  26.        
  27. void write(){   CVehicle *v1 = v1;      char x[256];
  28.         snprintf(x, 256, "x = %.2f;y = %.2f;z = %.2f;", v1->GetPosition().x, v1->GetPosition().y, v1->GetPosition().z);
  29.         if (x != cord){ char cord =  x[256];// сравнить с предыдущей значение
  30.         f << x; }// записать координаты в файл.
  31. }
  32. template <class t1, class t2>// это метод как шабло. функция.
  33. void getcord(t1 *q, t2 *pos) {int a; // принимает очередь и ассо массив.
  34. if (readf == false){ while (f >> a) { q->push(a); // считываем файл в очередь
  35.         readf = true;}//заполнена очередь, уст флаг.
  36. }
  37. if (q->empty()) { readf = false; }// если очередь пуста, уст флаг
  38.  
  39. else {pos->clear();// очистить ассо массив
  40.                 pos->emplace("x", q->front());  q->pop();// добавить значение по ключу
  41.                 pos->emplace("y", q->front());  q->pop();// и удаляет из очереди.
  42.                 pos->emplace("z", q->front());  q->pop();}
  43. }
  44. ~fille() {      f.close();} // деструктор, закрывает файл.
  45. };
  46. char fille::cord[255]; // предущеннее значение
  47.  
  48. bool isPedInVehicle(CPed * player) {return player->m_bInVehicle && player->m_pVehicle != NULL;}
  49.  
  50. class Message {//имя класса
  51. public:
  52.         Message() {     Events::gameProcessEvent += [] {//обработчик событий игры
  53.                 CPed *player = FindPlayerPed();// найти игрока
  54.                 if (!player) return;// проверка найден игрок
  55.                 if (!isPedInVehicle(player)) return; // в авто игрок?
  56.                 KeyCheck::Update();
  57.                 if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  58.                         CMessages::AddMessageJumpQ("red on", 5000, 3);//выводит сообщение на экран              
  59.                         CVehicle *v = player->m_pVehicle;// получить указатель на хенлд авто
  60.                         fille f("cord.txt", v);  // Вызывается конструктор.
  61.                         f.write();// записать координаты в файл.
  62.                 KeyCheck::Update();
  63.                 if (KeyCheck::CheckWithDelay('B', 200)) {//если м нажата
  64.                         f.getcord(&q, &pos);// получить координаты из файла.
  65.                         char s[256];
  66.                         snprintf(s, 256, "x = %.2f;y = %.2f;z = %.2f;", pos["x"], pos["y"], pos["z"]);
  67.                         CMessages::AddMessageJumpQ(s, 5000, 3);
  68.  
  69.                         }
  70.                   }  
  71.                 };
  72.         }
  73. } message;
  74.  
  75.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 22, 2018, 04:52:47 pm
Не совсем понимаю твою задумку. Для чего это нужно? Примеры чтения данных из файла здесь ранее показывал DK.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 23, 2018, 05:40:54 pm
Не совсем понимаю твою задумку. Для чего это нужно? Примеры чтения данных из файла здесь ранее показывал DK.
Здравствуйте, уважаемый kenking, задумка состоит в следующем: при нажатии определённой клавиши, записываются файлы-координаты по трём осям y, x, z. Нужно организовать так, чтобы записывались пока игрок не нажал другую кнопку. Тут без цикла while никак не обойтись. Потом из этого файла эти координаты могли считаться. Скажите, пожалуйста, как реализовать построение условной конструкции в sdk? Например, нажимаешь одну кнопку, выполняется одно, нажимаешь другую-другое. У меня это приводит к зависанию и вылету игры после вывода координат.

Код: C++
  1. #include "plugin.h"
  2. #include "common.h"
  3. #include "CWorld.h"
  4. #include "extensions\KeyCheck.h"
  5. #include "CMessages.h"
  6. #include "CAutomobile.h"
  7. #include "CModelInfo.h"
  8. #include<string>
  9. #include<fstream>
  10. #include<queue>
  11. #include<map>
  12. using namespace plugin;
  13.  
  14. using namespace std;
  15. static bool readf = false;
  16.  
  17. queue<double>q = {};// очередь для хранение всех значение координат из файла.
  18. map<string, double> pos;// ассоциативный массив
  19.  
  20. bool isPedInVehicle(CPed * player) { return player->m_bInVehicle && player->m_pVehicle != NULL; }
  21.  
  22. void write(CPed *player, string path) {
  23.         CVehicle *v = player->m_pVehicle;// получить указатель на хенлд авто
  24.         fstream f; static char cord[256];
  25.         f.open(path, fstream::in | fstream::app | fstream::out);
  26.         if (f.is_open()) {
  27.                 char x[256];
  28.                 snprintf(x, 256, "%.2f %.2f %.2f \n", v->GetPosition().x, v->GetPosition().y, v->GetPosition().z);
  29.                 if (x != cord) {
  30.                         char cord = x[256];// сравнить с предыдущей значение
  31.                         f << x;
  32.                 }// записать координаты в файл.
  33.         }f.close();
  34. };
  35. template <class t1, class t2>// это метод как шабло. функция.
  36. void getcord(t1 *q, t2 *pos, string path) {     fstream f1;
  37. f1.open(path, fstream::in | fstream::app | fstream::out);
  38.         int a; // принимает очередь и ассо массив.
  39.         if (f1.is_open()) {
  40.                 if (readf == false) {
  41.                         while (f1 >> a) {
  42.                                 q->push(a); // считываем файл в очередь
  43.                                 readf = true;
  44.                         }//заполнена очередь, уст флаг.
  45.                 }
  46.                 if (q->empty()) { readf = false; }// если очередь пуста, уст флаг
  47.  
  48.                 else {
  49.                         pos->clear();// очистить ассо массив
  50.                         pos->emplace("x", q->front());  q->pop();// добавить значение по ключу
  51.                         pos->emplace("y", q->front());  q->pop();// и удаляет из очереди.
  52.                         pos->emplace("z", q->front());  q->pop();
  53.                 }
  54.         }
  55.  f1.close();  // закрывает файл.
  56. };
  57. class PlayerCoors {
  58. public:
  59.         PlayerCoors() {
  60.                 Events::gameProcessEvent += [] {//обработчик событий игры
  61.                         KeyCheck::Update();
  62.                         if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  63.                                 CPed *player = FindPlayerPed();// найти игрока
  64.                                 if (!player && !isPedInVehicle(player)) return; {// проверка найден игрок
  65.                                         CMessages::AddMessageJumpQ("this is gta vc", 5000, 3);//выводит сообщение на экран
  66.                                         write(player, "cord.txt");  // записать координаты в файл.
  67.                 }       }
  68.                     if (KeyCheck::CheckWithDelay('B', 200)) {//если м нажата
  69.                                 CPed *player = FindPlayerPed();// найти игрока
  70.                                 if (!player) return;
  71.                                                 getcord(&q, &pos, "cord.txt");// получить координаты из файла.
  72.                                                 static char s[256];
  73.                                                 snprintf(s, 256, "x = %.2f;y = %.2f;z = %.2f;", pos["x"], pos["y"], pos["z"]);
  74.                                                 CMessages::AddMessageJumpQ(s, 5000, 3);
  75.                         }
  76.                 };
  77.         }
  78. } playerCoors;
  79.  
  80.  

так все стало работать, как надо.

Код: C++
  1.  
  2. #include "plugin.h"
  3. #include "common.h"
  4. #include "extensions\KeyCheck.h"
  5. #include "CMessages.h"
  6. #include "CTimer.h"
  7. #include<thread> // std::thread
  8. #include<chrono> // std::thread
  9. #include<string>
  10. #include<fstream>
  11. #include<queue>
  12. #include<map>
  13. using namespace plugin;
  14.  
  15. using namespace std;
  16.  
  17. queue<double>q = {};// очередь для хранение всех значение координат из файла.
  18. map<string, double> pos;// ассоциативный массив
  19. bool readf = false;// начальное положение флага для чтение из файла.
  20. bool off = false;// выключения записи флага
  21. bool isPedInVehicle(CPed * player) { return player->m_bInVehicle && player->m_pVehicle != NULL; }
  22.  
  23. void write(CPed *player, string path, bool &off) {
  24.         CVehicle *v = player->m_pVehicle;// получить указатель на хенлд авто
  25.         fstream f; static char cord[256]; static unsigned int time = 0;// обнулить таймер
  26.         f.open(path, fstream::in | fstream::app | fstream::out);
  27.         if (f.is_open()) {while(true){if (CTimer::m_snTimeInMilliseconds - time > 5000) {
  28.                 this_thread::sleep_for(chrono::milliseconds(600));// задержка
  29.                 time = 0;// обнулить таймер
  30.                 static string cord = ""; // строка для сравнение
  31.                 char x[256]; snprintf(x, 256, "%.2f %.2f %.2f \n", v->GetPosition().x, v->GetPosition().y, v->GetPosition().z);
  32.                  string cordnenxt = string(x); // массив char в string
  33.                 if (cordnenxt != cord) {cord = cordnenxt;// сравнить с предыдущей значение
  34.                         f << cordnenxt; }// записать координаты в файл.
  35.                         if (off == true) {      break;  }}}// если кнопка в нажата, выкл запись координат.
  36.                 }// записать координаты в файл.
  37.         f.close();      off = false;// выключения записи флага
  38.         return;
  39. };
  40. template <class t1, class t2>// это метод как шабло. функция.
  41. void getcord(t1 *q, t2 *pos, string path, bool &readf, bool &oof) {
  42.         fstream f1;
  43.         f1.open(path, fstream::in | fstream::app | fstream::out);
  44.         static unsigned int time = 0;// обнулить таймер.
  45.         double a; // принимает очередь и ассо массив.
  46.         off = true; //выкл запись координат.
  47.         if (f1.is_open()) {     if (readf == false) {// если false нужно прочитать файл.
  48.                 while (f1 >> a) {       if (CTimer::m_snTimeInMilliseconds - time > 500){
  49.                                 q->push(a); // считываем файл в очередь
  50.                                 readf = true; } }}//заполнена очередь, уст флаг.
  51.         if (q->empty()) { readf = false; }// если очередь пуста, уст флаг
  52.  
  53.                 else {pos->clear();// очистить ассо массив
  54.                         pos->emplace("x", q->front());  q->pop();// добавить значение по ключу
  55.                         pos->emplace("y", q->front());  q->pop();// и удалить из очереди.
  56.                         pos->emplace("z", q->front());  q->pop();}
  57.         }
  58.         f1.close();  // деструктор, закрывает файл.
  59. };
  60. class PlayerCoors {
  61. public:
  62.         PlayerCoors() { Events::gameProcessEvent += [] {//обработчик событий игры 
  63.                 KeyCheck::Update();
  64.                 CPed *player = FindPlayerPed();// найти игрока
  65.                 if (!player) return; {if (KeyCheck::CheckWithDelay('M', 200) && isPedInVehicle(player)) {// проверка найден игрок и за рулем.
  66.                         CMessages::AddMessageJumpQ("this is gta vc", 5000, 3);//выводит сообщение на экран
  67.                         thread th(write, player, "cord.txt", std::ref(off));th.detach();}// независим поток. записать координаты в файл.
  68.             // передаем в новом поток.
  69.                 if (KeyCheck::CheckWithDelay('B', 200) && !isPedInVehicle(player)) { //если м нажата
  70.              getcord(&q, &pos, "cord.txt", readf, off);// получить координаты из файла.                                                       
  71.                      char s[256];
  72.                           snprintf(s, 256, "x = %.2f;y = %.2f;z = %.2f;", pos["x"], pos["y"], pos["z"]);
  73.                           CMessages::AddMessageJumpQ(s, 5000, 3);//выводит сообщение на экран
  74.                         } }
  75.                 };
  76.         }
  77. } playerCoors;
  78.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 28, 2018, 07:10:33 pm

Поражаюсь насколько plugin sdk крутая вещь. Особенно в умелых руках. Потихоньку его осваиваю, возникли следующие вопросы: на что влияют данные функции?

            v->m_autopilot.m_fMaxTrafficSpeed = 300.0;
            v->m_fTotSpeed = 140.0;
            v->m_fGasPedal = 40.0;
            v->m_vecMoveSpeed.Set(-92.69, -997.78, 10.28);
            v->m_fVelocityFrequency = 100.0;// что это отвечает?

Все равно машина не едет без этих команд.
            Command<COMMAND_CAR_GOTO_COORDINATES>(CPools::GetVehicleRef(v), -92.69, -997.78, 10.28);
            Command<COMMAND_SET_CAR_CRUISE_SPEED>(CPools::GetVehicleRef(v), 30.0);   

Без команды Command<COMMAND_SET_CAR_CRUISE_SPEED>(CPools::GetVehicleRef(v), 30.0); вообще стоит на месте. 
Чем заменить скриптовую команду?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 29, 2018, 09:23:32 am
Цитировать
Чем заменить скриптовую команду?
Надо смотреть в базе, как устроен соответствующий опкод. Если я правильно разобрал опкод 00AD: set_car 36@ max_speed_to 30.0 то получается так:
Код: C++
  1. vehicle->m_autoPilot.m_nCruiseSpeed = 30.0f;
  2. float maxSpeed = 60.0f * vehicle->m_pHandling->m_transmissionData.m_fMaxSpeed;
  3. if ( vehicle->m_autoPilot.m_nCruiseSpeed >= maxSpeed )
  4.     maxSpeed = vehicle->m_autoPilot.m_nCruiseSpeed;
  5. vehicle->m_autoPilot.m_nCruiseSpeed = maxSpeed;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 29, 2018, 10:46:20 am
Спасибо большое kenking Но для GTA Vice City  такого метода нет. Он есть для GTA San Andreas.
 А что обозначает m_pHandling->m_transmissionData.m_fEngineInertia?
 Скажите пожалуйста как создать маркер на машины и удалить его?  Интересно  что ждет  в новом обновлении sdk plugin?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 29, 2018, 04:25:41 pm
Я ошибся. Там не m_fEngineInertia, а m_fMaxSpeed. Надо будет в sdk исправить для gta3 и для VC заодно разобрать.
Цитировать
Скажите пожалуйста как создать маркер на машины и удалить его?
Ты же в клео разбираешься? Смотри как устроены соответствующие опкоды в базе. Затем смотри в sdk добавлены ли нужные классы.
 
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 30, 2018, 11:57:27 am
kenking для  Vice City у m_autoPilot  Нет метода m_nCruiseSpeed   Вот даже видео записал https://www.youtube.com/watch?v=qglTA3su3Tg&feature=youtu.be (https://www.youtube.com/watch?v=qglTA3su3Tg&feature=youtu.be)  Может надо что-то подключить?  Поймите меня правильно я хочу разобраться, чтобы потом помогать разбираться  другим.  Может  этот метод ещё не добавлен.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Декабрь 30, 2018, 06:09:13 pm
Проект обнови, в CAutoPilot я добавил m_nCruiseSpeed. По маркерам - надо разбирать класс CRadar.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Декабрь 30, 2018, 06:12:35 pm
спасибо большое уважаемый kenking очень  ждал вашего ответа, спасибо огромное за подсказку. Добавьте еще, пожалуйста, v->m_pHandling->m_transmissionData.m_fMaxSpeed для vice city его нет. CRadar тоже нет для vc.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Январь 03, 2019, 04:46:25 pm
 Скажите пожалуйста, как проверить находится ли  авто в заданных координатах c радиусом?
Как пользоваться скриптами командой
    COMMAND_GET_CAR_COORDINATES = 0xAA,
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Январь 04, 2019, 01:17:28 pm
Цитировать
Добавьте еще, пожалуйста, v->m_pHandling->m_transmissionData.m_fMaxSpeed для vice city его нет.
Было добавлено в том же коммите.

Цитировать
CRadar тоже нет для vc.
надо разбирать класс CRadar.

Цитировать
Скажите пожалуйста, как проверить находится ли  авто в заданных координатах c радиусом?
В предыдущих постах уже писали.

Цитировать
Как пользоваться скриптами командой
    COMMAND_GET_CAR_COORDINATES = 0xAA,
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\KeyCheck.h"
  3. #include "extensions\ScriptCommands.h"
  4. #include "eScriptCommands.h"
  5. #include "CMessages.h"
  6.  
  7. using namespace plugin;
  8.  
  9. class Test {
  10. public:
  11.     Test() {
  12.         Events::gameProcessEvent += [] {
  13.             CVehicle *vehicle = FindPlayerVehicle();
  14.             KeyCheck::Update();
  15.             if (vehicle && KeyCheck::CheckWithDelay('M', 200)) {
  16.                 CVector pos = { 0.0f, 0.0f, 0.0f };
  17.                 Command<COMMAND_GET_CAR_COORDINATES>(CPools::GetVehicleRef(vehicle), &pos.x, &pos.y, &pos.z);
  18.                 static char message[256];
  19.                 snprintf(message, 256, "x = %.2f; y = %.2f; z = %.2f; ", pos.x, pos.y, pos.z);
  20.                 CMessages::AddMessageJumpQ(message, 3000, false);
  21.             }
  22.         };
  23.     }
  24. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Январь 05, 2019, 02:25:34 am
Спасибо большой за ответ kenking  и разъяснение.
  Всё-таки  я не оставлял попыток,  сделать булевую функцию пытался через консоль,она работает правильно,мы передаем 3  координаты первый точки, потом 3  координаты другой точки, радиус в 3 координатах, она возвращает true или false.
Код: C++
  1. bool in_point_in_car_in_radius(double x, double y, double z, double x1,
  2.         double y1, double z1, double rx=0, double ry=0, double rz=0){
  3.         rx = abs(rx); ry = abs(ry);     rz = abs(rz);
  4.         if (rx == 0 || ry == 0)
  5.         {
  6.                 if (x == x1 && y == y1) {
  7.                         return true;
  8.                 }
  9.                 else {double r2 = rx * rx + ry * ry + rz * rz;
  10.                         x -= x1;
  11.                         y -= y1;
  12.                         z -= z1;
  13.                         if (x * x + y * y + z * z <= r2)
  14.                                 return true;
  15.                         else
  16.                                 return false;
  17.                 }
  18.         }
  19. };
  20. int main(int args, char* argv[]) {
  21.         if (in_point_in_car_in_radius(2, 1, 0,    0, 0, 0,     2, 1, 0)) {
  22.                 cout << "yes " << endl;
  23.         }
  24.         else {cout <<"no " << endl;  
  25.         };
  26.  
  27. return 0;
  28. system("pause");
  29. }
  30.  
  31.  

Потом перенес в плагин.  Записал  одну точку в текстовой файл, Нажал кнопку "в" создалась  машина   И поехала  В эту точку, потом встала как вкопанная.  Конечно надо улучшать, хотел  вывести сообщения. Пока не получилось   вот видео
https://www.youtube.com/watch?v=1EDkZUxfjZU&feature=youtu.be (https://www.youtube.com/watch?v=1EDkZUxfjZU&feature=youtu.be)
код с комментариями
Код: C++
  1. #include "plugin.h"
  2. #include "common.h"
  3. #include "CStreaming.h"
  4. #include "eWeaponModel.h"
  5. #include "CModelInfo.h"
  6. #include "CWorld.h"
  7. #include "eVehicleModel.h"
  8. #include "CCarCtrl.h"
  9. #include "CVehicle.h"
  10. #include "CBoat.h"
  11. #include "CAutomobile.h"
  12. #include "CBike.h"
  13. #include "extensions\KeyCheck.h"
  14. #include "CMessages.h"
  15. #include "CTimer.h"
  16. #include "extensions\ScriptCommands.h"
  17. #include "eScriptCommands.h"
  18. #include<thread> // std::thread
  19. #include<chrono> // std::thread
  20. #include<string>
  21. #include<fstream>
  22. #include<queue>
  23. using namespace plugin;
  24.  
  25. using namespace std;
  26. struct pos { double x; double y; double z; };//структура для координат.
  27. queue<double>q = {};// очередь для хранение всех значение координат из файла.
  28. bool readf = false;// начальное положение флага для чтение из файла.
  29. bool off = false;// выключения записи флага
  30. bool isPedInVehicle(CPed * player) { return player->m_bInVehicle && player->m_pVehicle != NULL; }
  31. CVehicle * createcar(int modelID, float distance = 10.f) {// создать авто
  32.         char reference = 2;
  33.         CPed *player = FindPlayerPed();
  34.         CVector position = player->m_placement.pos;
  35.         position += player->m_placement.up * distance; // Вектор оси прямо от игрока умножаем на 10 метров и прибавляем к позиции.
  36.         CStreaming::RequestModel(modelID, 0); // ANGEL 166 ModelID
  37.         CStreaming::LoadAllRequestedModels(false);
  38.         CVehicle * v;
  39.         if (CModelInfo::IsCarModel(modelID))// если создаем авто.
  40.                 v = new CAutomobile(modelID, reference);
  41.         if (CModelInfo::IsBikeModel(modelID))
  42.                 v = new CBike(modelID, reference);
  43.         if (CModelInfo::IsBoatModel(modelID))
  44.                 v = new CBoat(modelID, reference);
  45.         CCarCtrl::JoinCarWithRoadSystem(v);// ии машина в системе.
  46.         v->m_nState = 4;
  47.         v->CVehicle::m_nCreatedBy = reference; // Если один то транспорт будет удален позже...
  48.         v->m_placement.SetRotate(0, 0, 3.5f);
  49.         v->m_placement.pos.x = position.x;
  50.         v->m_placement.pos.y = position.y;
  51.         v->m_placement.pos.z = position.z + v->GetDistanceFromCentreOfMassToBaseOfModel();
  52.         CWorld::Add(v);
  53.         return v;
  54. }
  55.  
  56. void write(CPed *player, string path, bool &off) {
  57.         CVehicle *v = player->m_pVehicle;// получить указатель на хенлд авто
  58.         fstream f; static char cord[256];
  59.         f.open(path, fstream::in | fstream::app | fstream::out);
  60.         if (f.is_open()) {
  61.           while (true) {this_thread::sleep_for(chrono::milliseconds(600));// задержка
  62.                         static string cord = ""; // строка для сравнение
  63.                         char x[256]; snprintf(x, 256, "%.2f %.2f %.2f \n", v->GetPosition().x, v->GetPosition().y, v->GetPosition().z);
  64.                         string cordnenxt = string(x); // массив char в string
  65.                         if (cordnenxt != cord) {        cord = cordnenxt;// сравнить с предыдущей значение
  66.                                         f << cordnenxt; }// записать координаты в файл.
  67.                         if (KeyPressed('N')) {
  68.                                 CMessages::AddMessageJumpQ("Stop rec ", 5000, 3);//выводит сообщение на экран
  69.                                 break;  }
  70.                         }// если кнопка в нажата, выкл запись координат.
  71.         }// записать координаты в файл.
  72.         f.close();      off = false;// выключения записи флага
  73.         return;
  74. };
  75. void getcord(queue<double>&q, pos &cord, string path, bool &readf, bool &oof) {
  76.         off = true; //выкл запись координат.
  77.         static unsigned int time = 0;// обнулить таймер.
  78.         if (CTimer::m_snTimeInMilliseconds - time > 500) {
  79.                 time = 0; // обнулить таймер
  80.                 fstream f1;
  81.                 f1.open(path, fstream::in | fstream::app | fstream::out);
  82.                 double a; // принимает очередь и ассо массив.
  83.                 if (f1.is_open()) {
  84.                         if (readf == false) {// если false нужно прочитать файл.
  85.                                 while (f1 >> a) {
  86.                                         q.push(a); // считываем файл в очередь
  87.                                         readf = true;
  88.                                 }
  89.                         }
  90.                 }//заполнена очередь, уст флаг.
  91.                 if (q.empty()) { readf = false; }// если очередь пуста, уст флаг
  92.                 else {cord.x = q.front(); q.pop();
  93.                         cord.y = q.front(); q.pop();
  94.                         cord.z = q.front(); q.pop();
  95.                 }// добавить в структуру и удалить из очереди.
  96.                 f1.close();  // деструктор, закрывает файл.
  97.         }
  98. };
  99. bool in_point_in_car_in_radius(CVehicle *v, double x1,double y1, double z1,
  100.         double rx = 0, double ry = 0, double rz = 0) {
  101.     double      x = v->GetPosition().x;
  102.     double      y = v->GetPosition().y;
  103.     double      z = v->GetPosition().z;
  104.         rx = abs(rx); ry = abs(ry);     rz = abs(rz);
  105.         if (rx == 0 || ry == 0)
  106.         {if (x == x1 && y == y1) {
  107.                         return true;    }
  108.         else {  double r2 = rx * rx + ry * ry + rz * rz;
  109.                         x -= x1;
  110.                         y -= y1;
  111.                         z -= z1;
  112.         if (x * x + y * y + z * z <= r2)
  113.                 return true;
  114.         else
  115.                 return false;
  116.                 }
  117.         }
  118. };
  119.  
  120. void drive(CVehicle *v, queue<double>&q, pos &pos, string path, bool &readf, bool &oof) {
  121.         v->m_autopilot.m_fMaxTrafficSpeed = 60.0;
  122.         v->m_fTotSpeed = 30.0;
  123.         v->m_autopilot.m_nDrivingStyle = 2;
  124.         static double x, y, z;// эти переменные нужны для сравнение
  125.          getcord(q, pos, path, readf, off);// получить координаты из очереди.
  126.          Command<COMMAND_CAR_GOTO_COORDINATES>(v, pos.x, pos.y, pos.z);
  127.          CMessages::AddMessageJumpQ("my sas", 5000, 3);//выводит сообщение на экран
  128.         while (true) {  this_thread::sleep_for(chrono::milliseconds(600));// задержка
  129.         double x1 = pos.x; double y1 = pos.y; double z1 = pos.z;// записаем координаты в переменные.
  130.         if (!in_point_in_car_in_radius(v, x1, y1, z1, 4.0, 4.0, 0))     return; {// ждем пока машина не будет в радиусе.
  131.                  x = x1; y = y; z = z1;// записываем координаты в стастик переменные.
  132.                  getcord(q, pos, path, readf, off);// получаем новые координаты из очереди.
  133.                  Command<COMMAND_CAR_GOTO_COORDINATES>(v, pos.x, pos.y, pos.z); }
  134.          if (x == x1 && y == y1 && z == z1) {// стастик переменне равны новым из очереди, значить преврать цикл.
  135.                  char s[256];
  136.                  snprintf(s, 256, "x = %.2f;y = %.2f;z = %.2f;", pos.x, pos.y, pos.z);
  137.                 CMessages::AddMessageJumpQ(s, 5000, 3);//выводит сообщение на экран
  138.                  break;}       
  139.          else { continue; }
  140.          }
  141.         v->m_wBombTimer=100;//взорвать авто
  142.         return;
  143. };
  144. class PlayerCoors {public:
  145.         PlayerCoors() { Events::gameProcessEvent += [] {//обработчик событий игры 
  146.                         KeyCheck::Update();
  147.                         pos pos;
  148.                         CPed *player = FindPlayerPed();// найти игрока
  149.                         if (!player) return; {if (KeyCheck::CheckWithDelay('M', 200) && isPedInVehicle(player)) {// проверка найден игрок и за рулем.
  150.                                 CMessages::AddMessageJumpQ("this is gta vc", 5000, 3);//выводит сообщение на экран
  151.                                 thread th(write, player, "cord.txt", std::ref(off)); th.detach();}// независим поток. записать координаты в файл. передаем в новом поток.
  152.                         if (KeyCheck::CheckWithDelay('B', 600) && !isPedInVehicle(player)) { //если м нажата
  153.                                 CVehicle *v = createcar(MODEL_AMBULAN); // Спавним скорую
  154.                                 thread th1(drive, v, q, pos, "cord.txt", std::ref(readf), std::ref(off)); th1.detach();
  155.                             }// независим поток. записать координаты в файл. передаем в новом поток.
  156.                      }
  157.                 };
  158.         }
  159. } playerCoors;
  160.  
  161.  
  162.  
  163.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Январь 26, 2019, 06:49:30 pm
У меня  к вам такой вопрос,  как сделать  функцию, которая  проверяет нажата ли клавиша? возвращает true, только когда  эта клавиша  отпущена?  Пока приходится пользоваться такой конструкцией.
Код: C++
  1.        
  2. bool wait(const char k []) {
  3.         unsigned int key = (unsigned int)k;
  4.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  5.         else { return false; }
  6. }      
  7. KeyCheck::Update();
  8. if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  9. if (wait("M")) return; {//если м нажата
  10.  
Хочется чтобы  чтобы была функция, которая выполняет действия После нажатия и опусканием, а не только при нажатии и задержки.
 Хочу прикрутить lua к sdk, как лучше это сделать?
  Пока Вот так получилось.
Код: C++
  1. #include "common.h"
  2. #include "plugin.h"
  3. #include "CWorld.h"
  4. #include "extensions\KeyCheck.h"
  5. #include "CMessages.h"
  6. #include"include/lua.hpp"
  7. using namespace plugin;
  8. using namespace std;
  9. bool wait(const char k []) {
  10.         unsigned int key = (unsigned int)k;
  11.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  12.         else { return false; }
  13. }
  14. class Message {//имя класса
  15. public: Message() {     Events::gameProcessEvent += [] {//обработчик событий игры
  16.                 CPed *player = FindPlayerPed();// найти игрока
  17.                 if (!player) return;// проверка найден игрок
  18.                 KeyCheck::Update();
  19.                 if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  20.                 if (wait("M")) return; {//если м нажата
  21.                         lua_State *L = luaL_newstate();
  22.                         luaL_dofile(L, "lualoader\\main.lua");// Загружает и запускает заданный файл. файл в которым все происходит.
  23.                         lua_getglobal(L, "money");// получить значение глобальной переменной x.
  24.                         int money = lua_tonumber(L, 1);
  25.                         lua_close(L);// закрыть состояние
  26.                 CWorld::Players[CWorld::PlayerInFocus].m_nMoney += money;// дать денег
  27.                 }
  28.                 }};
  29. }
  30. } message;
  31.  
  32.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Январь 27, 2019, 08:21:49 am
Цитировать
как сделать  функцию, которая  проверяет нажата ли клавиша? возвращает true, только когда  эта клавиша  отпущена?
class KeyCheck http://forum.gtabuilder.ru/index.php?topic=337.msg2356#msg2356 (http://forum.gtabuilder.ru/index.php?topic=337.msg2356#msg2356)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 04, 2019, 10:14:18 am
спасибо за Ваш ответ kenking.
все-таки хочу встроить lua plugin. с api lua получалось, оно слишком сложно в реализации.

остановил свой выбор на luabridge, изучил основы.

Не получается прикрутить lua к sdk plugin vice.

При добавлении  новых функций, возникает ошибка  C3861   getGlobalNamespace: идентификатор не найден   plugin   d:\games\gta vice city\plugin\plugin.cpp

Скажите пожалуйста как эту проблему решить?

Код: C++
  1.  
  2. #include "include/lua.hpp"
  3. #include"LuaBridge/LuaBridge.h"
  4. #include "common.h"
  5. #include "plugin.h"
  6. #include "CWorld.h"
  7. #include "extensions\KeyCheck.h"
  8. #include "CMessages.h"
  9. using namespace plugin;
  10. using namespace std;
  11. bool wait(const char k []) {
  12.         unsigned int key = (unsigned int)k;
  13.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  14.         else { return false; }
  15. }
  16. void foo() {
  17.         CMessages::AddMessageJumpQ("ok lua", 1000, 0);//выводит сообщение на экран
  18.  
  19. }
  20.  
  21. class Message {//имя класса
  22. public: Message() {     Events::gameProcessEvent += [] {//обработчик событий игры
  23.                 CPed *player = FindPlayerPed();// найти игрока
  24.                 if (!player) return;// проверка найден игрок
  25.                 KeyCheck::Update();
  26.                 if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  27.                 if (wait("M")) return; {//если м нажата
  28.                 lua_State* L = luaL_newstate();
  29.                 luaL_openlibs(L);
  30.                 .getGlobalNamespace(L)//Пространства имен LuaBridge для регистрации функции и классов, видны только сценариям Lua.
  31.                 .addFunction("foo", foo)// название функции в lua и c++.
  32.                 .endNamespace();
  33.                         luaL_dofile(L, "lualoader\\main.lua");// Загружает и запускает заданный файл. файл в которым все происходит.
  34.  
  35.                         lua_close(L);// закрыть состояние
  36.                 }
  37.                 }};
  38. }
  39. } message;
  40.  


все прикрутил две функции к lua.

Код: C++
  1. #include "include/lua.hpp"
  2. #include"LuaBridge/LuaBridge.h"
  3. #include "common.h"
  4. #include "plugin.h"
  5. #include "CWorld.h"
  6. #include "extensions\KeyCheck.h"
  7. #include "CMessages.h"
  8. using namespace plugin;
  9. using namespace std;
  10. using namespace luabridge;
  11. bool wait(const char k[]) {
  12.         unsigned int key = (unsigned int)k;
  13.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  14.         else { return false; }
  15. }
  16. CPed *findplayer(lua_State* L)  {
  17.         CPed *player = FindPlayerPed();// получить указатель на игрока.
  18.         CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 500;// дать денег
  19.         return player;// вернуть указатель на игрока.
  20. };
  21.  
  22. void sethealth(CPed *player, int health, lua_State* L) {
  23.         CPed *b = (CPed*)Userdata::get<CPed>(L, 1, false);
  24.         b->m_fHealth =  health;// уст здоровье игрока.
  25. };
  26. class Message {//имя класса
  27. public: Message() {     Events::gameProcessEvent += [] {//обработчик событий игры
  28.         CPed *player = FindPlayerPed();// найти игрока
  29.         if (!player) return;// проверка найден игрок
  30.         KeyCheck::Update();
  31.         if (KeyCheck::CheckWithDelay('M', 200)) {//если м нажата
  32.         if (!wait("M")) return; {//если м отпущена.
  33.                 lua_State* L = luaL_newstate();
  34.                 luaL_openlibs(L);
  35.                 getGlobalNamespace(L)//Пространства имен LuaBridge для регистрации функции и классов, видны только сценариям Lua.
  36.                 .beginClass<CPed>("cped")// имя класса в lua.
  37.                 .endClass()// закрыть регистрацию класса.
  38.                 .addFunction("findplayer", &findplayer)// возвращает указатель игрока.
  39.                 .addFunction("sethealth", &sethealth);// название функции в lua и c++.// название функции в lua и c++.
  40.                 luaL_dofile(L, "lualoader\\main.lua");// Загружает и запускает заданный файл. файл в которым все происходит.
  41.                 lua_close(L);// закрыть состояние
  42. }}};}
  43. } message;
  44.  
  45.  

Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 07, 2019, 04:27:37 am
здравствуйте всем. сейчас пытаюсь реализовать lua встроить в sdk plugin. Скажите, пожалуйста, как реализовать функцию wait, чтобы бесконечный цикл на lua не вылетал? как можно лучше реализовать перезагрузку скрипта(открыть и закрыть lua состояния)?

Код: C++
  1. #include<fstream>
  2. #include "include/lua.hpp"
  3. #include"LuaBridge/LuaBridge.h"
  4. #include "common.h"
  5. #include "plugin.h"
  6. #include "CWorld.h"
  7. #include "extensions\KeyCheck.h"
  8. #include "CMessages.h"
  9.  
  10. using namespace plugin;
  11. using namespace std;
  12. using namespace luabridge;
  13.  
  14. void writelog(const char x[]) {
  15.         string path = "lualoader\\log.txt";
  16.         fstream f1; {f1.open(path, fstream::in | fstream::out | fstream::app);
  17.         f1 << x << "\n"; }
  18.         f1.close();
  19. };
  20.  
  21. bool wait(const char k[]) {
  22.         unsigned int key = (unsigned int)k;
  23.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  24.         else { return false; }
  25. }
  26. CPed *findplayer(lua_State* L)  {
  27.         CPed *player = FindPlayerPed();// получить указатель на игрока.
  28.         return player;// вернуть указатель на игрока.
  29. };
  30.  
  31. int gethealth(lua_State* L) {
  32.         try {
  33.                 if (LUA_TUSERDATA == lua_type(L, -1)) {// указатель на игрока.
  34.                         CPed *b = (CPed*)Userdata::get<CPed>(L, 1, false);// получить указатель на игрока.
  35.                         int health = b->m_fHealth; // получить кол-во здоровья игрока.
  36.                         lua_pushnumber(L, health);// отправить в стек.   
  37.                         return 1;
  38.                 }
  39.                 else { throw "bad argument in function gethealth option of the player"; }
  40.         }
  41.         catch (const char* x) {
  42.                 writelog(x);
  43.                 return 0;
  44.         }
  45.         return 0;
  46. };
  47.  
  48. int sethealth(lua_State* L) {
  49.         try {if ( LUA_TUSERDATA == lua_type(L, -2) ) {// указатель на игрока.
  50.                 double x = lua_tonumber(L, -1);// если число.
  51.                 int health = (int)x;
  52.                 if (x == health && LUA_TNUMBER == lua_type(L, -1)) {
  53.                         CPed *b = (CPed*)Userdata::get<CPed>(L, 1, false);// получить указатель на игрока.
  54.                         b->m_fHealth = health;}// уст здоровье игрока.
  55.                 else { throw "bad argument in function sethealth option health"; }
  56.                 }
  57.                 else { throw "bad argument in function sethealth option of the player"; }
  58.         }catch (const char* x) {
  59.                 writelog(x);    }
  60. return 0;};
  61.  
  62. void man(lua_State* L) {
  63.         luaL_openlibs(L);
  64.         getGlobalNamespace(L)//Пространства имен LuaBridge для регистрации функции и классов, видны только сценариям Lua.
  65.                 .beginClass<CPed>("cped")// имя класса в lua.
  66.                 .endClass()// закрыть регистрацию класса.
  67.                 .addFunction("findplayer", &findplayer)// возвращает указатель игрока.
  68.                 .addCFunction("gethealth", &gethealth)// название функции в lua и c++. уст здоровье.
  69.                 .addCFunction("sethealth", &sethealth);// название функции в lua и c++. получить здоровье.
  70.                 luaL_dofile(L, "lualoader\\main.lua"); // Загружает и запускает заданный файл. файл в которым все происходит.  
  71. };
  72. bool reload = false;
  73. class Message {//имя класса
  74. public: Message() {     Events::gameProcessEvent += [] {//обработчик событий игры
  75.         CPed *player = FindPlayerPed();// найти игрока
  76.         if (!player) return;// проверка найден игрок
  77.         lua_State* L = luaL_newstate();
  78.         if (reload == false){ reload = true;
  79.         man(L);}
  80.      if (KeyPressed(VK_CONTROL)&& reload == true) {// перезагрузка скрипта
  81.                 reload = false;
  82.                 lua_close(L); // закрыть состояние
  83.                 }
  84. };};
  85. }message;
  86.  

lua
Код: C++
  1. while true do
  2. wait() -- миллисекунды в скобках
  3. player= findplayer()-- получить игрока
  4. x = gethealth(player)-- получить здоровье игрока.
  5.  
  6.  if x<100 then
  7.  sethealth(player, 150) -- 150 хп.
  8.  end
  9. end
  10.  

может так реализовать wait 0??

Код: Text
  1.  
  2. int wait(lua_State* L) {
  3.  
  4.         Command<COMMAND_WAIT>(100);
  5.         return 0;
  6. };
  7.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Февраль 07, 2019, 11:28:06 am
как реализовать функцию wait
Нужно делать таймер и проверять каждый цикл, прошло ли нужное количество времени.
Притом в идеале нужно синхронизироваться не с реальным временем Windows, а с внутриигровым таймером:
Код: C++
  1. INT 0x974B2C(InGame Timer in ms)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 07, 2019, 06:37:03 pm
Здравствуйте, уважаемый Shagg_E, очень, очень рад Вашему ответу. Первый раз писал на форуме почти 2 года назад. Многому с того времени научился, и не перестаю узнавать интересное в программировании. Сейчас те вопросы, которые я Вам задавал вначале кажутся глупыми. Изучил основы с++, lua api, и продолжаю совершенствоваться. Мне ещё давно понравился sdk plugin, но я думал, что не смогу с ним справиться. Но после изучения с++, появилось некоторая уверенность. Сейчас я делаю на основе sdk plugin типа moonloader, только для vc, но единственную сложность представляет для меня использование скриптовых команд, поскольку мы не знаем в каком порядке, какие и сколько аргументов передавать, как их получать. С обычными функциями ещё можно разобраться, но с этими очень тяжело без совета знающего человека.
 
Все-таки очень хочу встроить код в lua, пока получилось реализовать 3 функции, конечно, можно добавить ещё функции. Но без wait 0 это теряет всякий смысл. Есть скриптовая команда, просто я не знаю как её использовать, она нужна, чтобы бесконечный цикл не вылетал. Уже удалось реализовать перезагрузку скрипта на лету. На это ушло много часов, но только терпение, упорство и огромное желание приводит нас к результату. Буду очень рад любой помощи.
Название: Re: Написание плагина. Настройка проекта
Отправлено: Shagg_E от Февраль 07, 2019, 08:19:58 pm
egor230> Твои успехи вдохновляют: за полтора года научился стольким вещам. Удачи в дальнейшем!
Насчет lua - спроси у Sektor, он же запилил Vice Lua, он по-любому сталкивался со всеми этими проблемами. А может, и вовсе имеет смысл не изобретать велосипед, а продолжить его разработку?..
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 08, 2019, 10:01:29 am
Спасибо большое за добрые слова поддержки и понимания, Shagge_E, я недоволен своим прогрессом, этот прогресс нужно было достичь за неделю, я всегда хотел сделать настоящий прорыв в области изучения нового, но на деле происходит долго, тяжело, часто не понятно. Но буду стараться, потому что другого выхода у нас просто нет. Много общался с Виталием, его интересуют совершенно другие вещи, мне нравится очень общаться с Вами, всегда получишь четкий, ясный, правильный ответ, который нужен в данный момент. Я Вам очень признателен за ту помощь в 17 году. Виталий из-за скорости выполнения предпочитает команды ассемблера, я считаю, что это шаг назад, весь мир повышает уровень программирования, делая его простым и лёгким, ну что более легко изучить? Что более понятно обычным людям? Во что, как говорит наша молодежь, в что можно быстрее въехать: в сложный, непонятный ассемблер, или лёгкий и простой питон?
 
Поэтому, я внедряю в sdk lua, ведь функции готовы, только писать большое объём кода на с++ очень тяжело. Большая вероятность ошибки. Да, признаюсь, тяжело постигать sdk, нет документации, но когда это меня останавливало? Только лишь тормозило меня. Но идти медленно это не значит стоять на месте, как многие думают. Очень хочется услышать реальный совет, который поможет в реализации моей идеи.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 17, 2019, 09:00:23 am
Получилось  реализовать работу с клавишами. Столкнулся с интересным поведением функции.
Код: Text
  1. int printmessage(lua_State* L) {
  2.         try {
  3.                 if (LUA_TSTRING == lua_type(L, -1)) {//money.
  4.                 string msg = lua_tostring(L, -1);
  5.                 char str[255];
  6.                 strcpy(str, msg.c_str());
  7.  
  8.                         static char x[255];
  9.                         snprintf(x, 255,"%s", str);
  10.                         CMessages::AddMessageJumpQ(x, 5000, 3);
  11.                         return 0;
  12.                 }
  13.                 else { throw "bad argument in function printmessage"; }
  14.         }
  15.         catch (const char* x) {
  16.                 writelog(x);
  17.         }
  18.         return 0;
  19. };
  20.  
  21.  

Иногда она некорректно выводит сообщения,   А когда вообще ничего мы не видим  никакого текст на экране.
Как вы думаете с чем связанное такое поведение? Может я как-то не так делаю?

Оказалось нужно строку перевести в wchar_t.

Код: C++
  1. int printmessage(lua_State* L) {// аргументы текст и и время вывода на экран.
  2.         try {
  3.                 if (LUA_TSTRING == lua_type(L, -2) && LUA_TNUMBER == lua_type(L, -1)) {//строка.
  4.                         string aString = lua_tostring(L, -2);
  5.                         double t = lua_tonumber(L, -1);// если число.
  6.                         int time = (int)t;
  7.                         const int maxSize = 1024; // 1Мб символов
  8.                         wchar_t *str = L"_";
  9.                         wchar_t buff[maxSize];
  10.                         int nSize = ::MultiByteToWideChar(CP_UTF8, 0, aString.c_str(), static_cast<int>(aString.length() + 1), NULL, NULL);
  11.                         wchar_t *tBuff = buff;
  12.                         ::MultiByteToWideChar(CP_UTF8, 0, aString.c_str(), static_cast<int>(aString.length() + 1), buff, nSize);
  13.                         str = tBuff;
  14.                         CMessages::AddMessageJumpQ(str, time, 3);
  15.                         this_thread::sleep_for(chrono::milliseconds(time));
  16.                         return 0;
  17.                 }
  18.                 else { throw "bad argument in function printmessage"; }
  19.         }
  20.         catch (const char* x) {
  21.                 writelog(x);// записать ошибку в файл.
  22.         }
  23.         return 0;
  24.  
  25.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 09, 2019, 04:56:01 pm
... в CCarCtrl::JoinCarWithRoadSystemGotoCoors ошибочный лишний третий параметр.
Оказывается там всё верно, сорри.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 10, 2019, 02:37:37 pm
Помогите,  пожалуйста,  нужно найти  не только всех педов, которые которые находятся в радиусе,  но и тех кто сидит за рулём.
 Может так находим авто, как проверить есть ли  в нём водителей? И получить указатель  на его?

Код: Text
  1.  
  2. void randomfindcar(CPed *p, float radius) {
  3.         CVehicle*  v = isPedInVehicle(p);// авто игрока.
  4.                 for (auto car : CPools::ms_pVehiclePool) {
  5.                         if (car != v && DistanceBetweenPoints(car->GetPosition(), p->GetPosition()) < radius && car->m_fHealth > 50)
  6.                           car->???????
  7.         }
  8.                 for (auto ped : CPools::ms_pPedPool) {
  9.                         if (ped != p && DistanceBetweenPoints(ped->GetPosition(), p->GetPosition()) < radius && ped->m_fHealth > 50)
  10.                                 ped->m_fHealth = 0;
  11.  
  12.                 }
  13. };
  14.  

вроде так, но водитель не выходит.
Код: Text
  1. CVehicle* isPedInVehicle(CPed * player) {
  2.         if (player->m_bInVehicle && player->m_pVehicle != NULL) {// в авто игрок?
  3.                 CVehicle *v = player->m_pVehicle;
  4.                 return v;}// получить указатель на хенлд авто в котором сидит томии.
  5.         else {
  6.                 CVehicle *v = NULL;
  7.                 return v;}//если томми не в авто вернуть null;
  8. }
  9. void randomfindcar(CPed *p, float radius) {
  10.         CVehicle*  v = isPedInVehicle(p);// авто игрока.             
  11.         for (auto car : CPools::ms_pVehiclePool) {
  12.                         if (car != v && DistanceBetweenPoints(car->GetPosition(), p->GetPosition()) < radius && car->m_fHealth > 50) {
  13.                
  14.                                 if (CPed*p =car->m_pDriver) {
  15.                                        
  16.                                         if (p != NULL) {
  17.                                                 p->ExitCar();
  18.                                         CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1;// дать денег
  19.                                         }
  20.                         }
  21.                 }
  22.         }
  23.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 12, 2019, 07:26:25 am
Код: C++
  1. #include "plugin.h"
  2. #include "CPed.h"
  3.  
  4. using namespace plugin;
  5.  
  6. class Test {
  7. public:
  8.     Test() {
  9.         Events::gameProcessEvent += [] {
  10.             CPed *player = FindPlayerPed();
  11.             if (player) {
  12.                 for (auto car : CPools::ms_pVehiclePool) {
  13.                     if (DistanceBetweenPoints(car->GetPosition(), player->GetPosition()) < 20.0f && car->m_nVehicleClass == VEHICLE_AUTOMOBILE && car->m_fHealth > 50.0f) {
  14.                         if (car->m_pDriver && car->m_pDriver != player)
  15.                             car->m_pDriver->SetExitCar(car, 15);
  16.                     }
  17.                 }
  18.             }
  19.         };
  20.     }
  21. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 12, 2019, 04:04:50 pm
спасибо Вам огромное kenking за ответ. у меня пед выходит из машины с помощью    p->SetObjective(OBJECTIVE_LEAVE_CAR). чем отличается SetExitCar(car, 15)? 15 отвечает за выход педа, а какие числа еще есть, за что они отвечают? Скажите, пожалуйста, очень интересно.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 12, 2019, 05:48:29 pm
15 - это компонент  CAR_DOOR_LF (водитель выходит через левую переднюю дверь)
16 - CAR_DOOR_LR
11 - CAR_DOOR_RF
12 - CAR_DOOR_RR

Смотри eCarNodes
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 12, 2019, 05:52:27 pm
спасибо большое
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 17, 2019, 01:17:21 pm
Пытаюсь разобраться с функциями в sdk plugin,  с классом CPed, помогите, понять за что отвечают эти функции?
Код: C++
  1.                                 //ped->AttachPedToEntity();//?
  2.                                 //ped->DriveVehicle();//?
  3.                                 //ped->Duck();//?
  4.                                 //ped->BuyIceCream();// ?
  5.                                 //ped->Add();//?
  6.                                 //ped->BuildPedLists();//?
  7.                                 //ped->LookForInterestingNodes();//?
  8.                                 //ped->Dress();//пед дергается?
  9.                                 //ped->LoadFightData();//?
  10.                                 //ped->Idle();//??
  11.                                 //ped->Avoid();// избегает пед.
  12.                                 //ped->Flee();//?
  13.                                 //ped->Attack();//?
  14.                                 //ped->Fall();//пед падает
  15.                                 //ePedAction атака = 17;
  16.  

В некоторых функция есть параметр CEntity, что это за класс? Он использует в этой функции
 CEntity* AttachPedToEntity(CEntity* entity, CVector offset, unsigned short position, float angle, eWeaponType weaponType);

Очень хочу научиться писать плагины для gta vc.   
Название: Re: Написание плагина. Настройка проекта
Отправлено: xanser от Март 18, 2019, 05:02:43 am
Класс CEntity - это основа для всех сущностей игры: зданий, объектов, машин, людей, оружия и др, имеющих общие свойства, например идентификатор, матрицу поворота, флаги коллизии и прочее. От этого класса происходят остальные классы CVehicle, CPed и т.д. Функция AttachPedToEntity означает крепление педа к сущности, обычно к транспорту, как в некоторых миссиях, где пед стреляет с машины. Но можно крепить и к другим объектам, к карусели какой-нибудь, поэтому и используется общий класс CEntity.
Параметры функции:
entity - машина или другой объект, к которой происходит крепление педа
offset - точка крепления
position - от 0 до 3 - это сторона, в которую смотрит пед
angle - угол, на который может вращаться пед при стрельбе
weaponType - тип оружия

С остальными функциями надо разбираться, обычно из названия понятно, что они делают, дальше внутри смотри и ищи ссылки, откуда они вызываются. Например Ped->Dress() может переодеть педа. Если описать ее так, то можно менять скин игроку:

Код: C++
  1. void CPed::Dress(char * name) {
  2.         ((void(__thiscall *)(CPed *, char *))0x4EF030)(this, name);
  3.         ((void(__cdecl *)(bool _))0x40B5F0)(0);
  4.         ((void(__thiscall *)(CPed *))0x4EEFD0)(this);
  5. }
  6.  
  7. PlayerPed->Dress("player2");

А вообще не стоит все смешивать в одну кучу, вот зачем тебе все эти функции сразу, если непонятно их назначение. Выбери что-то конкретное и копай в этом направлении. Научиться писать плагины - это что-то слишком размытое. Ну напишешь ты 30 плагинов про все подряд, и что это будет? Лучше развивать конкретное направление, смотреть чего именно не хватает и собирать по кирпичику. Вообще эта тема зафлудилась.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 18, 2019, 10:30:26 pm
Спасибо вам большое за ваш ответ  xanser. Выходит,Класс CEntity  является родительским классом, других классов, они от него  наследуются.

 Получается в некотором роде Функция AttachPedToEntity является аналогом 0464: put_actor 4@ into_turret_on_car 3@ at_car_offset 0.4242 -0.0679 1.1322 position 0 angle 360.0 with_weapon 30


 Хочется чтобы  всё было  максимально просто и понятно. значит  метод Ped->Dress(), мы можем переопределить сами.

согласен с вами,  лучше работать в одном направлении.  Есть  задача, чтобы ped нападал  на  игрока.
 Думал, сделать так, через функции не получилось.
Код: Text
  1. ped->Attack();
  2. ped->m_dwAction;
  3. ped->m_fAttachRot =17;
  4.  

пришлось, чтобы пед  атаковал игрока, использовать скриптовую команду.

Код: Text
  1. CPed *ped = randomfindped(player, 20.0);
  2. Command<COMMAND_SET_CHAR_OBJ_KILL_CHAR_ON_FOOT>(ped, player );
  3.  

Да, заработало, но не так хотел, нападают, при любом количестве нажатии на клавишу активации, максимум только 2.
как сделать это через функции, метода класса CPed?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 19, 2019, 07:46:41 am
Цитировать
Есть  задача, чтобы ped нападал  на  игрока.
Думал, сделать так, через функции не получилось.
пришлось, чтобы пед  атаковал игрока, использовать скриптовую команду.
Надо смотреть, как устроен соответствующий опкод в базе (я уже ранее писал про это). Опкоды:
01C9: actor $2324 kill_actor $2291
01CA: actor $853 kill_player $PLAYER_CHAR

в базе выглядят так:
Код: C++
  1. case SET_CHAR_OBJ_KILL_CHAR_ON_FOOT:
  2.       CRunningScript::CollectParameters(this, &this->m_nIp, 2);
  3.       CPed *ped_01C9 = CPool<CPed,CPlayerPed>::GetAt(CPools::ms_pPedPool, ScriptParams[0].m_nIntValue);
  4.       CPed *ped_01C9a = CPool<CPed,CPlayerPed>::GetAt(CPools::ms_pPedPool, ScriptParams[1].m_nIntValue);
  5.       ped_01C9->bfFlagsD &= 0x7F;
  6.       CPed::SetObjective(ped_01C9, OBJECTIVE_KILL_CHAR_ON_FOOT, ped_01C9a);
  7.       result = 0;
  8. break;
  9. case SET_CHAR_OBJ_KILL_PLAYER_ON_FOOT:
  10.       CRunningScript::CollectParameters(this, &this->m_nIp, 2);
  11.       CPed *ped_01CA = CPool<CPed,CPlayerPed>::GetAt(CPools::ms_pPedPool, ScriptParams[0].m_nIntValue);
  12.       id_01CA = ScriptParams[1].m_nIntValue;
  13.       ped_01CA->bfFlagsD &= 0x7F;
  14.       CPed::SetObjective(ped_01CA, OBJECTIVE_KILL_CHAR_ON_FOOT, CWorld::Players[id_01CA].m_pPed);
  15.       result = 0;
  16. break;

Значит в первом случае надо сделать так:
Код: C++
  1. pedOne->bfFlagsD &= 0x7F;
  2. CPed::SetObjective(pedOne, OBJECTIVE_KILL_CHAR_ON_FOOT, pedTwo);

Во втором случае с игроком так:
Код: C++
  1. ped->bfFlagsD &= 0x7F;
  2. CPed::SetObjective(ped, OBJECTIVE_KILL_CHAR_ON_FOOT, CWorld::Players[CWorld::PlayerInFocus].m_pPed);

Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 20, 2019, 12:17:06 am
Спасибо вам большое за вас ответ, kenking. сделал в цикле- находит людей, они начинают атаковать меня. Всё хорошо, но есть 2 но, враги  они становится медленнее находится чем на cleo, через пару минут  игра вылетает, Как решить данную проблему?

Код: Text
  1.  
  2. CPed* randomfindped(CPed *p, float radius) {CVehicle* v = NULL;
  3.  
  4.         if (p->m_bInVehicle && p->m_pVehicle != NULL) {// в авто игрок?
  5.                 CVehicle *v = p->m_pVehicle;    }// получить указатель на хенлд авто в котором сидит томии.
  6.         for (auto car : CPools::ms_pVehiclePool) {
  7.                 if (car != v && DistanceBetweenPoints(car->GetPosition(), p->GetPosition()) < radius && car->m_fHealth > 50) {
  8.                 car->CanPedExitCar(true);
  9.                 if (CPed*ped = car->m_pDriver) {if (ped != NULL && ped != p) {
  10.                         CMessages::AddMessageJumpQ("found ped", 1000, 0);//выводит сообщение на экран
  11.                                 return ped;     }}}}
  12.         for (auto ped : CPools::ms_pPedPool) {
  13.                 if (ped != p && DistanceBetweenPoints(ped->GetPosition(), p->GetPosition()) < radius && ped->m_fHealth > 50) {
  14.                         CMessages::AddMessageJumpQ("found ped", 1000, 0);//выводит сообщение на экран
  15.                         return ped;     }}
  16.        
  17.                  CMessages::AddMessageJumpQ("not found ped", 1000, 0);  
  18. };
  19. bool flag = false;
  20. class Message {//имя класса
  21. public:
  22.         Message() {
  23.                 Events::gameProcessEvent += [] {//обработчик событий игры
  24.                                 CPed *player = FindPlayerPed();// найти игрока
  25.                         KeyCheck::Update();
  26.                         if (KeyCheck::CheckWithDelay('M', 200)|| flag==true) {//если м нажата
  27.                                 flag=true;
  28.                                 if (!player) return;// проверка найден игрок
  29.                                 CPed *ped = randomfindped(player, 20.0);
  30.                                 //ped->bfFlagsD &= 0x7F;//это метода нет
  31.                                 ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, CWorld::Players[CWorld::PlayerInFocus].m_pPed);
  32.                         }};
  33.         }
  34. } message;
  35.  

все работает без проблем.

Код: Text
  1. CPed* randomfindped(CPed *p, float radius) {CVehicle* v = NULL;
  2.  
  3.         if (p->m_bInVehicle && p->m_pVehicle != NULL) {// в авто игрок?
  4.                 CVehicle *v = p->m_pVehicle;    }// получить указатель на хенлд авто в котором сидит томии.
  5.         for (auto car : CPools::ms_pVehiclePool) {
  6.                 if (car != v && DistanceBetweenPoints(car->GetPosition(), p->GetPosition()) < radius && car->m_fHealth > 50) {
  7.                 car->CanPedExitCar(true);// пед может выйти из авто
  8.                 if (car->m_pDriver != NULL && car->m_pDriver != p) {
  9.                         CMessages::AddMessageJumpQ("found ped", 1000, 0);//выводит сообщение на экран
  10.                         return car->m_pDriver;
  11.                 }
  12.  
  13.         }
  14. }
  15.         for (auto ped : CPools::ms_pPedPool) {
  16.                 if (ped != p && DistanceBetweenPoints(ped->GetPosition(), p->GetPosition()) < radius && ped->m_fHealth > 50) {
  17.                         CMessages::AddMessageJumpQ("found ped", 1000, 0);//выводит сообщение на экран
  18.                         return ped;     }
  19.        
  20.         }
  21.                  CMessages::AddMessageJumpQ("not found ped", 1000, 0);  
  22.                         return NULL;
  23. };
  24. bool flag = false;
  25. class Message {//имя класса
  26. public:
  27.         Message() {
  28.                 Events::gameProcessEvent += [] {//обработчик событий игры
  29.                                 CPed *player = FindPlayerPed();// найти игрока
  30.                         KeyCheck::Update();
  31.                         if (KeyCheck::CheckWithDelay('M', 200)|| flag==true) {//если м нажата
  32.                                 flag=true;
  33.                                 if (!player) return;// проверка найден игрок
  34.                                 CPed *ped = randomfindped(player, 20.0);
  35.  
  36.                                 if (ped == NULL) return;// проверка найден игрок
  37.                                 ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, CWorld::Players[CWorld::PlayerInFocus].m_pPed);
  38.                         }
  39.                 };
  40.         }
  41. } message;
  42.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 20, 2019, 08:00:56 am
Цитировать
//ped->bfFlagsD &= 0x7F;//это метода нет
Это установка флага. В базе и в sdk записи в данный момент не совпадают и не все флаги "обозначены" правильно.
Надо так:
Код: C++
  1. ped->m_nPedFlags.b32 = 0;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 21, 2019, 03:59:08 am
 Спасибо за ваш ответ kenking. Всё таки получилось создать педа. Но вопрос правильно ли?
Код: Text
  1. CPed * create(int modelID) {// создать pedа
  2.         char reference = 2;// чтобы удалился потом.
  3.         CPed *player = FindPlayerPed();
  4.         CVector position = player->m_placement.pos;
  5.         position += player->m_placement.up * 10.f; // Вектор оси прямо от игрока умножаем на 10 метров и прибавляем к позиции.
  6.         CStreaming::RequestModel(modelID, 0); // загрузим.
  7.         CStreaming::LoadAllRequestedModels(false);// модель загружена.
  8.         CPed *ped = new CCivilianPed(PEDTYPE_COP, modelID);
  9.                
  10.         ped->m_nState = 4;// флаг
  11.         ped->m_placement.SetRotate(0, 0, 3.5f);// смещение от координат игрока
  12.         ped->m_placement.pos.x = position.x;
  13.         ped->m_placement.pos.y = position.y;
  14.         ped->m_placement.pos.z = position.z;
  15.         CWorld::Add(ped);// добавить в мир педа.
  16.         return ped;    
  17. }
  18.  

за что отвечают эти функции?
Код: Text
  1.  //v->CollideWithPed(player);//??
  2. // v->HasAttractor();//??
  3. // v->Initialise();//?
  4.  

как заставить педа бежать к координатам? в некоторые функциях есть параметр CVector, что передаем в таком случае?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 21, 2019, 10:01:02 am
Цитировать
как заставить педа бежать к координатам?
В который раз объясняю, что надо смотреть в базе, как устроен соответствующий опкод, без этого не разберёшься.
Код: C++
  1. CPed *ped;
  2. CVector *point;
  3. ped->m_nPedFlags.b32 = 0;
  4. CPed::SetObjective(ped, OBJECTIVE_RUN_TO_AREA, point);

Цитировать
в некоторые функциях есть параметр CVector, что передаем в таком случае?
Вектор и передаём.

Цитировать
за что отвечают эти функции?
Переведи названия функций, смотри в базе, где они вызываются, может используются в каких-либо скриптовых командах (опкодах).
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 28, 2019, 07:56:34 pm
благодарю Вас за помощь kenking. пытаюсь разобраться. Вы пишите- надо смотреть как устроен в базе.
хорошо, что нужно изучить?  Чтобы в ней разбираться.  Было бы здорово к каждой функции иметь  комментарий, для лучшего понимания.
 Не всегда название функции, помогают понять как они работают.
 Всё это время вникал в класс cped,  Вот, Может это кому-то облегчить путь.
Код: C++
  1.  
  2.                                 // v->ClearInvestigateEvent();// пед уходит, опустить педа.
  3.                                 // v->ReactToAttack(player);// временно атакует
  4.                                 // CVector pla = player->m_placement.pos;
  5.                                 // CVector ped = v->m_placement.pos;
  6.                                  //v->FightHitPed(player,ped,pla,1);// как бы получает удар и теряет хп.
  7.  
  8.                                  
  9.                                  // чем отличается способы получение вектора?
  10.                                   CVector pos = player->GetPosition(); 
  11.                                    //CVector pos = player->m_placement.pos;                            
  12.  
  13.                                   // телепорт чем отличает 2 функции телепорта?                                                                                     
  14.                                  //player->m_placement.SetTranslate(pos.x, pos.y, pos.z + 13.0f);
  15.                                  //player->m_placement.SetTranslateOnly(pos.x, pos.y, pos.z + 13.0f);
  16.                                  
  17.                                  //v->m_placement.RotateX(45.0);// перемещение, поворот.
  18.                                  //player->m_placement.SetRotate(pos.x, pos.y, pos.z + 13.0f);// телепорт.
  19.                                  //player->m_placement.Rotate(pos.x, pos.y, pos.z + 13.0f);// телепорт в разные места.
  20.                
  21.                                  // v->CanPedJumpThis(player, pos.x);//?? прыжок?.
  22.                                 //v->Mug();//?
  23.                                  //v->DeadPedMakesTyresBloody();//?? может быть кровавые следы педа.
  24.  
  25.                                   //v->SetObjective(player, OBJECTIVE_RUN_TO_AREA, &pos);//не получается заставить идти педа в координаты.
  26.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 29, 2019, 12:39:32 pm
Цитировать
Вы пишите- надо смотреть как устроен в базе.
хорошо, что нужно изучить?  Чтобы в ней разбираться.
Отрыть базу в IDA. Взять простой опкод или простую функцию и попытаться понять, разобрать как он  устроен (как работает функция). Мне легче разбирать в псевдокоде (F5).

Цитировать
Не всегда название функции, помогают понять как они работают.
Поэтому я и написал, что надо смотреть в базе, где вызываются эти функции.

Цитировать
// чем отличается способы получение вектора?
CVector pos = player->GetPosition(); 
//CVector pos = player->m_placement.pos;
Ничем.
Код: C++
  1. inline CVector &GetPosition() {
  2.     return m_placement.pos;
  3. }

Цитировать
// телепорт чем отличает 2 функции телепорта?
Если в названии функции есть приставка Only, то при вращении (например, компонента транспорта) не придётся сохранять координаты позиции компонента, компонент просто повернётся на указанный градус и останется в той же позиции. Если использовать "похожую" функцию без этой приставки в названии, то надо перед вращением считывать координаты позиции компонента, после вращения их восстанавливать, так как координаты сбросятся в ноль после вращения. Аналогично для функций перемещения, только для значений углов поворота.

 
Цитировать
// v->CanPedJumpThis(player, pos.x);//?? прыжок?.
Это проверка может ли сделать прыжок. Смотри в базе, где вызывается
Код: C++
  1. if ( CPed::CanPedJumpThis(ped, pedTwo, &ped->physical.m_vecCollisionPower) )
  2.     CPed::SetJump(ped);
Обращай внимание на параметры.

Цитировать
//v->SetObjective(player, OBJECTIVE_RUN_TO_AREA, &pos);//не получается заставить идти педа в координаты.
Код: C++
  1. CVector offset = { 0.0f, 20.0f, 0.0f };
  2. CVector point = player->m_placement * offset;
  3. player->m_nPedFlags.bHasObjectiveCompleted = 0;
  4. player->SetObjective(OBJECTIVE_RUN_TO_AREA, point);

Что касается других функций. Сделай какой-нибудь простой плагин для тестов, например, так.
Код: C++
  1. #include "plugin.h"
  2. #include "CPed.h"
  3. #include "extensions\KeyCheck.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class Test {
  8. public:
  9.     static CPed *GetRandomPed(CVector const &posn, float radius) {
  10.         std::vector<CPed *> peds;
  11.         for (auto ped : CPools::ms_pPedPool) {
  12.             if (DistanceBetweenPoints(ped->GetPosition(), posn) <= radius)
  13.                 peds.push_back(ped);
  14.         }
  15.         return peds.empty() ? nullptr : peds[plugin::Random(0, peds.size() - 1)];
  16.     }
  17.    
  18.     Test() {
  19.         Events::gameProcessEvent += [] {
  20.             KeyCheck::Update();
  21.             if (KeyCheck::CheckWithDelay('M', 500)) {
  22.                 CPed *player = FindPlayerPed();
  23.                 if (player) {
  24.                     CPed *ped = GetRandomPed(player->GetPosition(), 15.0f);
  25.                     if (ped) {
  26.                         CVector offset = { 0.0f, 2.0f, 0.0f };
  27.                         CVector point = player->m_placement * offset;
  28.                         ped->m_nPedFlags.bHasObjectiveCompleted = 0;
  29.                         ped->SetObjective(OBJECTIVE_RUN_TO_AREA, point);
  30.                     }
  31.                 }
  32.             }
  33.         };
  34.     }
  35. } test;

и проверяй нужные тебе функции (не забывай про правильную передачу параметров).


Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Май 29, 2019, 09:52:23 am
Здравствуйте, уважаемый kenking.   Спасибо большое я ваш  ответ. сделал плагин для тестов,  изучаю  Assembler  идёт очень тяжело.

 Пытаюсь разобрать функции  в псевдокоде, иногда псевкод простой функции отражается так.  Может, он не так должен отображается?

  Благодарю благодарю Вас за объяснения функций телепорта,  буду изучать как это работает на практике.
 Выходит это проверка сделан ли прыжок.
 Насчёт функции player->SetObjective(OBJECTIVE_RUN_TO_AREA, point);// заставить педа бежать в точку.  А функция ped->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, point);// пед идет.

 Вообще  функция SetObjective  имеет 5  перегрузки.
    void SetObjective(eObjective objective);// emun.
    void SetObjective(eObjective objective, CVector arg1);// emun и вектор.
    void SetObjective(eObjective objective, float arg1, CVector const& arg2);// emun, float, вектор.
    void SetObjective(eObjective objective, short arg1, short arg2);// emun, int, int.
    void SetObjective(eObjective objective, void* arg1);// emun, функция.

 Это понятно,  теперь  допустим берём emun OBJECTIVE_SOLICIT_VEHICLE,  какие параметры передать в функцию SetObjective. Поймите меня правильно,  Очень хочу разобраться в этом.  Например, более- менее  понимаю в api lua,  вот написал  небольшую  подсказку новичкам
код https://pastebin.com/8f9UH56W

 Мне бы хотелось в будущем  написать  статьи,  Как создавать плагины.
 Посоветуйте пожалуйста,  какую литературу прочитать,  чтобы  понимать основы работы движка игры?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Май 29, 2019, 08:12:16 pm
Цитировать
теперь  допустим берём emun OBJECTIVE_SOLICIT_VEHICLE,  какие параметры передать в функцию SetObjective.
Код: C++
  1. CPed *ped;
  2. CVehicle *vehicle;
  3. ped->SetObjective(OBJECTIVE_SOLICIT_VEHICLE, vehicle);

Цитировать
Пытаюсь разобрать функции  в псевдокоде, иногда псевкод простой функции отражается так.  Может, он не так должен отображается?
Учиться разбирать надо с маленьких функций.
Возьмём для примера функцию CPed::SetObjectiveTimer
Нажимаем F5 и получаем такой псевдокод:
Код: C++
  1. unsigned int __thiscall CPed::SetObjectiveTimer(int this, int a2)
  2. {
  3.   unsigned int result; // eax@2
  4.  
  5.   if ( a2 )
  6.   {
  7.     result = *(_DWORD *)(this + 1360);
  8.     if ( CTimer::m_snTimeInMilliseconds > result )
  9.     {
  10.       result = CTimer::m_snTimeInMilliseconds + a2;
  11.       *(_DWORD *)(this + 1360) = CTimer::m_snTimeInMilliseconds + a2;
  12.     }
  13.   }
  14.   else
  15.   {
  16.     *(_DWORD *)(this + 1360) = 0;
  17.   }
  18.   return result;
  19. }

Это метод класса CPed, значит первым параметром передаётся указатель на этот класс.
Ставим курсор мышки на this, нажимаем Y и вводим вместо int CPed* (или можно нажать правую клавишу мыши и в контекстном меню выбрать Convert to struct* и выбрать из списка имеющихся в базе структур CPed)
Получается так:
Код: C++
  1. unsigned int __thiscall CPed::SetObjectiveTimer(CPed *this, int a2)
Смотрим тип второго аргумента, там должен быть unsigned int, а у нас int, исправляем (курсор мыши на a2, нажимаем Y и добавляем unsigned перед int):
Код: C++
  1. unsigned int __thiscall CPed::SetObjectiveTimer(CPed *this, unsigned int a2)
Переменную a2 переименуем в time, курсор мыши на a2, нажимаем N и вводим time:
Код: C++
  1. unsigned int __thiscall CPed::SetObjectiveTimer(CPed *this, unsigned int time)
Смотрим в тех функциях, где вызывается эта функция есть ли возвращаемое значение (клавиша X и переход в место, где эта функция вызывается).
В данном случае возвращаемого значения нет. Меняем тип возвращаемого значения на void, курсор на названии функции и Y, воодим void вместо unsigned int:
Код: C++
  1. void __thiscall CPed::SetObjectiveTimer(CPed *this, unsigned int time)

Можно было все вышеперечисленные правки сделать в этом последнем действии (Y на названии функции и ввод нужных данных и изменение названий переменных), показал отдельно для наглядности.
В итоге получилось так:
Код: C++
  1. void __thiscall CPed::SetObjectiveTimer(CPed *this, unsigned int time)
  2. {
  3.   if ( time )
  4.   {
  5.     if ( CTimer::m_snTimeInMilliseconds > this->m_nObjectiveTimer )
  6.       this->m_nObjectiveTimer = CTimer::m_snTimeInMilliseconds + time;
  7.   }
  8.   else
  9.   {
  10.     this->m_nObjectiveTimer = 0;
  11.   }
  12. }

Всё стало ясно и понятно, не так ли?
Ну это простая функция и разбирать её легко, но начинать надо именно с таких простых функций.
Изменения надо сохранить в базе (нажать на иконку сохранения).


Возьмём для второго примера ещё одну небольшую функцию CPed::Teleport
Нажимаем F5 и получаем такой псевдокод:
Код: C++
  1. char __thiscall CPed::Teleport(CEntity *this, float a2, int a3, int a4)
  2. {
  3.   CEntity *v4; // ebx@1
  4.  
  5.   v4 = this;
  6.   CWorld::Remove(this);
  7.   v4->m_placement.m_matrix.pos.x = a2;
  8.   v4->m_placement.m_matrix.pos.y = *(float *)&a3;
  9.   v4->m_placement.m_matrix.pos.z = *(float *)&a4;
  10.   LOBYTE(v4[3].m_placement.m_matrix.pad1) &= 0xFEu;
  11.   v4[5].m_pRwObject = 0;
  12.   v4[5].m_placement.m_matrix.pAttached = 0;
  13.   v4[5].m_placement.m_matrix.bDeleteOnDetach = 0;
  14.   v4[2].m_placement.m_matrix.pad4 = 0;
  15.   return CWorld::Add((CPhysical *)v4);
  16. }

Это метод класса CPed, но сейчас в псевдокоде почему-то класс CEntity, вместо второго параметра CVector одна переменная типа float и две типа int, возвращаемое значение стоит char, хотя функция ничего не должна возвращать. Будем исправлять.
Нажимаем Y на названии функции и водим нужные данные:
Код: C++
  1. void __thiscall CPed__Teleport(CPed *this, CVector point)
Переименовываем переменную v2 в ped.
Получаем такой псевдокод:
Код: C++
  1. void __thiscall CPed::Teleport(CPed *this, CVector point)
  2. {
  3.   CPed *ped; // ebx@1
  4.  
  5.   ped = this;
  6.   CWorld::Remove(&this->physical.entity);
  7.   ped->physical.entity.m_placement.matrix.pos = point;
  8.   ped->bfFlagsA &= 0xFEu;
  9.   ped->m_nActionTimer = 0;
  10.   ped->fActionX = 0;
  11.   ped->fActionY = 0;
  12.   ped->physical.m_pPhysColliding = 0;
  13.   CWorld::Add(&ped->physical);
  14. }

Ну тут тоже всё стало понятно (за исключением установки какого-то флага, но это отдельная история, не все флаги названы).
Изменения надо сохранить в базе (нажать на иконку сохранения).

 
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Май 31, 2019, 08:46:39 pm
Спасибо вам огромное уважаемый kenking за исключительно подробный ответ. Вы столько времени на него потратили. за это я вам очень благодарен. Примерно, понимаю какие параметры передавать в  функцию.  Вот нашел список  https://zredix.com/index.php?title=GTA_VC_Functions(1.0)

  Долго копался тестировал, может кому поможет.

Код: Text
  1. //ped->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, player);// пед хочет убить игрока.
  2. //ped->SetObjective(OBJECTIVE_SPRINT_TO_AREA, point);// пед делает спринт к точке.
  3. //CMessages::AddMessage(L"ok", 2000, 0);// 0 текст белого цвета.
  4. //CMessages::AddBigMessage(L"ok", 2000, 0);/*0 большими, розовые как миссии пройдена, 1 надпись как названия миссии, 2 зеленым большими,
  5. // в правом нижним углу, 3 синим в центре, 4 зеленным в центре.*/
  6. //ped->SetObjective(OBJECTIVE_SOLICIT_VEHICLE, v);// ЦЕЛЬ.ПРОСИТЬ.ТРАНСПОРТ пед подходит к авто.
  7. //ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, v);// пед садится как пассажир.
  8. //ped->SetObjective(OBJECTIVE_DESTROY_CAR, v);// пед ударит авто.
  9. ped->SetDead();// как будь-то пед умер под ним кровь.
  10.  
  11.                                         Проверка пед не в воздухе, а на земле.
  12.                                         if(!ped->CheckIfInTheAir()){
  13.  
  14.                                                 CMessages::AddMessageJumpQ(L"ped not in air", 1000, 0);
  15.                                         }
  16.  
  17.  

 Иногда явного  эффекта от функции нет.  Например, что даёт  функция
ped->SetObjectiveTimer(60000);

 Да это таймер,  но никакой задержка  вы действиях педа не наблюдается.
или Idle(). псевкоду что-то перерисовывает.

 Скажите пожалуйста, когда завершится работа над  sdk plugin?  чтобы можно было  приступить к   документации всех функций,   тогда новичкам будет легче освоится.

 Допустим, CLEO которая является хуком  знаю,  где посмотреть ее исходник на с++. Может  это поможет разобраться?  Посоветуйте, пожалуйста, книгу,  которая помогла вам стать  таким крутым специалистом??
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 01, 2019, 09:40:13 am
Цитировать
Иногда явного  эффекта от функции нет.  Например, что даёт  функция
ped->SetObjectiveTimer(60000);
 Да это таймер,  но никакой задержка  вы действиях педа не наблюдается.
Задержки и не должно быть. По-идеи это установка максимального времени на какое-то действие педа (как я это понимаю).

Цитировать
Скажите пожалуйста, когда завершится работа над  sdk plugin?  чтобы можно было  приступить к   документации всех функций,   тогда новичкам будет легче освоится.
Думаю, что ещё несколько лет.

Цитировать
Допустим, CLEO которая является хуком  знаю,  где посмотреть ее исходник на с++. Может  это поможет разобраться?  Посоветуйте, пожалуйста, книгу,  которая помогла вам стать  таким крутым специалистом??
Я учусь разбираться в классах игры также, как и ты и крутым специалистом себя не считаю. В некоторых случаях, чтобы ответить на твой вопрос, мне приходится самому его сначала разобрать. Никакой такой книги я не знаю. Мне помогли подсказки и советы DK и других пользователей, которые они писали в этой теме, в целом на этом форуме и других форумах.

Вот немного пояснений, которые я для себя сохранил:
Цитировать
Если есть IDA и idb-база, то для "распутывания ниточек" можно использовать такие приёмы:

Как определить, откуда вызывается данная функция?
1.Открываем код функции в основной вкладке.
2.Далее выбираем в меню пункт View - Open Subviews - Function calls - список Caller.

Как определить, откуда происходит обращение к данному адресу?
1.Вставляем курсор между буквами названия адреса. Например здесь
Code:

.data:00B7CB84 _currentTime dd ? ; DATA XREF: _sub_406E50r

вставляем курсор между любыми буквами _currentTime.
2.Жмём X. Открывается список ссылок на данный адрес.


Очень часто случается такое, что декомпилятор (hex-rays) выдаёт ошибку "switch analysis failed".
Случается это в функциях, где используется конструкция switch.
Случается это потому что (моё предположение) разные версии декомпилятора по-разному работают с этой
конструкцией.
В официальных доках рекомендуют вручную настроить эту конструкцию, но есть более простое решение:
пересобрать функцию.
Для этого надо преобразовать функцию в обычные данные, преобразовать данные в код, и создать функцию.

1. Нажимаем U на названии функции (Undefine function).
2. Нажимаем C на первом байте (Code)
3. Нажимаем P (Create function).

В exe есть 2 основных типа адресов - data и text (есть и другие типы). Если проводить аналогию со
скриптами, то адреса типа data можно сравнить с глобальными переменными - в них хранятся различные
значения (например, 0xB7CB84 - [dword] Глобальный таймер в ms, 0x8D2530 - [float] Плотность движения
пешеходов). В ходе игры отдельные процедуры exe читают эти значения или записывают в эти адреса новые
значения. Эти адреса (не все) можно читать/перезаписывать и в скрипте с помощью опкодов 0A8C/0A8D.
Назначение некоторых часто употребляемых data-адресов, а также смещений в структурах можно найти тут:
[url]http://gtamodding.ru[/url] ([url]http://gtamodding.ru[/url])...еса_Памяти_(SA)
Что касается адресов типа text, то в них записаны отдельные команды, из которых в свою очередь
состоят процедуры exe. Сами по себе значения этих адресов во время игры не меняются, но их, как и
адреса data, можно (не все) менять скриптом - в этом случае в опкодах 0A8C/0A8D следует ставить
значение параметра virtual protect, равное 1. Понятно, что в случае изменения значения text-адреса,
процедура, которой он принадлежит, станет работать уже по новому алгоритму.
Для поиска нужных адресов и процедур незаменима idb-база от listener. Открыть её можно с помощью
IDA 5. В окне программы есть несколько вкладок, которые представляют код exe в различном виде.
Основные из них: "IDA View-A" - основной вид. Если текущий участок exe состоит из адресов типа data,
то они отображаются в виде списка, а если текущий участок является какой-то
процедурой (text-адреса), то она отобразится в виде блок-схемы. "Hex View-A" - побайтовое отображение
кода. Многие data-адреса и процедуры в базе проименованы, при активной вкладке "IDA View-A" можно
осуществлять их поиск по названию (Search - Text).
Есть ещё полезная вкладка Functions - список всех процедур exe. Если эта вкладка активна, то можно
осуществить поиск процедуры по названию (Search). Например, осуществив поиск по слову train, можно
найти процедуры, имеющие отношение к поездам. При щелчке по названию процедуры, активируется вкладка
"IDA View-A" и появится блок-схема этой процедуры, по которой можно исследовать, как она
работает (какие процедуры вызывает, со значениями каких адресов оперирует и т.д.).


Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июнь 02, 2019, 12:41:45 am
 Здравствуйте уважаемый kenking. Был  уверен,  что вы досконально знаете все функции в sdk. Вы же понимаете хочется всё и сразу.
Пока непонятно как это задержка работает.
Несколько лет это долго.
Советы и подсказки от других людей это конечно хорошо, в час по чайной ложке, а желание всё горит внутри. Например, учил с++ - посмотрел видеокурсы, переписал код, с ним поэкспериментировал, прочитал несколько книг, так учебный процесс прошел быстро.
А тут прямо буксую. Сегодня нашел вот что
Код: C++
  1. ped->SetObjective(OBJECTIVE_HASSLE_CHAR, player); // пед идет к игроку.
  2. ped->SetAttack(player);//пед бьет
  3. ped->Attack();// правой рукой.
  4.  
  5.  
Спасибо большое за ваше объяснение. Очень не хочется,чтобы такой гениальный проект забросили.

Как использовать эту скриптовую команду?
Код: C++
  1.  
  2.                                         CPed* ped = randomfindped(player, 30.0);
  3.                                         CObject *p;
  4.                                         Command<COMMAND_ADD_BLIP_FOR_CHAR_OLD>(CPools::GetPedRef(ped), p);
  5.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 03, 2019, 09:37:28 am
Цитировать
Как использовать эту скриптовую команду?
Скриптовая команда - это опкод, смотришь в eScriptCommands какому номеру опкода соответствует эта команда. Открываешь поиск опкодов в SB, находишь нужный опкод: 0162: tie_marker $2344 to_actor $2320 4 2
Смотришь параметры этого опкода.
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\KeyCheck.h"
  3. #include "extensions\ScriptCommands.h"
  4. #include "eScriptCommands.h"
  5.  
  6. using namespace plugin;
  7.  
  8. class Test {
  9. public:
  10.     static int blip;
  11.    
  12.     Test() {
  13.         Events::gameProcessEvent += [] {
  14.             CPed *player = FindPlayerPed();
  15.             KeyCheck::Update();
  16.             if (player && KeyCheck::CheckWithDelay('M', 1000))
  17.                 Command<COMMAND_ADD_BLIP_FOR_CHAR_OLD>(CPools::GetPedRef(player), 4, 2, &blip);
  18.             if (player && KeyCheck::CheckWithDelay('N', 1000))
  19.                 Command<COMMAND_REMOVE_BLIP>(blip);
  20.         };
  21.     }
  22. } test;
  23.  
  24. int Test::blip;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июнь 08, 2019, 01:51:01 pm
 Спасибо большое уважаемый kenking за ваш ответ. Это очень удобно использовать скриптовые команды. Благодаря им наметился  определенный прогресс, что радует.
Не думал, что маркер, это int.  Предполагал,  что мы должны передать  структуру.
Вот примеры, может кому-то облегчать путь.
Код: C++
  1. Command<COMMAND_ADD_BLIP_FOR_CHAR>(CPools::GetPedRef(ped), &blip);// стрелка над педом.
  2. Command <COMMAND_SET_CHAR_MONEY>(CPools::GetPedRef(ped), 1000);// дать денег педу, но почему-то выходит 1006, может это прибавка?.
  3.  

 Конечно, как всегда столкнулся с трудностями,  как использовать скриптовую команду в качестве проверки?
 Пробовал разные варианты, получал  только вылет.
Код: C++
  1.         bool mod;
  2. class Test {//имя класса
  3. public:
  4.  
  5.         Test() {
  6.                 Events::gameProcessEvent += [] {
  7.                         CPed* player = FindPlayerPed();
  8.                         KeyCheck::Update();
  9.  
  10.                         if (KeyCheck::CheckWithDelay('M', 1000)){
  11.                        
  12.                         Command<COMMAND_IS_PLAYER_IN_ANY_CAR>(CPools::GetPedRef(player), mod);
  13.                         if(mod == true){ CMessages::AddMessageJumpQ(L"in car", 1000, 0);
  14.                         }
  15.                         }
  16.                 };
  17.         }
  18. } test;
  19.  
  20.  

 Так же интересная ситуация с выводом целых чисел на экран, они не выводится.
Код: C++
  1. class Test {//имя класса
  2. public:
  3.  
  4.         Test() {
  5.                 Events::gameProcessEvent += [] {
  6.                         CPed* player = FindPlayerPed();
  7.                         KeyCheck::Update();
  8.  
  9.                         if (KeyCheck::CheckWithDelay('M', 300)){
  10.                                 int numb = 3;
  11.                                 static char x[256];
  12.                                 snprintf(x, 256, "x = %.d", numb);
  13.  
  14.                         }
  15.                 };
  16.         }
  17. } test;
  18.  

Все сделал по правилам форматирования сделал в с++, может, что-то упустил? Подскажите, пожалуйста.

Разобрался с проверками.
Код: C++
  1.  
  2.                         mod = Command<COMMAND_IS_PLAYER_IN_ANY_CAR>();
  3.                         if(mod== true){
  4.                         CMessages::AddMessageJumpQ(L"in car", 1000, 0);
  5.                 }
  6.                         else{
  7.                                 CMessages::AddMessageJumpQ(L"not in car", 1000, 0);
  8.                         }
  9.                 }
  10.  

Создать машину.
Код: C++
  1.                         if (KeyCheck::CheckWithDelay('M', 300)){
  2.                                 Command<COMMAND_REQUEST_MODEL>(MODEL_COMET);
  3.                                 bool f = Command<COMMAND_HAS_MODEL_LOADED>(MODEL_COMET);
  4.                         if ( f== true) {
  5.                                 CVector pos = player->GetPosition();
  6.                                 CVehicle* v = nullptr;
  7.                                 Command<COMMAND_CREATE_CAR>(MODEL_COMET, pos.x, pos.y+10, pos.z, &v);
  8.                 }
  9. }
  10.                 };
  11.  


Только не получается дать оружие игроку через скриптовую команду.

Код: Text
  1.                         if (KeyCheck::CheckWithDelay('M', 300)){
  2.                        
  3.                                 Command<COMMAND_REQUEST_MODEL>(MODEL_COLT45);
  4.                         if (Command<COMMAND_HAS_MODEL_LOADED>(MODEL_COLT45)) {
  5.                                
  6.                                 CMessages::AddMessageJumpQ(L"model load", 1000, 0);
  7. Command<COMMAND_GIVE_WEAPON_TO_PLAYER>(CPools::GetPedRef(player), WEAPONTYPE_PISTOL, 100);
  8.                 }
  9.  

Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 08, 2019, 08:25:44 pm
Цитировать
Не думал, что маркер, это int.  Предполагал,  что мы должны передать  структуру.
Это ID маркера.

Цитировать
Конечно, как всегда столкнулся с трудностями,  как использовать скриптовую команду в качестве проверки?
Цитировать
Так же интересная ситуация с выводом целых чисел на экран, они не выводится.
Цитировать
Разобрался с проверками.
Цитировать
Только не получается дать оружие игроку через скриптовую команду.
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\KeyCheck.h"
  3. #include "CMessages.h"
  4. #include "extensions\ScriptCommands.h"
  5. #include "eScriptCommands.h"
  6. #include "CWorld.h"
  7. #include "eWeaponModel.h"
  8. #include "eWeaponType.h"
  9. #include "CStreaming.h"
  10.  
  11. using namespace plugin;
  12.  
  13. class Test {
  14. public:
  15.     static int m_test;
  16.  
  17.     Test() {
  18.         Events::gameProcessEvent += [] {
  19.             CPed *player = FindPlayerPed();
  20.             KeyCheck::Update();
  21.             if (KeyCheck::CheckWithDelay('B', 1000)) {
  22.                 static char message[256];
  23.                 snprintf(message, 256, "test = %d", m_test);
  24.                 CMessages::AddMessageJumpQ(message, 1000, false);
  25.             }
  26.             if (player) {
  27.                 if (KeyCheck::CheckWithDelay('N', 1000)) {
  28.                     //if (player->m_bInVehicle)
  29.                     if (Command<COMMAND_IS_PLAYER_IN_ANY_CAR>(CWorld::PlayerInFocus))
  30.                         CMessages::AddMessageJumpQ(L"in car", 1000, 0);
  31.                     else
  32.                         CMessages::AddMessageJumpQ(L"not in car", 1000, 0);
  33.                 }
  34.                 if (KeyCheck::CheckWithDelay('M', 1000)) {
  35.                     //CWorld::Players[CWorld::PlayerInFocus].m_nMoney += 1000;
  36.                     Command <COMMAND_ADD_SCORE>(CWorld::PlayerInFocus, 1000);
  37.  
  38.                     /*CStreaming::RequestModel(MODEL_COLT45, 2);
  39.                     CStreaming::LoadAllRequestedModels(false);
  40.                     player->GiveWeapon(WEAPONTYPE_PISTOL, 100, true);
  41.                     player->SetCurrentWeapon(WEAPONTYPE_PISTOL);
  42.                     CStreaming::SetModelIsDeletable(MODEL_COLT45);*/
  43.                     Command<COMMAND_REQUEST_MODEL>(MODEL_COLT45, 2);
  44.                     Command<COMMAND_LOAD_ALL_MODELS_NOW>(false);
  45.                     if (Command<COMMAND_HAS_MODEL_LOADED>(MODEL_COLT45)) {
  46.                         Command<COMMAND_GIVE_WEAPON_TO_PLAYER>(CWorld::PlayerInFocus, WEAPONTYPE_PISTOL, 100, true);
  47.                         Command<COMMAND_SET_CURRENT_PLAYER_WEAPON>(CWorld::PlayerInFocus, WEAPONTYPE_PISTOL);
  48.                         Command<COMMAND_MARK_MODEL_AS_NO_LONGER_NEEDED>(MODEL_COLT45);
  49.                     }
  50.                 }
  51.             }
  52.         };
  53.     }
  54. } test;
  55.  
  56. int Test::m_test = 3;

Цитировать
Это очень удобно использовать скриптовые команды.
Скриптовые команды надо использовать в случае отсутствия в sdk нужных функций и классов (ну для тестов ещё, чтобы поучиться). В остальном надо писать код с  разобранными функциями. В примере такой альтернативный код закомментирован.
Пример с оружием есть в sdk, ты же уже про это спрашивал.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июнь 14, 2019, 04:11:12 pm

 kenking, Бесконечно Вам благодарен. Потихоньку начинаю понимать, как это устроено.  Есть тестовой плагин, где экспериментирую.  Выходит маркер имеет свой id.
 Спасибо,  что Вы показали  как работает скриптовая комманда,  бывает привычнее использовать их, они похожи на опкоды cleo.
 Очень признательный, что вы  показали  как выводить целые числа на экран.

 Всегда хотел, написать плагин, позволяющий запускать lua скрипты для vc.
sdk имеет свой основный поток, который является  бесконечным циклом,  В каком-то роде. Если  там поставить задержу, например,  10 секунд, то на это время остановится игра.  Поэтому  запускаем  новый Независимый поток с флагом, для того,  чтобы  он был один.
Ищем  все lua файлы в папке,  запускаем в новом потоке с новым lua состоянием. Потоки и lua состояния  добавляются в вектора.
 Идет проверка на ошибки, счетчик запущенных скриптов увеличивается,  запускаем скрипт,  получаем в стек функцию main,  запускаем её.

В lua  находится функция main. она  имеет бесконечный цикл.  Всё работает, но есть одно но.  Как сделать перезагрузку всех скриптов?
 Нажимаем ctrl, проходим циклом for  вектор  c lua  состояниями,  снимаем со стека  функции, закрываем lua состоянием.
  Но к сожалению,  всё зависает.  Подскажите пожалуйста,  как правильно написать реализацию перезагрузке скриптов.
Код: C++
  1. void second(bool& reload) {
  2. vector<thread>t;//вектор для lua потоков.
  3. vector<lua_State*>luastate;// вектор для lua состояний.
  4.         for (auto const& de : fs::recursive_directory_iterator{ fs::current_path() / "lualoader" }) { // папка для поиска
  5.                 if (de.path().extension() == ".lua" || de.path().extension() == ".LUA") {
  6.                         string res = de.path().string();// перевод имя файла в строку.
  7.                         t.push_back(move((std::thread(search, res, std::ref(luastate)))));// добавить поток в вектор.
  8.                 }
  9.         };
  10.        
  11.         while (true) {
  12.                 if (KeyPressed(VK_CONTROL)) {// перезагрузка скрипта        
  13.                         this_thread::sleep_for(chrono::milliseconds(1));
  14.                         static unsigned int time = 0;// обнулить таймер.
  15.                         if (CTimer::m_snTimeInMilliseconds - time > 500) {
  16.                                 time = 0;// обнулить таймер
  17.         for (auto L : luastate) { lua_pop(L, lua_gettop(L));// снять со стека функцию main.
  18.         counts--;// уменьшить счетчик.
  19.                 lua_close(L);// закрыть состояние.
  20. };
  21.                                 for (auto& i : t) {
  22.                                         i.detach(); // все потоки независимы.
  23.                                 };
  24.                                 break;
  25.  
  26.                         };
  27.                 };
  28.         };
  29.  
  30.         if (counts == 0){// если нет запущенных скриптов.
  31.                 reload = false; // флаг, что можно запускать новый поток.
  32.  
  33.         };                     
  34. };
  35.  
  36. class Message {//имя класса
  37. public: Message() {
  38.         Events::gameProcessEvent += [] {//обработчик событий игры
  39.                 CPed* player = FindPlayerPed();// найти игрока
  40.                 if (!player) return;// проверка найден игрок
  41.                 if (reload == false) {  reload = true;// флаг, что уже запущен поток.
  42.                         thread th(second, std::ref(reload)); th.detach();// независимый поток.         
  43.                 }
  44.         };
  45. }
  46. } message;
  47.  
  48.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 15, 2019, 08:13:12 am
К сожалению, по работе с lua скриптами ничего подсказать не могу.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июнь 18, 2019, 03:36:46 am
kenking рад, искреннему ответу, удалось реализовать отключение lua скриптов через триггер, также несколько новых функций.
 Есть список моделей машин и педов,  можно в lua создавать  авто car = createcar(model, x,y,z)- создает машину на координатах.
 Но при создание педов,  нужно указать его тип
ped = createped(model, 4, x, y, z) – создает педа на координатах, принимает модель, тип пед, координаты.

Скажите, пожалуйста, у вас есть список типа для каждого педа, хочу с помощью массива, определять  тип пед  автоматический.

в moonloader делал так.
Код: Text
  1.  
  2. function mymod.createped(m,x,y,z) -- создать педа
  3. list = {["BMYBE"]= {4,18}, ["HMYDRUG"]= {18,30}, ["SWMOCD"]= {4,234}, ["WMYLG"]= {4,97}, ["OMORI"]= {4,57}, ["HMYBE"]= {4,45}, ["WFYBU"]= {5,150},
  4. ["DWMOLC1"]= {4,32}, ["WFYCLOT"]= {5,211}, ["OMYKARA"]= {4,203}, ["WMYBE"]= {4,154}, ["WMYGOL1"]= {4,36}, ["CWFOFR"]= {5,196}, ["BFYBU"]= {5,148},
  5. ["BMORI"]= {4,14}, ["BMYDRUG"]= {18,28}, ["WMYKARA"]= {4,204}, ["SBMYST"]= {4,142}, ["SWMOST"]= {4,236}, ["BMYPIMP"]= {4,249}, ["FAM3"]= {8,107},
  6. ["MAFFA"]= {18,111}, ["ARMY"]= {6,287}, ["WFYRO"]= {5,92}, ["SBMYTR3"]= {4,136}, ["DNFYLC"]= {5,131}, ["VWFYWA2"]= {5,263}, ["SWMYRI"]= {4,240},
  7. ["DNFOLC2"]= {5,130}, ["WMOMIB"]= {4,165}, ["SOFOST"]= {5,225}, ["SOFORI"]= {5,224}, ["BMYPOL2"]= {4,67}, ["LSV3"]= {9,110}, ["MECGRL3"]= {5,192},
  8. ["SFFD1"]= {17,279}, ["SFR1"]= {10,173}, ["HFOST"]= {5,39}, ["OFOST"]= {5,54}, ["SWMOTR2"]= {4,135}, ["OMONOOD"]= {4,209}, ["WFOST"]= {5,89},
  9. ["BMYMIB"]= {4,166}, ["SWMYST"]= {4,188}, ["WMORI"]= {4,94}, ["BALLAS2"]= {7,103}, ["SWMYCR"]= {4,250}, ["VWMOTR2"]= {4,213}, ["WMYVA"]= {4,189},
  10. ["BMYCG"]= {18,144}, ["VHMYELV"]= {4,82}, ["WMYCLOT"]= {4,217}, ["SWMOTR3"]= {4,137}, ["VLA3"]= {14,116}, ["WMYCH"]= {4,255}, ["WMYVA2"]= {4,252},
  11. ["LSV2"]= {9,109}, ["SPECIAL03"]= {4,292}, ["WFYBURG"]= {5,205}, ["BMOCD"]= {4,262}, ["SBFYRI"]= {5,219}, ["WMYPLT"]= {4,61}, ["WMYRO"]= {4,99},
  12. ["VMAFF2"]= {12,125}, ["SPECIAL09"]= {4,298}, ["SBFYSTR"]= {5,256}, ["VWMYCD"]= {4,206}, ["VWMYBJD"]= {4,171}, ["DWFOLC"]= {5,31}, ["WMYJG"]= {4,96},
  13. ["MAFFB"]= {18,112}, ["SBMORI"]= {4,221}, ["TRIADB"]= {13,118}, ["SWFYSTR"]= {5,257}, ["BMYMOUN"]= {4,51}, ["DWFYLC1"]= {5,151}, ["OMOST"]= {4,58},
  14. ["TRIADA"]= {13,117}, ["BIKERB"]= {4,248}, ["SBMYRI"]= {4,185}, ["WFYST"]= {5,93}, ["HMOST"]= {4,44}, ["WMYCON"]= {4,27}, ["SOMORI"]= {4,228},
  15. ["BMYDJ"]= {4,19}, ["CWFYHB"]= {5,157}, ["SPECIAL02"]= {4,291}, ["WMOST"]= {4,95}, ["DWMYLC2"]= {4,202}, ["SWFYRI"]= {5,216}, ["DNFOLC1"]= {5,129},
  16. ["BFYST"]= {5,13}, ["SPECIAL10"]= {4,299}, ["BALLAS3"]= {7,104}, ["VIMYELV"]= {4,84}, ["CWMOHB1"]= {4,159}, ["WFYLG"]= {5,251}, ["OFYST"]= {5,56},
  17. ["DNMOLC2"]= {4,133}, ["BMOST"]= {4,15}, ["SHMYCR"]= {18,223}, ["HFYST"]= {5,41}, ["MALE01"]= {4,7}, ["LAFD1"]= {17,277}, ["SOMYBU"]= {4,187},
  18. ["WFORI"]= {5,88}, ["HECK1"]= {4,258}, ["SBMOTR2"]= {4,134}, ["SOFYBU"]= {5,141}, ["HFYBE"]= {5,140}, ["OFORI"]= {5,53}, ["VBMYCR"]= {18,183},
  19. ["WMYBOUN"]= {4,164}, ["WMOICE"]= {4,264}, ["BMYAP"]= {4,16}, ["HFORI"]= {5,38}, ["BFORI"]= {5,9}, ["BFYBE"]= {5,139}, ["SBFYST"]= {5,69},
  20. ["SOMOST"]= {4,229}, ["WFYBE"]= {5,138}, ["BIKDRUG"]= {4,254}, ["GUNGRL3"]= {5,191}, ["MAFBOSS"]= {18,113}, ["DNMOLC1"]= {4,132}, ["SOFYST"]= {5,226},
  21. ["FBI"]= {6,286}, ["DSHER"]= {6,288}, ["VBFYCRP"]= {5,11}, ["WMOPJ"]= {4,62}, ["CWFYFR1"]= {5,198}, ["VMAFF1"]= {12,124}, ["SWFOST"]= {5,232},
  22. ["CWMYHB2"]= {4,200}, ["DNB1"]= {11,121}, ["DWMOLC2"]= {4,33}, ["CSHER"]= {6,283}, ["DWFYLC2"]= {5,201}, ["SWFORI"]= {5,231}, ["VWMYBOX"]= {4,81},
  23. ["WMYBP"]= {4,26}, ["VWFYST1"]= {5,87}, ["FAM1"]= {8,105}, ["BMYBU"]= {4,17}, ["WMOTR1"]= {4,78}, ["DNMYLC"]= {4,128}, ["WFYSTEW"]= {5,76},
  24. ["COPGRL3"]= {5,190}, ["VHMYCR"]= {18,184}, ["VWMYCR"]= {18,181}, ["SBMYCR"]= {18,143}, ["BMYBOUN"]= {4,163}, ["WMYDRUG"]= {18,29}, ["BMYCR"]= {18,21},
  25. ["WMYCONB"]= {4,153}, ["LVFD1"]= {17,278}, ["SFEMT1"]= {16,276}, ["SWMOTR1"]= {4,77}, ["VWMOTR1"]= {4,212}, ["LAEMT1"]= {16,274}, ["LVEMT1"]= {16,275},
  26. ["BFOST"]= {5,10}, ["SWMORI"]= {4,235}, ["VLA1"]= {14,114}, ["TRIBOSS"]= {13,120}, ["VWFYWAI"]= {5,214}, ["SBFOST"]= {5,218}, ["VMAFF4"]= {12,127},
  27. ["HMYRI"]= {4,46}, ["BMYCON"]= {4,260}, ["WMYPIZZ"]= {4,155}, ["SPECIAL05"]= {4,294}, ["WMOPREA"]= {4,68}, ["DNB3"]= {11,123}, ["WMYGOL2"]= {4,37},
  28. ["OMYRI"]= {4,59}, ["BMOTR1"]= {4,79}, ["DNB2"]= {11,122}, ["VHFYST3"]= {5,246}, ["SBMOCD"]= {4,220}, ["GANGRL3"]= {5,195}, ["SFR3"]= {10,175},
  29. ["SFR2"]= {10,174}, ["WMYRI"]= {4,98}, ["LSV1"]= {9,108}, ["FAM2"]= {8,106}, ["SBFORI"]= {5,215}, ["WFYJG"]= {5,90}, ["SWAT"]= {6,285},
  30. ["LAPDM1"]= {6,284}, ["LVPD1"]= {6,282}, ["SPECIAL07"]= {4,296}, ["WBDYG1"]= {4,24}, ["NURGRL3"]= {5,193}, ["LAPD1"]= {6,280}, ["SPECIAL08"]= {4,297},
  31. ["HMYST"]= {4,48}, ["SOMOBU"]= {4,227}, ["SWMYHP1"]= {4,72}, ["WMYCD1"]= {4,261}, ["VMAFF3"]= {12,126}, ["HECK2"]= {4,259}, ["BMOSEC"]= {4,253},
  32. ["BIKERA"]= {4,247}, ["SMYST2"]= {4,242}, ["OFYRI"]= {5,55}, ["SBMOST"]= {4,222}, ["SWMOTR4"]= {4,239}, ["WMYMECH"]= {4,50}, ["VLA2"]= {14,115},
  33. ["OMYST"]= {4,60}, ["SWMOTR5"]= {4,230}, ["HFYRI"]= {5,40}, ["SPECIAL04"]= {4,293}, ["SMYST"]= {4,241}, ["BALLAS1"]= {7,102}, ["SOMYRI"]= {4,186},
  34. ["CROGRL3"]= {5,194}, ["VBMOCD"]= {4,182}, ["HMYCR"]= {4,47}, ["BMYTATT"]= {4,180}, ["BMOBAR"]= {4,156}, ["WMYAMMO"]= {4,179}, ["WMYBAR"]= {4,177},
  35. ["BMYPOL1"]= {4,66}, ["BMYBAR"]= {4,176}, ["BMYRI"]= {4,20}, ["SOMYST"]= {4,170}, ["BMOCHIL"]= {4,168}, ["WFYRI"]= {5,91}, ["WMYBELL"]= {4,167},
  36. ["BMYST"]= {4,22}, ["WMYCR"]= {18,100}, ["WMYST"]= {4,101}, ["CWMYFR"]= {4,161}, ["CWMOHB2"]= {4,160}, ["CWMOFR"]= {4,158}, ["WMYBU"]= {4,147},
  37. ["SPECIAL06"]= {4,295}, ["CWMYHB1"]= {4,162}, ["WFYSEX"]= {5,178}, ["VBMYELV"]= {4,83}, ["CWFOHB"]= {5,197}, ["VBMYBOX"]= {4,80}, ["WMYMOUN"]= {4,52},
  38. ["SPECIAL01"]= {4,290}, ["WMYSGRD"]= {4,71}, ["OMOBOAT"]= {4,210}, ["SWMYHP2"]= {4,73}, ["WFYCRK"]= {5,145}, ["BFYRI"]= {5,12}, ["SOFYRI"]= {5,169},
  39. ["OMOKUNG"]= {4,49}, ["HMYCM"]= {4,146}, ["HMORI"]= {4,43}, ["HMOGAR"]= {4,35}, ["DWMYLC1"]= {4,34}, ["SFPD1"]= {6,281}, ["WMYBMX"]= {4,23},
  40. ["VBFYST2"]= {5,244}, ["SWFYST"]= {5,233},["CWFYFR2"]= {5,199}, ["VWFYCRP"]= {5,172}, ["WMOSCI"]= {4,70}}
  41. for k,v in pairs(list) do
  42. if m == k
  43. then t = v[1] -- тип педа
  44.      m1 =v[2] -- модель педа
  45. end end
  46. m = m1
  47. requestModel(m) -- запрос модели
  48. while not isModelAvailable(v) do wait(0) end-- проверка на загруженность модели
  49. ped = createChar(t, m, x,y,z) -- 009A: 2@ = create_actor_playerPedtype 4 model #MALE01 at 0.0 0.0 0.0
  50. return ped
  51. end
  52.  

это упрощало создания педов, вот lua плагин https://vk.com/gtabuilder?w=wall-56513456_510

очень помогли скриптовые команды.

Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июнь 18, 2019, 02:27:30 pm
Цитировать
Скажите, пожалуйста, у вас есть список типа для каждого педа
\GTA Vice City\data\default.ide раздел peds Default pedtype

в sdk есть enum ePedType
https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_vc/game_vc/ePedType.h (https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_vc/game_vc/ePedType.h)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июль 03, 2019, 03:34:34 pm
Здравствуйте, уважаемый kenking за Ваш ответ. Написал функции определения типов педа и оружие(конечно, буду дорабатывать).
Все хорошо с lua плагином, но есть одно но. Пытаюсь сделать функцию таймер.

Обычно таймер делается так.
Код: C++
  1.         static unsigned int time = 0;// обнулить таймер.
  2.         if (CTimer::m_snTimeInMilliseconds - time > 500) {
  3.                 time = 0; // обнулить таймер
  4.  
  5.  

Мне нужна именно функция таймер, например, передаешь 1000 мс, получаешь задержку в 1 сек, пробовал через рекурсии не выходит.
Код: C++
  1. CVector* worldcoord(CPed* ped, float x = 1.0, float y = 1.0) {
  2.                 CVector& pos1 = ped->m_placement.pos + ped->m_placement.right * x + ped->m_placement.up * y;
  3.                 CVector* pos = &pos1;
  4.                 return pos;
  5. };
  6. CPed* create(int modelID, CVector *pos) {// создать pedа
  7.         char reference = 2;// чтобы удалился потом.
  8.     CStreaming::RequestModel(modelID, 0); // ANGEL 166 ModelID
  9.         CStreaming::LoadAllRequestedModels(false);// модель загружена.
  10.         CPed* ped = new CCivilianPed(PEDTYPE_COP, modelID);
  11.  
  12.         ped->m_nState = 4;// флаг
  13.         //ped->m_placement.SetRotate(0, 0, 3.5f);// смещение от координат игрока
  14.         ped->m_placement.pos.x = pos->x;
  15.         ped->m_placement.pos.y = pos->y;
  16.         ped->m_placement.pos.z = pos->z;
  17.         CWorld::Add(ped);// добавить в мир педа.
  18.         return ped;
  19. }
  20.  
  21. int delay(unsigned int &time, int delaytime) {
  22.         if (CTimer::m_snTimeInMilliseconds - time > delaytime) {
  23.                 time = 0;// обнулить таймер
  24.                 CMessages::AddMessageJumpQ(L"Stop timer ", 5000, 3);//выводит сообщение на экран
  25.                 }
  26.         else {
  27.                 for (int i = 0; i < 10000; i++) {
  28.                         int a = 0;
  29.                 };
  30.                 delay(time, delaytime);
  31.         }
  32. };
  33.  
  34. class Message {//имя класса
  35. public:
  36.         Message() {
  37.                 Events::gameProcessEvent += [] {//обработчик событий игры
  38.                         CPed* player = FindPlayerPed();// найти игрока
  39.                         if (!player) return;// проверка найден игрок
  40.                         KeyCheck::Update();
  41.  
  42.                         if (KeyCheck::CheckWithDelay('N', 200)) {//если м нажата
  43.                                 static unsigned int time = 0;// обнулить таймер.
  44.                                 delay(time, 1000);
  45.                                 CVector* pos = worldcoord(player, 1.0, 10.0); //Нахождени координат на 10 от взгляда томми.
  46.                                 CPed* v = create(MODEL_COP, pos); // Спавним копа, передаем коор на 10 м вперед от томми.
  47.                                        
  48.                         }
  49.                 };
  50.         }
  51. } message;
  52.  

Чтобы в lua реализовать это.

Код: C++
  1. function Createped(m,x,y,z)
  2.  local list = { COP = {1,6}, SWAT = {2,6}, FBI = {3,6}, ARMY = {4,6}, MEDIC = {5,16}, FIREMAN = {6,17},
  3.              HFYST = {9,5}, HFOST = {10,5}, HMYST = {11,4}, HFOST = {12,4}, HFYRI = {13,5}, HFORI = {14,5},
  4.              HMYRI = {15,4},HMORI = {16,4},HFYBE = {17,5},HFOBE = {18,5},HMYBE = {19,4},HMOBE = {20,4},
  5.              HFYBU = {21,5},HFYMD = {22,5},HFYCG = {23,5},HFYPR = {24,5},HFOTR = {25,5},HMOTR = {26,4},
  6.              HMYAP = {27,4},HMOCA = {28,4},BMODK = {29,4},BMYCR = {30,4},BFYST = {31,5},BFOST = {32,5},
  7.              BMYST = {33,4},BMOST = {34,4},BFYRI = {35,5},BFORI = {36,5},BMYRI = {37,4},BFYBE = {38,5},
  8.              BMYBE = {39,4},BFOBE = {40,5},BMOBE = {41,4},BMYBU = {42,4},BFYPR = {43,5},BFOTR = {44,5},
  9.              BMOTR = {45,4},BMYPI = {46,4},BMYBB = {47,4},WMYCR = {48,4},WFYST = {49,5},WFOST = {50,5},
  10.              WMYST = {51,4},WMOST = {52,4},WFYRI = {53, 5},WFORI = {54, 5}, WMYRI = {55,4}, WMORI = {56,4 },
  11.              WFYBE = {57,5}, WMYBE = {58,4}, WFOBE = {59,5}, WMOBE = {60,4}, WMYCW = {61,4}, WMYGO = {62,4},
  12.              WFOGO = {63,5}, WMOGO = {64,4}, WFYLG = {65, 5}, WMYLG = {66, 4}, WFYBU = {67,5}, WMYBU = {68, 4},
  13.              WMOBU = {69,4}, WFYPR = {70,5}, WFOTR = {71,5}, WMOTR = {72,4}, WMYPI = {73,4}, WMOCA = {74, 4},
  14.              WFYJG = {75, 5}, WMYJG = {76,4}, WFYSK = {77,5}, WMYSK = {78,4}, WFYSH = {79,5}, WFOSH = {80,5 },
  15.              JFOTO = {81, 5}, JMOTO = {82, 4}, CBA = {83,7}, CBB = {84,7}, HNA = {85,8}, HNB = {86,8},
  16.              SGA = {87,9}, SGB = {88,9}, CLA = {89,10}, CLB ={90,10}, GDA = {91,11}, GDB = {92,11},
  17.              BKA = {93, 12}, BKB = {94,12}, PGA = {95,13}, PGB = {96,13}, VICE1 = {97,18}, VICE2 = {98,18},
  18.              VICE3 = {99,18}, VICE4 = {100,18}, VICE5 = {101,18}, VICE6 = {102,18}, VICE7 = {103,18},
  19.              VICE8 = {104,18},WFYG1 = {105,5}, WFYG2 = {106,6}}
  20.    for k,v in pairs(list) do
  21.         if m == k
  22.         then m1 = v[1] -- модель педа.
  23.             t1 =v[2] -- тип педа
  24.         end end
  25.     m = m1--модель.
  26.     t = t1-- тип.
  27.        
  28.  loadmodel(m)
  29. while not availablemodel(m) do  delay(100) end
  30. ped= createped(m,t, x,y,z)
  31. releasemodel(m)
  32. return ped
  33. end
  34.  

Вообще таймеров много, чем они отличаются? 
Код: C++
  1.     SUPPORTED_10EN_11EN_STEAM static int &m_snTimeInMillisecondsPauseMode;
  2.     SUPPORTED_10EN_11EN_STEAM static int &m_snTimeInMilliseconds;
  3.     SUPPORTED_10EN_11EN_STEAM static float &ms_fTimeStepNonClipped;
  4.     SUPPORTED_10EN_11EN_STEAM static float &ms_fTimeStep;
  5.     SUPPORTED_10EN_11EN_STEAM static int &m_snPreviousTimeInMilliseconds;
  6.     SUPPORTED_10EN_11EN_STEAM static float &ms_fTimeScale;
  7.     SUPPORTED_10EN_11EN_STEAM static int &m_snTimeInMillisecondsNonClipped;
  8.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 04, 2019, 01:17:35 pm
Цитировать
Вообще таймеров много, чем они отличаются?
Надо смотреть каждую из этих переменных в базе, в каких функциях используются, тогда можно понять чем они отличаются и для чего используются.

Цитировать
Мне нужна именно функция таймер, например, передаешь 1000 мс, получаешь задержку в 1 сек, пробовал через рекурсии не выходит.
Задержку по времени между выполнением действий в теме была показана ранее на примере нажатия клавиши. Вот такой пример. Загрузка модели и создание педа вынесены в отдельные функции.
Код: C++
  1. #include "plugin.h"
  2. #include "CMessages.h"
  3. #include "CWorld.h"
  4. #include "CStreaming.h"
  5. #include "CTimer.h"
  6. #include "ePedModel.h"
  7. #include "ePedType.h"
  8. #include "CCivilianPed.h"
  9.  
  10. using namespace plugin;
  11.  
  12. class Test {
  13. public:
  14.     static bool LoadModel(int model) {
  15.         unsigned char oldFlags = CStreaming::ms_aInfoForModel[model].m_nFlags;
  16.         CStreaming::RequestModel(model, GAME_REQUIRED);
  17.         CStreaming::LoadAllRequestedModels(false);
  18.         if (CStreaming::ms_aInfoForModel[model].m_nLoadState == LOADSTATE_LOADED) {
  19.             if (!(oldFlags & GAME_REQUIRED)) {
  20.                 CStreaming::SetModelIsDeletable(model);
  21.                 CStreaming::SetModelTxdIsDeletable(model);
  22.             }
  23.             return true;
  24.         }
  25.         return false;
  26.     }
  27.  
  28.     static CPed *CreatePed(ePedType pedType, unsigned int modelIndex) {
  29.         CPed *ped = nullptr;
  30.         if (LoadModel(modelIndex)) {
  31.             ped = new CCivilianPed(pedType, modelIndex);
  32.             if (ped) {
  33.                 ped->SetPosition(FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 2.0f, 0.0f)));
  34.                 CWorld::Add(ped);
  35.             }
  36.         }
  37.         return ped;
  38.     }
  39.  
  40.     Test() {
  41.         static int keyPressTime = 0;
  42.  
  43.         Events::gameProcessEvent += [] {
  44.             CPed *player = FindPlayerPed();
  45.             if (player) {
  46.                 if (KeyPressed('M') && CTimer::m_snTimeInMilliseconds > (keyPressTime + 5000)) {
  47.                     keyPressTime = CTimer::m_snTimeInMilliseconds;
  48.                     CPed *ped = CreatePed(PEDTYPE_CIVFEMALE, MODEL_HFYST);
  49.                     if (ped)
  50.                         CMessages::AddMessageJumpQ(L"CreatePed", 1000, 0);;
  51.                 }
  52.             }
  53.         };
  54.     }
  55. } test;

Как я уже писал ранее, по работе с lua ничего подсказать не могу.
Зачем ты смешиваешь код lua и плагин? Что такого можно сделать в lua, чего нельзя сделать в плагине? Хотя в lua я не разбираюсь, может чего и можно.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июль 08, 2019, 11:36:51 pm
Здравствуйте, уважаемый kenking, Спасибо вам большое, что уделили мне время.
 классный код, Вы четко и грамотно пиши код, Вы очень помогли. реализовал выдачу оружие педу

 У меня получилось сделать, чтобы клавиша срабатывала один раз, нажал, отпустил- действие, это помогает избежать залипание клавиш.
Код: Text
  1. //Нажать на клавишу один раз.
  2.  
  3. bool wait(unsigned int key) {
  4.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  5.         else { return false; }
  6. }
  7.  
  8. class Message {//имя класса
  9. public:
  10.         Message() {
  11.                 Events::gameProcessEvent += [] {//обработчик событий игры
  12.                         CPed* player = FindPlayerPed();// найти игрока
  13.                         if (!player) return;// проверка найден игрок
  14.                         KeyCheck::Update();
  15.                         if (KeyCheck::CheckWithDelay('N', 200)) {//если N нажата
  16.                                 if (wait('N')) return; {//если м нажата
  17.                                 CMessages::AddMessageJumpQ(L"message", 2000, false);
  18.                                 }
  19.                         }
  20.                 };
  21.         }
  22. } message;
  23.  
  24.  

потом решил создать сферу и удалить ее, но тут встретился интересный нюанс, когда сферу создаешь первый раз, она через секунду удаляется. второй раз создается и удаляется, как было задумано. это какой-то глюк. Специально записал на видео этот глюк автоматическое
удаление сферы при первом ее создании. https://www.youtube.com/watch?v=BAoS1yaKakk&feature=youtu.be (https://www.youtube.com/watch?v=BAoS1yaKakk&feature=youtu.be)
может я что-то не так делаю?
Код: Text
  1. class Sphere1 {//имя класса
  2. public:
  3.         Sphere1() {
  4.                 static  int sphere;
  5.                 Events::gameProcessEvent += [] {//обработчик событий игры
  6.                         KeyCheck::Update();
  7.                         CPed* player = FindPlayerPed();// найти игрока
  8.                         if (!player) return; {
  9.                                 if (KeyCheck::CheckWithDelay('B', 1900)) {// проверка найден игрок
  10.                                         CMessages::AddMessageJumpQ(L"Create", 2000, 1);//выводит сообщение на экран
  11.                                         CVector* pos = worldcoord(player, 1.0, 10.0); //Нахождения координат на 10 от взгляда томми.
  12.                                         Command<COMMAND_ADD_SPHERE>(pos->x, pos->y, pos->z, 2.0, &sphere);
  13.                                 }
  14.                                 if (KeyCheck::CheckWithDelay('N', 1900)) { // (KeyCheck::CheckWithDelay('B', 200)) //если м нажата
  15.                                         CMessages::AddMessageJumpQ(L"delete", 2000, 1);  //выводит сообщение на экран.  
  16.                                         Command<COMMAND_REMOVE_SPHERE>(sphere);// удалить сферу.  
  17.                                 }
  18.                         }
  19.                 };
  20.         }
  21. } sphere1;
  22.  

Стараюсь разобраться со скриптовой командой, проверкой на нахождения в заданных координатах, вроде передаю параметры правильно.
Код: Text
  1. Создать маркер сферу и проверка на координаты.
  2.  
  3. class Message {//имя класса
  4. public:
  5.         Message() {
  6.  Events::gameProcessEvent += [] {//обработчик событий игры
  7. CVector* pos;
  8. static  int sphere;
  9.          KeyCheck::Update();
  10.          CPed* player = FindPlayerPed();// найти игрока
  11.          if (!player) return; {
  12.                  if (KeyCheck::CheckWithDelay('B', 1900)) {// проверка найден игрок
  13.                          CMessages::AddMessageJumpQ(L"Create", 2000, 1);//выводит сообщение на экран
  14.                          pos = worldcoord(player, 1.0, 10.0); //Нахождения координат на 10 от взгляда томми.
  15.                          Command<COMMAND_ADD_SPHERE>(pos->x, pos->y, pos->z, 2.0, &sphere);    
  16.                          //double x = pos->x;
  17.                          //double z = pos->y;
  18.                          //double z = pos->z;
  19.                  }
  20.          if (Command<COMMAND_LOCATE_PLAYER_ANY_MEANS_3D>(CWorld::PlayerInFocus, true, pos->x, pos->y, pos->z, 2.0, 2.0, 2.0))
  21.          { CMessages::AddMessageJumpQ(L"delete", 2000, 1); }     //выводит сообщение на экран.  
  22.           }
  23.          };
  24.   }
  25. } message;             
  26.  
  27.  
  28.  


У нас есть много условно говоря функций(методов разных классов), с++ можно использовать как библиотеку классов и  функций, а lua их выполняет, то есть их реализовывает.
вот действия скрипта.
по нажатию клавиши “G”, создать пед, который побежит к девушке на маркере, клавишей “K” откроет огонь по ней.
видео   https://www.youtube.com/watch?v=0eIs4lqNRxI&feature=youtu.be (https://www.youtube.com/watch?v=0eIs4lqNRxI&feature=youtu.be)
теперь код, он прост.
Код: Text
  1. require("lualoader/mod")
  2. --model = VICE8
  3. function main()
  4. while lualoader == nil do
  5.  wait()
  6.  player = findplayer()-- получить игрока
  7.  if Keypress(VK_G)
  8.  then     x,y,z = getworldcoordped(player,1.0,4)-- получить координаты на 4 м впереди от томми.
  9.  man = Createped("BMODK",x,y,z)-- создать педа(убийцу).
  10.  Giveweaponped(man,m4,100)-- дать педу оружие.
  11.  mar = create_marker_actor(man) -- создать маркер педа.
  12.  x,y,z = getworldcoordped(man,0.1,30)-- получить координаты на 30 м впереди от педа.
  13.  woman = Createped("HFYPR",x,y,z)-- создать педа(жертву).
  14.   sp = create_sphere(x,y,z, 1.5)-- создать сферу, последний параметр радиус.
  15.   x,y,z = getworldcoordped(woman,0.1,-4)-- получить координаты на 4 м сзади от жертвы.
  16.  ped_sprint_to_point(man, x,y,z)-- в эту точку делает спринт убийца.
  17.  wait(3000)-- задержка.
  18.  ped_aim_at_ped(man, woman)-- пед целиться в педа.
  19. --printmessage("created by the killer and victim", 2500, 3)
  20. end
  21.  if Keypress(VK_K)
  22.  then Kill_ped_on_foot(man, woman)-- пед хочет убить другого педа.
  23. removemarker(mar)-- удалить маркер над педом.
  24. remove_sphere(sp) -- удалить сферу.
  25.  end
  26. end
  27. end
  28.  

видите легко реализовать свои задумки на lua.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 09, 2019, 08:27:14 am
Код: C++
  1. #include "plugin.h"
  2. #include "CMessages.h"
  3. #include "CWorld.h"
  4. #include "extensions\ScriptCommands.h"
  5. #include "eScriptCommands.h"
  6. #include "extensions\KeyCheck.h"
  7.  
  8. using namespace plugin;
  9.  
  10. class Test {
  11. public:
  12.     Test() {
  13.  
  14.         Events::gameProcessEvent += [] {
  15.             CPed *player = FindPlayerPed();
  16.             if (player) {
  17.                 CVector point = { 241.6f, -1283.0f, 10.9f };
  18.                 if (Command<COMMAND_LOCATE_PLAYER_ANY_MEANS_3D>(CWorld::PlayerInFocus, point.x, point.y, point.z, 2.0, 2.0, 2.0))
  19.                     CMessages::AddMessageJumpQ(L"Yes", 1000, 1);
  20.                 //
  21.                 static int sphere;
  22.                 KeyCheck::Update();
  23.                 if (KeyCheck::CheckWithDelay('M', 2000)) {
  24.                     CVector pos = FindPlayerPed()->TransformFromObjectSpace(CVector(0.0f, 5.0f, 0.0f));
  25.                     Command<COMMAND_ADD_SPHERE>(pos.x, pos.y, pos.z, 2.0, &sphere);
  26.                     CMessages::AddMessageJumpQ(L"Create", 2000, 1);
  27.                 }
  28.                 if (KeyCheck::CheckWithDelay('N', 2000)) {
  29.                     Command<COMMAND_REMOVE_SPHERE>(sphere);
  30.                     CMessages::AddMessageJumpQ(L"Delete", 2000, 1);
  31.                 }
  32.             }
  33.         };
  34.     }
  35. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Июль 26, 2019, 07:42:58 pm
спасибо большое за Ваш ответ уважаемый kenking. много работал над многопоточности, удалось ее реализовать через костыл.
потому не lanes и effil не удалось собрать. все работает.
По нажатию клавиши “G” запускается функция
newthread(funs,"BMYBB","remove ped")
первый параметр, названия функцией запущенной в отдельном потоке, модель педа, текст надписи на экране.
Вот сама функция.
Код: C++
  1. require("lualoader/mod")
  2. function funs(ped, text)
  3.  player = findplayer()-- получить игрока
  4.  x,y,z =getcoordinates_on_y(player,5)-- получить координаты на 5 м впереди.
  5.  man = Createped(ped,x,y,z) -- создать педа.
  6.  mar = create_marker_actor(man) -- создать маркер педа.
  7. while true do
  8.  if 0 == gethealth(man)-- проверить его здоровье.
  9.  then  
  10.  printmessage(text, 1500,1)
  11.  remove_ped(man)-- удалить педа.
  12.  removemarker(mar)-- удалить маркер над педом.
  13.  break
  14.  end
  15. end
  16. end
  17. function main()
  18. while lualoader == nil do
  19.  wait()
  20.  player = findplayer()-- получить игрока
  21.  if Keypress(VK_G)
  22.  then
  23.  newthread(funs,"BMYBB","remove ped")-- функция, модель пед, текст надписи.
  24.  end
  25.  
  26.  end  
  27.  end
  28.  

теперь есть желание написать простую миссию, пытаюсь понять как получить и установить флаг миссии.
пробовал вот так не получается.
Код: C++
  1.                 if (KeyCheck::CheckWithDelay('M', 1000)) {
  2.                                 //      Command<COMMAND_DECLARE_MISSION_FLAG>(true);
  3.                                         if(Command <COMMAND_CAN_PLAYER_START_MISSION>(CWorld::PlayerInFocus)){
  4.                                         //CRunningScript script;
  5.                                     //if(script.m_bIsMission) {
  6.                                                 CMessages::AddMessageJumpQ(L"on", 2000, 1);}
  7.  
  8.                                         else {  CMessages::AddMessageJumpQ(L"mission", 2000, 1);
  9.                                         }
  10.        
  11.                                 }
  12.  

помогите, пожалуйста, Ваши советом, как проверить флаг миссии? И установить его, что миссия запущена.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Июль 27, 2019, 10:41:56 am
Флаг миссии устанавливается так:
Код: C++
  1. CTheScripts::ScriptSpace[CTheScripts::OnAMissionFlag] = 1
Переменная CTheScripts::OnAMissionFlag для VC в sdk пока не добавлена
Пока можно так:
Код: C++
  1. #include "plugin.h"
  2. #include "CTheScripts.h"
  3. #include "extensions\KeyCheck.h"
  4.  
  5. unsigned int &OnAMissionFlag = *(unsigned int *)0x978748;
  6.  
  7. using namespace plugin;
  8.  
  9. class Test {
  10. public:
  11.     Test() {
  12.         Events::drawingEvent += [] {
  13.             gamefont::Print({
  14.                 Format("OnAMissionFlag = %d", CTheScripts::ScriptSpace[OnAMissionFlag])
  15.             }, 10, 200, 1, FONT_DEFAULT, 0.75f, 0.75f, color::Orange);
  16.            
  17.             CPed *player = FindPlayerPed();
  18.             if (player) {
  19.                 KeyCheck::Update();
  20.                 if (KeyCheck::CheckWithDelay('M', 1000)) {
  21.                     if (CTheScripts::ScriptSpace[OnAMissionFlag])
  22.                         CTheScripts::ScriptSpace[OnAMissionFlag] = 0;
  23.                     else
  24.                         CTheScripts::ScriptSpace[OnAMissionFlag] = 1;
  25.                 }
  26.             }
  27.         };
  28.     }
  29. } test;
Цитировать
как проверить флаг миссии? И установить его, что миссия запущена.
Перед запуском своей миссии проверяешь значение CTheScripts::ScriptSpace[OnAMissionFlag], если оно равно 0, никакая миссия в данным момент не запущена. Запускаешь свою миссию, устанавливаешь значение CTheScripts::ScriptSpace[OnAMissionFlag] в 1. Миссия запущена. Когда миссия заканчивается, ставишь CTheScripts::ScriptSpace[OnAMissionFlag] в 0.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Август 01, 2019, 08:45:47 am
спасибо Вам большое уважаемый kenking. Что Вы помогли мне разобраться с флагами миссий. их добавил в lua.  Смог написать первую  простую миссию  https://www.youtube.com/watch?v=z6BFxEsu4W4 (https://www.youtube.com/watch?v=z6BFxEsu4W4) https://vk.com/gtabuilder?w=wall-56513456_515 (https://vk.com/gtabuilder?w=wall-56513456_515)

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

Код: C++
  1. :left_front_door
  2. 05E7: 10@ = car 10@ struct
  3. 0085: 11@ = 10@
  4. 05E4: call_function_method 6@ struct 11@ num_params 1 pop 0 0@ {1..19} 2@ // IsComponentPresent
  5. if
  6. 2@ == 1
  7. then
  8. 0085: 3@ = 10@
  9. 3@ += 0x2A0 // CDamageManager
  10. 05E4: call_function_method 7@ struct 3@ num_params 1 pop 0 1@ {0..5} 4@ // GetComponnetStatus
  11. if
  12. 4@ <> 3
  13. then
  14. for 12@ = 0.0 TO 1.0 step 0.1
  15. 05E3: call_function_method 9@ struct 10@ num_params 3 pop 0 12@ 1@ 0@ {1..19} // CAutomobile__OpenDoor ???
  16. wait 0
  17. end
  18. 05E3: call_function_method 9@ struct 10@ num_params 3 pop 0 12@ 1@ 0@ {1..19} // CAutomobile__OpenDoor ???
  19. end
  20. end
  21. return
  22.  

там было очень много тонкостей, транспорт должен быть авто и не гольф машиной. некоторые машины были двух дверными, при попытке открыть заднюю левую дверь, был вылет, также двери могло и быть.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 01, 2019, 12:10:13 pm
Цитировать
Скажите, пожалуйста, с помощью какой функции можно открыть двери и капот, багажник.
1) Скрипт вот https://gta.com.ua/file_details.phtml?id=2832 (https://gta.com.ua/file_details.phtml?id=2832)
2) В этой теме DK показывал код такого плагина для SA. Я переписал для VC https://github.com/kenkingGitHub/GTA-Projects/blob/master/VC_OpenComponent/VC_OpenComponent.cpp (https://github.com/kenkingGitHub/GTA-Projects/blob/master/VC_OpenComponent/VC_OpenComponent.cpp)
(там только под более раннюю версию sdk, #include надо заменить)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Август 13, 2019, 11:21:00 am
Здравствуйте,  уважаемый kenking. Спасибо за ссылки.  Компоненты авто( капот,  багажник, двери) работаю.  Думаю, как это встроит в lua.
 Только в одной строке  выдает ошибку, ее пришлось закомментировать
Код: C++
  1.  
  2.                 //if (automobile->stDamage.GetDoorStatus(doorId) != DAMSTATE_NOTPRESENT) {
  3.                                 DoorEvent& event = VehDoors.Get(automobile).events[doorId];
  4.                                 if (event.m_type == DOOR_EVENT_OPEN)
  5.                                         event.m_type = DOOR_EVENT_CLOSE; // Если последнее событие - открытие, то закрываем
  6.                                 else
  7.                                         event.m_type = DOOR_EVENT_OPEN; // Если последнее событие закрытие - то открываем
  8.                                 event.m_active = true; // Включаем обработку
  9.                                 m_nLastTimeWhenAnyActionWasEnabled = CTimer::m_snTimeInMilliseconds;
  10.                         //}
  11.  

хотя функция есть  // Converted from thiscall uint CDamageManager::GetDoorStatus(eDoors door) 0x5A9810
unsigned int CDamageManager::GetDoorStatus(eDoors door) {
    return plugin::CallMethodAndReturn<unsigned int, 0x5A9810, CDamageManager *, eDoors>(this, door);
} здесь https://github.com/DK22Pac/plugin-sdk/blob/b4b8841561d4d8742b0e15a16d5096e1b56b31c2/plugin_vc/game_vc/CDamageManager.cpp

Может ее неправильно подключил. заново собрал sdk, обновил. он прогрессирует.

добавил в свой lua плагин пару новых функций, благодаря SDK Plugin.


Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Август 18, 2019, 11:49:01 am
Здравствуйте, всем. Удалось реализовать  открытия дверей автомобиля в lualoader. только у авто модели MODEL_ENFORCER капот открывается в обратную сторону MODEL_ENFORCER https://www.youtube.com/watch?v=Lb5UNBe_QtQ&t=2s (https://www.youtube.com/watch?v=Lb5UNBe_QtQ&t=2s) ,https://vk.com/gtabuilder?w=wall-56513456_517

может я допустил ошибку в коде, на других авто капот открывается нормально.

 
Код: Text
  1. const float ACTION_TIME_STEP = 0.05f;
  2. const unsigned int TIME_FOR_KEYPRESS = 500;
  3. struct Doorse {
  4.         static int componentByDoorId[6]; // Таблица перевода eDoors в Id компонента
  5.         static int m_nLastTimeWhenAnyActionWasEnabled; // Последнее время запуска события
  6.         enum eDoorEventType { // Тип события
  7.                 DOOR_EVENT_OPEN, DOOR_EVENT_CLOSE
  8.         };
  9.  
  10.         struct DoorEvent { // Класс события
  11.                 bool m_active;  eDoorEventType m_type;  float m_openingState;
  12.  
  13.                 DoorEvent() { m_active = false; m_type = DOOR_EVENT_CLOSE; }
  14.         };
  15.  
  16.         struct VehicleDoors {
  17.                 DoorEvent events[6]; // События для всех 6 дверей
  18.                 VehicleDoors(CVehicle*) {}
  19.         };
  20. };
  21. struct DoorsExample {
  22.         static int componentByDoorId[6]; // Таблица перевода eDoors в Id компонента
  23.         static int m_nLastTimeWhenAnyActionWasEnabled; // Последнее время запуска события
  24.  
  25.         enum eDoorEventType { // Тип события
  26.                 DOOR_EVENT_OPEN, DOOR_EVENT_CLOSE
  27.         };
  28.  
  29.         struct DoorEvent { // Класс события
  30.                 bool m_active;  eDoorEventType m_type;  float m_openingState;
  31.                 DoorEvent() { m_active = false; m_type = DOOR_EVENT_CLOSE; }
  32.         };
  33.  
  34.         struct VehicleDoors {
  35.                 DoorEvent events[6]; // События для всех 6 дверей
  36.                 VehicleDoors(CVehicle*) {}
  37.         };
  38.  
  39.         static VehicleExtendedData<VehicleDoors> VehDoors; // Наше расширение
  40.  
  41.         static void EnableDoorEvent(CAutomobile* automobile, eDoors doorId) { // Включить событие двери
  42.                 if (automobile->IsComponentPresent(componentByDoorId[doorId])) {
  43.                         CDamageManager* p;
  44.                         if (p->GetDoorStatus(doorId) != DAMSTATE_NOTPRESENT) {
  45.                                 DoorEvent& event = VehDoors.Get(automobile).events[doorId];
  46.                                 if (event.m_type == DOOR_EVENT_OPEN)
  47.                                         event.m_type = DOOR_EVENT_CLOSE; // Если последнее событие - открытие, то закрываем
  48.                                 else
  49.                                         event.m_type = DOOR_EVENT_OPEN; // Если последнее событие закрытие - то открываем
  50.                                 event.m_active = true; // Включаем обработку
  51.                                 m_nLastTimeWhenAnyActionWasEnabled = CTimer::m_snTimeInMilliseconds;
  52.                         }
  53.                 }
  54.         };
  55.  
  56.         static void ProcessDoors(CVehicle* vehicle) { // Обработка событий для конкретного авто
  57.                 if (vehicle->m_nVehicleClass == VEHICLE_AUTOMOBILE) {
  58.                         CAutomobile* automobile = reinterpret_cast<CAutomobile*>(vehicle);
  59.                         for (unsigned int i = 0; i < 6; i++) { // Обрабатываем все события
  60.                                 eDoors doorId = static_cast<eDoors>(i);
  61.                                 DoorEvent& event = VehDoors.Get(automobile).events[doorId];
  62.                                 if (event.m_active) { // Если событие активно
  63.                                         if (event.m_type == DOOR_EVENT_OPEN) {
  64.                                                 event.m_openingState += ACTION_TIME_STEP;
  65.                                                 if (event.m_openingState > 1.0f) { // Если полностью открыли
  66.                                                         event.m_active = false; // Отключаем обработку
  67.                                                         automobile->OpenDoor(componentByDoorId[doorId], doorId, 1.0f); // Полностью открываем
  68.                                                         event.m_openingState = 1.0f;
  69.                                                 }
  70.                                                 else
  71.                                                         automobile->OpenDoor(componentByDoorId[doorId], doorId, event.m_openingState);
  72.                                         }
  73.                                         else {
  74.                                                 event.m_openingState -= ACTION_TIME_STEP;
  75.                                                 if (event.m_openingState < 0.0f) { // Если полностью открыли
  76.                                                         event.m_active = false; // Отключаем обработку
  77.                                                         automobile->OpenDoor(componentByDoorId[doorId], doorId, 0.0f); // Полностью открываем
  78.                                                         event.m_openingState = 0.0f;
  79.                                                 }
  80.                                                 else
  81.                                                         automobile->OpenDoor(componentByDoorId[doorId], doorId, event.m_openingState);
  82.                                         }
  83.                                 }
  84.                         }
  85.                 }
  86.         };
  87. };
  88. int DoorsExample::componentByDoorId[6] = { CAR_BONNET, CAR_BOOT, CAR_DOOR_LF, CAR_DOOR_RF, CAR_DOOR_LR, CAR_DOOR_RR };
  89. int DoorsExample::m_nLastTimeWhenAnyActionWasEnabled = 0;
  90. VehicleExtendedData<DoorsExample::VehicleDoors> DoorsExample::VehDoors;
  91. class Message {//имя класса
  92. public: Message() {
  93.         Events::gameProcessEvent += [] {//обработчик событий игры
  94.                 Events::vehicleRenderEvent += DoorsExample::ProcessDoors; // Тут обрабатываем события, а также выключаем их
  95.                 CPed* player = FindPlayerPed();// найти игрока.
  96.                 if (!player) return;// проверка найден игрок
  97.                 static unsigned int time = 0;// обнулить таймер
  98.  
  99.                 if (reload == false) {
  100.                         if (CTimer::m_snTimeInMilliseconds - time > 500) {
  101.                                 this_thread::sleep_for(chrono::milliseconds(600));// задержка
  102.                                 time = 0;// обнулить таймер
  103.                                 reload = true;// флаг, что уже запущен поток.
  104.                         }
  105.                         thread th(second, std::ref(reload)); th.detach();// независимый поток.        
  106.                 };
  107.  
  108.         };
  109. }
  110. } message;
  111. int opendoorcar(lua_State* L) { // открыть дверь авто.
  112.         try {
  113.                 if (LUA_TUSERDATA == lua_type(L, -2) && LUA_TNUMBER == lua_type(L, -1)) {// указатель на авто.
  114.                         CVehicle* b = (CVehicle*)Userdata::get<CVehicle>(L, 1, false);// получить указатель на авто.
  115.                         CAutomobile* automobile = reinterpret_cast<CAutomobile*>(b); // опять же, приведение типов. Т.к. мы будет юзать damageManager, нам нужно убедиться, что транспорт - это автомобиль (CAutomobile)
  116.                        
  117.                         int door = Stack<int>::get(L, 2);
  118.                         switch (door)           {
  119.                         case 0: {DoorsExample::EnableDoorEvent(automobile, BONNET); // 0 капот
  120.                                 break;   }
  121.                         case 1: {DoorsExample::EnableDoorEvent(automobile, BOOT); // 1 багажник
  122.                                 break;   }
  123.                 case 2:  { DoorsExample::EnableDoorEvent(automobile, DOOR_FRONT_LEFT); // 2 левая передняя дверь
  124.                         break;   }
  125.                 case 3: {DoorsExample::EnableDoorEvent(automobile, DOOR_FRONT_RIGHT); // 3 правая передняя дверь
  126.                         break;   }
  127.                 case 4: {DoorsExample::EnableDoorEvent(automobile, DOOR_REAR_LEFT); // 4 левая задняя дверь
  128.                         break;   }
  129.                         case 5: {DoorsExample::EnableDoorEvent(automobile, DOOR_REAR_RIGHT); // 5 правая задняя дверь
  130.                         break; }
  131.                  default:{}
  132.                         }
  133.                         return 0;
  134.                 }
  135.                 else { throw "bad argument in function opendoorcar option of the vehicle"; }
  136.         }
  137.         catch (const char* x) { writelog(x); }
  138.         return 0;
  139. };
  140.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 18, 2019, 03:08:20 pm
Цитировать
только у авто модели MODEL_ENFORCER капот открывается в обратную сторону MODEL_ENFORCER
На модели влаг выставлен неверно. В файле handling.cfg найди строчку ENFORCER и замени 3 цифру с конца 27 на 23
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Август 28, 2019, 02:35:05 pm
Kenking может можно обойти этот баг, без внесение изменений в файл.

Добавил несколько функций в lualoader.
У нас есть скриптовая функция ((Command<COMMAND_HAS_PICKUP_BEEN_COLLECTED>(s))), которая возвращает булевое значение подобран ли пикап? как-то работает некорректно. Может что-то напутал

Код: Text
  1.                                         CVector pos = player->m_placement.pos;
  2.                                         pos += player->m_placement.up * 10;
  3.                                         Command<COMMAND_REQUEST_MODEL>(335);
  4.                         Command<COMMAND_LOAD_ALL_MODELS_NOW>(false);
  5.                                 if (Command<COMMAND_HAS_MODEL_LOADED>(335)) {
  6.                                         Command<COMMAND_CREATE_PICKUP>(335, 3, pos.x, pos.y, pos.z, &s);
  7.                                         }
  8.  
  9.                                 }
  10.                         }      
  11.                         if (Command<COMMAND_HAS_PICKUP_BEEN_COLLECTED>(s)) {
  12.                                 CMessages::AddMessageJumpQ(L"message", 2000, false);
  13.                         }
  14.                 };
  15.  

Пытался написать гоночный чекпойнт, есть идея написать миссию гонку, вспомнил опкод 024F: create_corona_with_radius 2.0 type 9 lensflares 0 with_color 0 255 0 at 2490.4514 -1674.7673 13.3359. все равно нужно потом удалить чекпойнт.
Код: Text
  1. Command<COMMAND_DRAW_CORONA>(5.5, 6, 0, 0, 255, 0, pos.x, pos.y, pos.z);
  2.  

Так думаю как воспроизвести звуковой файл. На cleo было так
Код: Text
  1. wait 0  
  2. 03CF: load_wav 'FIN_1a' as 1
  3. wait 0
  4. if 03D0:  wav 1 loaded
  5. jf @sound
  6. 03D1: play_wav 1
  7. :intro5
  8. wait 0
  9. if 03D2:  wav 1 ended
  10. jf @Intro5
  11. 040D: unload_wav 1  
  12.  

Думал на sdk можно так? Подскажите, пожалуйста.
Код: Text
  1.                 Command<COMMAND_LOAD_MISSION_AUDIO>(152, &s);// = 0x3CF,
  2.                                         if (Command<COMMAND_HAS_MISSION_AUDIO_LOADED>(s)){;// = 0x3D0,
  3.                                         Command<COMMAND_PLAY_MISSION_AUDIO>(s);// = 0x3D1,
  4.                                         if (Command<COMMAND_HAS_MISSION_AUDIO_FINISHED>(s)) {// = 0x3D2,
  5.                                                 Command<COMMAND_CLEAR_MISSION_AUDIO>(s);//      040D: unload_wav 1
  6.                
  7.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Август 28, 2019, 06:58:25 pm
Цитировать
может можно обойти этот баг, без внесение изменений в файл.
Это просто ошибка разработчиков. Без исправления этого флага не обойдёшься. В чём проблема заменить одну цифру?

Цитировать
которая возвращает булевое значение подобран ли пикап? как-то работает некорректно. Может что-то напутал
С пикапами я не работал. Посмотрел в main, эта проверка вроде для другого пикапа, созданного опкодом 0517

Цитировать
Пытался написать гоночный чекпойнт, есть идея написать миссию гонку
Думаю, что это тоже надо смотреть в main.

Цитировать
как воспроизвести звуковой файл
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\ScriptCommands.h"
  3. #include "eScriptCommands.h"
  4. #include "extensions\KeyCheck.h"
  5.  
  6. using namespace plugin;
  7.  
  8. class Test {
  9. public:
  10.     enum eAudioState { STATE_LOAD, STATE_PLAY, STATE_CLEAR };
  11.     static eAudioState m_currentState;
  12.    
  13.     Test() {
  14.         Events::gameProcessEvent += [] {
  15.             switch (m_currentState) {
  16.             case STATE_LOAD:
  17.                 KeyCheck::Update();
  18.                 if (KeyCheck::CheckWithDelay('M', 2000)) {
  19.                     Command<COMMAND_LOAD_MISSION_AUDIO>(1, "FIN_1a");
  20.                     m_currentState = STATE_PLAY;
  21.                 }
  22.                 break;
  23.             case STATE_PLAY:
  24.                 if (Command<COMMAND_HAS_MISSION_AUDIO_LOADED>(1)) {
  25.                     Command<COMMAND_PLAY_MISSION_AUDIO>(1);
  26.                     m_currentState = STATE_CLEAR;
  27.                 }
  28.                 break;
  29.             case STATE_CLEAR:
  30.                 if (Command<COMMAND_HAS_MISSION_AUDIO_FINISHED>(1)) {
  31.                     Command<COMMAND_CLEAR_MISSION_AUDIO>(1);
  32.                     m_currentState = STATE_LOAD;
  33.                 }
  34.                 break;
  35.             }
  36.         };
  37.     }
  38. } test;
  39.  
  40. Test::eAudioState Test::m_currentState = STATE_LOAD;


Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Сентябрь 06, 2019, 11:00:42 am
Спасибо за Ваш ответ  kenking. Вряд ли кто-то будет менять флаг в файле при использовании плагина. возможно, есть способ обойти его.

Благодарю Вас, что показали как воспроизводить реплики, добавил в lua.
Буду с пикапом и гоночными чекпойнтами  разобраться, ох, трудностей всегда хватает.


Потоки работают, но есть сильное ограничение, нельзя передать указатели на педа, авто и объект. Дело в том, что у запуска функции в новом потоке есть очень сильное ограничение. Мы не можем передать указатели, потому что между состояниями нельзя передавать объекты, которые занимают память. Я думал, как это ограничение обойти? Решил, указатель преобразовать в строку, передать в новый поток, потом эту строку передать в функцию, которая обратно конвертирует строку в числовой указатель и ищет её в пуле. Но, опять произошла проблема, адреса в пуле являются не разыминованные, в отличие от числового указателя. Поэтому поиск никогда не даёт результатов. Буду очень рад, если Вы подскажите как решить эту проблему.

Код: Text
  1.  
  2.                         string str  = lua_tostring(L, -1);
  3. for (auto ped : CPools::ms_pPedPool) {
  4.                                         int p = (int)ped;
  5.                                         std::string sped = to_string(p);
  6.                                         if (str == sped) {
  7.                                                 Stack<bool>::push(L, true); Stack<CPed*>::push(L, ped);// отправить в стек и получить из стека можно
  8.                                                 return 2;
  9.                                         }
  10.                                 }
  11.  
Решил вывести указатели в файл.
Передаем в функцию 10EA92A8

В пуле такие адреса.

Код: Text
  1. 0C47DE08
  2. 0C47EBB8
  3. 0C47F290
  4. 0C47F968
  5. 0C480040
  6. 0C480718
  7.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Сентябрь 07, 2019, 11:30:03 am
Цитировать
Вряд ли кто-то будет менять флаг в файле при использовании плагина. возможно, есть способ обойти его.
Никто не играет со стандартными моделями давно. А в заменяемых моделях авторы указывают свои настройки, где это исправлено.   

Цитировать
Потоки работают, но есть сильное ограничение, нельзя передать указатели на педа, авто и объект. Дело в том, что у запуска функции в новом потоке есть очень сильное ограничение. Мы не можем передать указатели, потому что между состояниями нельзя передавать объекты, которые занимают память. Я думал, как это ограничение обойти? Решил, указатель преобразовать в строку, передать в новый поток, потом эту строку передать в функцию, которая обратно конвертирует строку в числовой указатель и ищет её в пуле. Но, опять произошла проблема, адреса в пуле являются не разыминованные, в отличие от числового указателя. Поэтому поиск никогда не даёт результатов. Буду очень рад, если Вы подскажите как решить эту проблему.
Вообще не понял, что ты хочешь сделать.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Сентябрь 29, 2019, 05:41:18 pm
Спасибо за ответ  kenking. Теперь понятно. Как всегда много трудности при реализации такого проекта. Зато идет прокачка навыков. Не знал как в SDK сделать проверку на ввод с клавиатуры строки. Написал функцию для считывание символов при нажатии клавиш. Все работает https://vk.com/gtabuilder?w=wall-56513456_521.

Конечно, со времени что-то переписываю, например, при перезагрузке скрипта, удаляются все созданные объекты из памяти.
Хотел у Вас спросить, вчера обновил visual studio 2019 при этом изменилась цветовая палитра. С ней неприятно работать, можете скинуть конфиг с прежней цветовой палитрой.
Скажите как в sdk заставить стрелять ракетами и пулеметом вертолет hunter?

   
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 01, 2019, 07:56:09 am
Цитировать
вчера обновил visual studio 2019 при этом изменилась цветовая палитра. С ней неприятно работать, можете скинуть конфиг с прежней цветовой палитрой.
Настроить: Сервис->Параметры->Окружение->Общие->Цветовая тема
У меня 2017

Цитировать
как в sdk заставить стрелять ракетами и пулеметом вертолет hunter?
Не знаю, не изучал этот вопрос.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Октябрь 01, 2019, 05:56:04 pm
kenking, Ох, Вы не поверите, сколько сил и времени потребовалось чтобы вернуть прежнюю цветовую палитру. Просто за год к ней привык, а другая просто режет глаза, и работать невозможно. Подскажите, мне, пожалуйста, способ сохранения информации данного типа. Мы имеем основные потоки, у каждого потока могут быть дополнительные потоки, чтобы было понятнее, у потока один есть дополнительные потоки А и B, и у потока 2 есть потоки С и D, как лучше все это сохранить? В какой структуре? Чтобы легко перебирать дополнительные потоки исходя из основного. Структура вроде похожа на матрицу. Вот ломаю голову как это все реализовать. Может Вы что-то подскажете? Чтобы ещё была хорошая итерация, быстрая добавление и удаление любого дополнительного потока.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 02, 2019, 01:46:49 pm
К сожалению, подсказать не могу.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Октябрь 08, 2019, 04:51:48 am
kenking, решил эту проблему через костыль. сейчас пилю миссию, заметил один нюанс, если установить водителя для авто через скриптовую команду Command<COMMAND_CREATE_CHAR_INSIDE_CAR>(CPools::GetVehicleRef(car), 10, MODEL_SWAT, &ped); он начинает ехать сам. ищу способ это отключить, буду очень рад подсказке.
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 08, 2019, 12:43:05 pm
Попробуй так:
Код: C++
  1. car->m_autoPilot.m_nCarMission = MISSION_NONE;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Октябрь 13, 2019, 05:06:49 am
Спасибо вам большое уважаемый kenking за Ваш ответ. Всё работает как надо. Наконец-то смог переписать миссию "Опека" из gta vice city long night. Теперь можно задать машины точный маршрут следования.
  Но всё же далеко от идеала.  Например, если  начать новую игру, то происходит вылет, пытаюсь  найти  событие "если  новая игра начата, ждать  пока  заставка кончится".  Так же ищу функция арестован игрок или нет.  Конечно,  много приходится костылить)))))))))))))
https://vk.com/gtabuilder?w=wall-56513456_522
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 13, 2019, 09:48:54 am
Так же ищу функция арестован игрок или нет. 
Код: C++
  1. CWorld::Players[CWorld::PlayerInFocus].m_nPlayerState == PLAYERSTATE_HASBEENARRESTED
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Октябрь 22, 2019, 02:06:25 pm

Спасибо вам большое уважаемый kenking, Вы мне очень сильно помогли. Теперь смог написать полноценную миссию. https://vk.com/gtabuilder?w=wall-56513456_523

Всего 50 строк кода, стараюсь его сделать более полиморфизмым, чтобы писать более короче.
Есть класс  CPhysical от него наследуются классы CVehicle и CPed. Как можно узнать через  функцию, то  что мы в него передали, является классом, например, CVehicle.
Код: C++
  1. bool wait(unsigned int key) {
  2.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  3.         else { return false; }
  4. }
  5. CVehicle* createcar(int modelID, float distance = 10.f) {// создать авто
  6.         char reference = 2;
  7.         CPed* player = FindPlayerPed();
  8.         CVector position = player->m_placement.pos;
  9.         position += player->m_placement.up * distance; // Вектор оси прямо от игрока умножаем на 10 метров и прибавляем к позиции.
  10.         CStreaming::RequestModel(modelID, 0); // ANGEL 166 ModelID
  11.         CStreaming::LoadAllRequestedModels(false);
  12.         CVehicle* v;
  13.         if (CModelInfo::IsCarModel(modelID))// если создаем авто.
  14.                 v = new CAutomobile(modelID, reference);
  15.         if (CModelInfo::IsBikeModel(modelID))
  16.                 v = new CBike(modelID, reference);
  17.         if (CModelInfo::IsBoatModel(modelID))
  18.                 v = new CBoat(modelID, reference);
  19.         CCarCtrl::JoinCarWithRoadSystem(v);// ии машина в системе.
  20.         v->m_nState = 4;
  21.         v->CVehicle::m_nCreatedBy = reference; // Если один то транспорт будет удален позже...
  22.         v->m_placement.SetRotate(0, 0, 3.5f);
  23.         v->m_placement.pos.x = position.x;
  24.         v->m_placement.pos.y = position.y;
  25.         v->m_placement.pos.z = position.z + v->GetDistanceFromCentreOfMassToBaseOfModel();
  26.         CWorld::Add(v);
  27.         return v;
  28. };
  29.  
  30. bool iscar(CPhysical* en) {
  31.         /*if (en->)
  32.         {
  33.  
  34.         }*/
  35. };
  36. class Test {
  37. public:
  38.    
  39.     Test() {
  40.                 Events::gameProcessEvent += [] {
  41.                         static int s;
  42.                         CPed* player = FindPlayerPed();// найти игрока
  43.                         if (!player) return;// проверка найден игрок
  44.                         KeyCheck::Update();
  45.                         if (KeyCheck::CheckWithDelay('N', 200)) {//если N нажата
  46.                                 if (wait('N')) return; {//если м нажата
  47.                
  48.                         CVehicle* car = createcar(MODEL_INFERNUS);
  49.                         if (iscar(car)) {
  50.                                 CMessages::AddMessageJumpQ(L"this is car", 10000, 0);
  51.                         }
  52.                                 }
  53.                         }
  54.                 };
  55.         }
  56. } test;
  57.  

Зачем это нужно? Чтобы на lua осуществить перегрузку функций, что упростить процесс написание скриптов.

Есть ли способ заставить ехать машину назад? Хочу реализовать дистанционное управление авто. Пытался через скриптовую команду не вышло.

Код: C++
  1.  
  2. Command<COMMAND_SET_CAR_TEMP_ACTION>(CPools::GetVehicleRef(car), 22,20000);
  3.  

Разбирал функции, вот, что вышло.

Код: C++
  1. car->FireFixedMachineGuns();//  починка авто от огневого оружия?
  2. //      car->ExtinguishCarFire();// выход из горящего авто?
  3. //      unsigned char c = car->m_nLastWeaponDamage;// последнее оружия наносящее урон авто?
  4. car->DoSunGlare();//авто едет в воду.
  5.  


Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 23, 2019, 02:57:12 pm
Цитировать
Как можно узнать через  функцию, то  что мы в него передали, является классом, например, CVehicle.
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\KeyCheck.h"
  3. #include "CMessages.h"
  4. #include "CModelInfo.h"
  5.  
  6. using namespace plugin;
  7.  
  8. class Test {
  9. public:
  10.  
  11.     static void EntityType(CEntity *entity) {
  12.         if (CModelInfo::ms_modelInfoPtrs[entity->m_nModelIndex]->m_nType == MODEL_INFO_PED)
  13.             CMessages::AddMessageJumpQ(L"ped", 2000, 0);
  14.         if (CModelInfo::ms_modelInfoPtrs[entity->m_nModelIndex]->m_nType == MODEL_INFO_VEHICLE)
  15.             CMessages::AddMessageJumpQ(L"vehicle", 2000, 0);
  16.     }
  17.  
  18.     Test() {
  19.         Events::gameProcessEvent += [] {
  20.             KeyCheck::Update();
  21.             if (KeyCheck::CheckWithDelay('M', 2000)) {
  22.                 CPed *player = FindPlayerPed();
  23.                 if (player) {
  24.                     if (player->m_pVehicle && player->m_bInVehicle)
  25.                         EntityType(player->m_pVehicle);
  26.                     else
  27.                         EntityType(player);
  28.                 }
  29.             }
  30.         };
  31.     }
  32. } test;

Цитировать
Есть ли способ заставить ехать машину назад?
Код: C++
  1. vehicle->m_autoPilot.m_nAnimationId = TEMPACT_REVERSE;
  2. vehicle->m_autoPilot.m_nAnimationTime = 20000;
В транспорте должен быть водитель.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Октябрь 26, 2019, 05:50:04 am
Благодарю вас kenking за помощь. плагин скоро  будет допилен))))))))))) надеюсь на это.

что-то у  меня  не вышло, заставить авто ехать назад, может  какого-то флага не  хватает. происходит вылет.

Код: Text
  1.  
  2. bool wait(unsigned int key) {
  3.         if (!KeyCheck::CheckWithDelay(key, 200)) { return true; }
  4.         else { return false; }
  5. }
  6. CVehicle* createcar(int modelID, float distance = 10.f) {// создать авто
  7.         char reference = 2;
  8.         CPed* player = FindPlayerPed();
  9.         CVector position = player->m_placement.pos;
  10.         position += player->m_placement.up * distance; // Вектор оси прямо от игрока умножаем на 10 метров и прибавляем к позиции.
  11.         CStreaming::RequestModel(modelID, 0); // ANGEL 166 ModelID
  12.         CStreaming::LoadAllRequestedModels(false);
  13.         CVehicle* v;
  14.         if (CModelInfo::IsCarModel(modelID))// если создаем авто.
  15.                 v = new CAutomobile(modelID, reference);
  16.         if (CModelInfo::IsBikeModel(modelID))
  17.                 v = new CBike(modelID, reference);
  18.         if (CModelInfo::IsBoatModel(modelID))
  19.                 v = new CBoat(modelID, reference);
  20.         CCarCtrl::JoinCarWithRoadSystem(v);// ии машина в системе.
  21.         v->m_nState = 4;
  22.         v->CVehicle::m_nCreatedBy = reference; // Если один то транспорт будет удален позже...
  23.         v->m_placement.SetRotate(0, 0, 3.5f);
  24.         v->m_placement.pos.x = position.x;
  25.         v->m_placement.pos.y = position.y;
  26.         v->m_placement.pos.z = position.z + v->GetDistanceFromCentreOfMassToBaseOfModel();
  27.         CWorld::Add(v);
  28.         return v;
  29. };
  30.  
  31. bool iscar(CPhysical* en) {
  32.         if (CModelInfo::ms_modelInfoPtrs[en->m_nModelIndex]->m_nType == MODEL_INFO_PED) {
  33.                 CMessages::AddMessageJumpQ(L"ped", 2000, 0);
  34.                 return false;
  35.         }
  36.  
  37.         if (CModelInfo::ms_modelInfoPtrs[en->m_nModelIndex]->m_nType == MODEL_INFO_VEHICLE){
  38.                 CMessages::AddMessageJumpQ(L"vehicle", 2000, 0);
  39.                 return false;
  40.         }
  41. };
  42. class Test {
  43. public:
  44.    
  45.     Test() {
  46.                 Events::gameProcessEvent += [] {
  47.                         CVehicle* car = nullptr;
  48.                         CPed* player = FindPlayerPed();// найти игрока
  49.                         if (!player) return;// проверка найден игрок
  50.                         KeyCheck::Update();
  51.                         if (KeyCheck::CheckWithDelay('N', 200)) {//если N нажата
  52.                                 if (wait('N')) return; {//если N нажата
  53.  
  54.                                 CPed* ped = nullptr;
  55.                                  car = createcar(MODEL_INFERNUS);
  56.                                 Command<COMMAND_REQUEST_MODEL>(MODEL_ARMY);
  57.                                 Command<COMMAND_LOAD_ALL_MODELS_NOW>(false);
  58.                                 if (Command<COMMAND_HAS_MODEL_LOADED>(MODEL_ARMY)) {
  59.                                                 Command<COMMAND_CREATE_CHAR_INSIDE_CAR>(CPools::GetVehicleRef(car), 4, MODEL_ARMY, &ped);
  60.                                                 //car->m_autoPilot.m_nCarMission = MISSION_NONE;
  61.                                         }
  62.                                 }
  63.                         }
  64.                         if (KeyCheck::CheckWithDelay('M', 200)) {//если M нажата
  65.                                 CMessages::AddMessageJumpQ(L"this is car", 10000, 0);
  66.                                         car->m_autoPilot.m_nAnimationId = TEMPACT_REVERSE;
  67.                                         car->m_autoPilot.m_nAnimationTime = 20000;
  68.                         }
  69.                 };
  70.         }
  71. } test;
  72.  
  73.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Октябрь 26, 2019, 08:21:23 am
Код: C++
  1. #include "plugin.h"
  2.  
  3. using namespace plugin;
  4.  
  5. class Test {
  6. public:
  7.     Test() {
  8.         Events::gameProcessEvent += [] {
  9.             CPed *player = FindPlayerPed();
  10.             if (player) {
  11.                 for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {
  12.                     CVehicle *vehicle = CPools::ms_pVehiclePool->GetAt(i);
  13.                     if (vehicle && (DistanceBetweenPoints(player->GetPosition(), vehicle->GetPosition()) < 7.0f)) {
  14.                         vehicle->m_autoPilot.m_nAnimationId = TEMPACT_REVERSE;
  15.                         vehicle->m_autoPilot.m_nAnimationTime = 20000;
  16.                     }
  17.                 }
  18.             }
  19.         };
  20.     }
  21. } test;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 04, 2019, 05:10:17 am
спасибо большое за Ваш ответ kenking. удалось реализовать управление авто следующим образом.
Код: C++
  1. int setcaraction(lua_State* L) {// установить поведение авто.
  2.         try {
  3.                 if (LUA_TUSERDATA == lua_type(L, -3)) {// указатель на авто.
  4.                         if (LUA_TNUMBER == lua_type(L, -2) && LUA_TNUMBER == lua_type(L, -1)) {
  5.                                 CVehicle* car = (CVehicle*)Userdata::get<CVehicle>(L, 1, false);// получить указатель на авто.
  6.                                 int style = Stack<int>::get(L, 2);// если число.
  7.                                 unsigned int t = Stack<int>::get(L, 3);// если число.
  8.                                 unsigned int time = t * 10;
  9.  
  10.                                 for (int i = 0; i < CPools::ms_pVehiclePool->m_nSize; i++) {
  11.                                         CVehicle* vehicle = CPools::ms_pVehiclePool->GetAt(i);
  12.                                         if (vehicle == car) {
  13.  
  14.                                                 if (style == 0) {
  15.                                                         Command<COMMAND_SET_CAR_TEMP_ACTION>(CPools::GetVehicleRef(vehicle), TEMPACT_NONE, time);
  16.                                                         return 0;
  17.                                                 }
  18.                                                 if (style == 1) {
  19.                                                         Command<COMMAND_SET_CAR_TEMP_ACTION>(CPools::GetVehicleRef(vehicle), TEMPACT_WAIT, time);
  20.                                                         return 0;
  21.                                                 }                                                                                                                                                                      
  22. .........................
  23.  

пытался написать подобие миссии "Водитель" вышло криво https://vk.com/gtabuilder?w=wall-56513456_524 (https://vk.com/gtabuilder?w=wall-56513456_524)
не хватает таймера  гонки.  Vital в видео показывал так https://www.youtube.com/watch?v=YzGGZM_KyjQ&t=1256s (https://www.youtube.com/watch?v=YzGGZM_KyjQ&t=1256s)
но в vice city он не работает на cleo.
хотелось узнать как сделать таймер на sdk, чтобы потом перенести в lua.
можно создать тему lualoader? чтобы выкладывать туда наработки?
как этот раздел http://forum.gtabuilder.ru/index.php?board=28.0 (http://forum.gtabuilder.ru/index.php?board=28.0)
Скажите, пожалуйста, как помочь сайту материально?

Код: C++
  1. {$CLEO}
  2. 0000:    
  3. const
  4.  TEXT_X = 608.0 //timer X position (0.0–640.0)
  5.  TEXT_Y = 136.0 //timer Y position (0.0–448.0)
  6.  TEXT_R = 144 //timer red colour (0–255)
  7.  TEXT_G = 96 //timer green colour (0–255)
  8.  TEXT_B = 16 //timer blue colour (0–255)
  9.  TEXT_A = 255 //timer alpha (0–255)
  10.  TEXT_FONT = 3 //0 (Gothic),1 (Standard),2 (Menu),3 (Pricedown)
  11.  LETTER_H = 2.3 //letter height
  12.  LETTER_W = 0.6 //letter width
  13.  OUTLINE_R = 0 //outline red colour (0–255)
  14.  OUTLINE_G = 0 //outline green colour (0–255)
  15.  OUTLINE_B = 0 //outline blue colour (0–255)
  16.  OUTLINE_A = 200 //outline alpha (0–255)
  17.  OUTLINE_W = 1 //outline width (1 & 2 are optimal values)
  18. end // const
  19.                            
  20. :1
  21. while true
  22. wait 0 ms  
  23. 03F0: enable_text_draw 1
  24. 03E4: set_text_draw_align_right 1
  25. 0340: set_text_draw_RGBA TEXT_R TEXT_G TEXT_B TEXT_A
  26. 0349: set_text_draw_font TEXT_FONT
  27. 033F: set_text_draw_letter_size LETTER_W LETTER_H
  28. 045B: draw_text_2numbers TEXT_X TEXT_Y GXT 'TIME' numbers 0 0 //~1~:~1~
  29.   03F0: enable_text_draw 0  
  30.   end
  31. jump @1
  32.  



Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Ноябрь 04, 2019, 09:46:41 am
Цитировать
можно создать тему lualoader? чтобы выкладывать туда наработки?
Форум для того и существует, чтобы научиться чему-то новому и показать свои разработки, которые могут пригодиться другим пользователям.

Цитировать
Скажите, пожалуйста, как помочь сайту материально?
Обратись к владельцу ресурса Sektor'у через личное сообщение.

Цитировать
хотелось узнать как сделать таймер на sdk, чтобы потом перенести в lua.
Таймер можно реализовать по-разному, зависит от конкретной ситуации, например, так:
Код: C++
  1. #include "plugin.h"
  2. #include "extensions\KeyCheck.h"
  3. #include "CTimer.h"
  4.  
  5. using namespace plugin;
  6.  
  7. class Test {
  8. public:
  9.     enum eTimerState { STATE_START, STATE_PLAY };
  10.     static eTimerState m_currentState;
  11.     static int m_min, m_sec, m_millisec;
  12.  
  13.     Test() {
  14.         Events::drawingEvent += [] {
  15.             switch (m_currentState) {
  16.             case STATE_START:
  17.                 KeyCheck::Update();
  18.                 if (KeyCheck::CheckWithDelay('M', 2000)) {
  19.                     m_min = 0; m_sec = 0; m_millisec = CTimer::m_snTimeInMilliseconds;
  20.                     m_currentState = STATE_PLAY;
  21.                 }
  22.                 break;
  23.             case STATE_PLAY:
  24.                 if (CTimer::m_snTimeInMilliseconds > (m_millisec + 1000)) {
  25.                     m_millisec = CTimer::m_snTimeInMilliseconds;
  26.                     if (m_sec < 59)
  27.                         m_sec++;
  28.                     else {
  29.                         m_sec = 0;
  30.                         if (m_min < 2)
  31.                             m_min++;
  32.                         else
  33.                             m_currentState = STATE_START;
  34.                     }
  35.                 }
  36.                 gamefont::Print({
  37.                     Format("min %02d : sec %02d", m_min, m_sec)
  38.                 }, 10, 10, 1, FONT_DEFAULT, 0.75f, 0.75f, color::White);
  39.                 break;
  40.             }
  41.         };
  42.     }
  43. } test;
  44.  
  45. Test::eTimerState Test::m_currentState = STATE_START;
  46. int Test::m_min = 0;
  47. int Test::m_sec = 0;
  48. int Test::m_millisec = 0;
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Ноябрь 06, 2019, 11:30:00 pm
kenking спасибо очередной раз за Вашу неоцененную помощь,  таймер пока не перенес, хочется, чтобы нормально работало. тему создам, может прогресс ускорится. времени часто не хватает.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 11, 2020, 12:31:27 pm

Хотел написать миссию “Вечеринка” на чистом с++ sdk plugin, чтобы лучше понимать, как там все устроено. Какой принцип? Запускается из основного потока, независимый поток, чтобы можно было использовать задержки, аналог wait. Вся миссия находится в бесконечном цикле? пока флаг миссии не будет изменён. Но всё вылетает, как только игрок находится на маркере. С помощью тестов установил, что причина вылета происходит из-за проверки, находится ли на точке пешком в радиусе. Как исправить эту ситуацию? Подскажите, пожалуйста. Самое интересное, что все раньше работало нормально.

Ошибка


Код: Javascript
  1.  
  2.         // 1 этап.
  3.         while (getflagmission()) {this_thread::sleep_for(chrono::milliseconds(10));
  4.         if (ped_in_point(player, 95.4, -1136.2, 10.5, 3.0,3.0, 2.0) && !player->m_bInVehicle){// если в точке и не в авто.
  5.                 remove_sphere_and_blip(marker, sphere);// удалить маркер и сферу.
  6.  
Вот как выглядит вся миссия

Код: Javascript
  1. void mission(){ CPed* player = FindPlayerPed();// найти игрока
  2.         static int marker, sphere; //id маркера.
  3.         Command<COMMAND_SET_PLAYER_COORDINATES>(CWorld::PlayerInFocus, 118.0, -825.9, 10.5);
  4.         Command<COMMAND_SET_PLAYER_HEADING>(CWorld::PlayerInFocus, 54.0);
  5.         CVehicle* car = createcar(MODEL_ANGEL, 123.8, -810.9, 10.5, 320.0); // создать авто
  6.  
  7.         Command<COMMAND_DO_FADE>(1500, 1);// просветление.
  8.         CMessages::AddMessageJumpQ(L"~r~Go get some new threads from Rafael's clothes shop", 5000, 1);// вывести сообщение на экран.
  9.         create_blip_and_sphere(marker, sphere, 95.4, -1136.2, 10.5);// создать маркер на карте и создать сферу.
  10.  
  11.         // 1 этап.
  12.         while (getflagmission()) {this_thread::sleep_for(chrono::milliseconds(10));
  13.         if (ped_in_point(player, 95.4, -1136.2, 10.5, 3.0,3.0, 2.0) && !player->m_bInVehicle){// если в точке и не в авто.
  14.                 remove_sphere_and_blip(marker, sphere);// удалить маркер и сферу.
  15.                 Command<COMMAND_SWITCH_WIDESCREEN>(CWorld::PlayerInFocus, 1);// вкл/выкл широкий экран.
  16.                 Command<COMMAND_DO_FADE>(1500, 0);
  17.                 this_thread::sleep_for(chrono::milliseconds(2500));
  18.                 set_skin(player, "PLAYER9");
  19.                 Command<COMMAND_POINT_CAMERA_AT_POINT>(92.39, -1131.74, 16.724, 2);// переместить камеру в координатах.  
  20.                 Command<COMMAND_SET_FIXED_CAMERA_POSITION>(91.813, -1131.116, 17.251, 0.0, 0.0, 0.0); //уст камеру в координатах.
  21.                 Command<COMMAND_DO_FADE>(1500, 1);
  22.                 create_blip_and_sphere(marker, sphere, -251.2, -1360.8, 8.1);// создать маркер на карте и сферу.
  23.  
  24.                 this_thread::sleep_for(chrono::milliseconds(1500));
  25.                 Command<COMMAND_RESTORE_CAMERA>();
  26.                 Command<COMMAND_RESTORE_CAMERA_JUMPCUT>();      // восстановить камеру.
  27.                 Command<COMMAND_SWITCH_WIDESCREEN>(CWorld::PlayerInFocus, 0);// вкл/выкл широкий экран.
  28.                 CMessages::AddMessageJumpQ(L"~r~Get to then Colonel's boat", 5000, 1);// вывести сообщение на экран.
  29.                 break;}
  30.         };
  31.         CPed* ped;
  32.         // 2 этап.
  33.         while (getflagmission()) {this_thread::sleep_for(chrono::milliseconds(10));
  34.         if (ped_in_point(player, -251.2, -1360.8, 8.1, 3.0, 3.0, 2.0 && !player->m_bInVehicle)) {// если в точке и не в авто.
  35.                 remove_sphere_and_blip(marker, sphere);// удалить маркер и сферу.
  36.                 Command<COMMAND_DO_FADE>(1500, 0);
  37.                 this_thread::sleep_for(chrono::milliseconds(2500));
  38.                 Command<COMMAND_SET_PLAYER_COORDINATES>(CWorld::PlayerInFocus, -241.7, -1362.3, 8.1);
  39.                 Command<COMMAND_SET_PLAYER_HEADING>(CWorld::PlayerInFocus, 269.0);
  40.                 CMessages::AddMessageJumpQ(L"~r~Take the Colonel's daughter to the Pole Position club", 5000, 1);// вывести сообщение на экран., 3000, 1);// вывести сообщение на экран.
  41.                 create_blip_and_sphere(marker, sphere, 100.7, -1477.6, 10.1);// создать маркер на карте, создать сферу
  42.  
  43.                 ped = create_spec_ped("IGMERC", -241.7, -1360.3, 8.1); // создать спец педа.    
  44.                 ped->SetObjective(OBJECTIVE_SET_LEADER, player);
  45.                 Command<COMMAND_DO_FADE>(1500, 1);// просветление.
  46.                 break;  }
  47.         };
  48.  
  49.         // 3 этап.
  50.         while (getflagmission()) {      this_thread::sleep_for(chrono::milliseconds(10));
  51.         if (ped_in_point(player, 100.7, -1477.6, 10.1, 3.0, 3.0, 2.0)) {// если в точке и не в авто.
  52.                 remove_sphere_and_blip(marker, sphere);// удалить маркер и сферу.
  53.                 miss(100);      break;  }      
  54.         if (!ped->m_fHealth > 0.10f){ CMessages::AddMessageJumpQ(L"~r~Mercedes is dead", 5000, 1);// вывести сообщение на экран
  55.             fail_mission();     break;  }
  56.         };
  57.         ped->SetObjective(OBJECTIVE_LEAVE_CAR); // выйти из авто.
  58.         while(ped->m_bInVehicle) { this_thread::sleep_for(chrono::milliseconds(10)); };
  59.         destroy();// удалить маркер и сферу.
  60. };
  61.  

Вот исходник. Есть ли функция для проверки нахождения педа в точке с радиусом?
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Февраль 27, 2020, 09:17:22 am
вот написал кастомную миссию "вечеринка" на lua.

есть функция ped->SetObjective(OBJECTIVE_SET_LEADER, player); пед следует за игроком.

но если мы выстрелим около педа, он перестанет за нами следовать. Скажите пожалуйста как это исправить?

 Уже почти год работаю над плагином, не могу никак его довести до ума. Очень буду рад если вы подскажите функции работы с камерой.

 Видео https://www.youtube.com/watch?v=tS_IdkQ11NE&feature=youtu.be (https://www.youtube.com/watch?v=tS_IdkQ11NE&feature=youtu.be)
Название: Re: Написание плагина. Настройка проекта
Отправлено: xanser от Февраль 28, 2020, 10:49:50 am
Ради чего столько мучений? По идее ты переписываешь стандартный скрипт на другом языке, вся последовательность команд должна быть та же самая. И что будет в результате, та же самая игра, только с вероятными проблемами. Какие функции с камерой подсказать? Ну вот например (в SDK аналогично):

Код: C++
  1. void CCamera::SetBehindPlayer() {
  2.         ((void(__thiscall *)(CCamera *))0x46BADE)(this);
  3. }
  4. void CCamera::Restore() {
  5.         ((void(__thiscall *)(CCamera *))0x46BC7D)(this);
  6. }
  7. void CCamera::SetPosition(CVector pos, CVector rotation) {
  8.         ((void(__thiscall *)(CCamera *, CVector *, CVector *))0x46BA72)(this, &pos, &rotation);
  9. }
  10. void CCamera::SetTarget(CVector point, signed int mode, signed int flag) {
  11.         ((void(__thiscall *)(CCamera *, CVector *, signed int, signed int))0x46A494)(this, &point, mode, flag);
  12. }
  13. void CCamera::SetRadius(float value, bool flag) {
  14.         this->nearClipPlain = value;
  15.         this->nearClipPlainOn = flag;
  16. }
  17.  
  18. auto Camera = (CCamera *)0x7E4688;
  19. // установка камеры
  20. Camera->SetRadius(0.02f, 1);
  21.  
  22. Camera->cams[Camera->activeCam].target.x = Camera->pos.x + (float)(-X1 * cos(U) + Y1 * sin(U));
  23. Camera->cams[Camera->activeCam].target.y = Camera->pos.y + (float)(-Y1 * cos(U) - X1 * sin(U));
  24. Camera->cams[Camera->activeCam].target.z = Camera->cams[Camera->activeCam].target.z + R0 * Mouse->Y / 100;
  25.  
  26. Camera->pos.x = Camera->cams[Camera->activeCam].target.x + R2*(float)(X1 * cos(U) - Y1 * sin(U));
  27. Camera->pos.y = Camera->cams[Camera->activeCam].target.y + R2*(float)(Y1 * cos(U) + X1 * sin(U));
  28. Camera->pos.z = Camera->pos.z - R0 * Mouse->Y / 100;
  29.  
  30.  
  31. Camera->SetPosition(Camera->pos, CVector(0, 0, 0));
  32. Camera->SetTarget(Camera->cams[Camera->activeCam].target, 2, 1);
  33.  
  34. // восстановление камеры
  35. Camera->SetRadius(0.9f, 0);
  36. Camera->Restore();
  37. Camera->SetBehindPlayer();
  38.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 09, 2020, 05:25:07 pm
Спасибо большое за ответ уважаемый  xanser. Конечно мучений много, но это того стоит, например, миссии писать  легко. Ещё  можно как-то упростить, чтобы  ускорить написание кода скрипта.
Функции, которые вы написали, нет в "CCamera.h", может просто ещё не добавляли в репозиторий.
Скажите, пожалуйста, что делает эта функции?
Понимаю, что она принимает числа, где посмотреть какие именно ?
Код: Javascript
  1. CCamera* c;
  2.                                         c->SetNewPlayerWeaponMode(3,1,3);
  3. SetNearClipScript(float fNearClipScript);
  4.         void SetNewPlayerWeaponMode(short Mode, short MinZoom, short MaxZoom);
  5.         void SetZoomValueCamStringScript(short mode);
  6.         void SetZoomValueFollowPedScript(short mode);
  7.         void StartTransition(short mode);
  8.  

Допустим, установили камеру в нужных нам координатах, но нужно её развернуть по вертикальной оси или наклонить от себя или от себя, для хорошего операторского ракурса, какие функции для этого использовать?


Скажите, пожалуйста, функцию, которая проверяет игрок целиться в педа?

Почему-то не могу получить 5 или 6 звёзд розыска с помощью скриптовой команды , 
Command<COMMAND_ALTER_WANTED_LEVEL>(CWorld::PlayerInFocus, wanted); только максимум 4 звезды розыска можно получить.

Название: Re: Написание плагина. Настройка проекта
Отправлено: xanser от Март 13, 2020, 04:33:27 pm
Функции, которые вы написали, нет в "CCamera.h", может просто ещё не добавляли в репозиторий.

Поищи по адресам в CCamera.cpp, у меня другие названия.

Допустим, установили камеру в нужных нам координатах, но нужно её развернуть по вертикальной оси или наклонить от себя или от себя, для хорошего операторского ракурса, какие функции для этого использовать?

Функция 0x46A494 устанавливает точку, в которую камера смотрит.
Название: Re: Написание плагина. Настройка проекта
Отправлено: Saint от Март 13, 2020, 11:39:51 pm
Почему-то не могу получить 5 или 6 звёзд розыска с помощью скриптовой команды , 

cначало надо установить максимальный уровень розыска https://gtamods.com/wiki/01F0
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 24, 2020, 01:45:11 am
Спасибо  xanser  вам ответ.

Камера работает следующим образом
Код: Javascript
  1. CCamera* cam;
  2. cam = (CCamera*)0x7E4688;
  3. cam->Restore();
  4.  
 

Наконец-то удалось  установить угол для  камеры https://www.youtube.com/watch?v=kyDgJicxGdQ&feature=youtu.be (https://www.youtube.com/watch?v=kyDgJicxGdQ&feature=youtu.be)

Спасибо за подсказку, теперь уровень розыска устанавливается нужный.
Код: Javascript
  1.  
  2. Command<COMMAND_SET_MAX_WANTED_LEVEL>(wanted);
  3.  
  4. Command<COMMAND_ALTER_WANTED_LEVEL>(CWorld::PlayerInFocus, wanted);
  5.  
  Интересно, можно ли  заменить их функциями?
Скажите, пожалуйста, какие функции отвечают за проверки целиться игрок ли в педа? Получил ли пед  урон от игрока, получил ли пед урон конкретного вида оружия?
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Март 24, 2020, 02:59:15 pm
Цитировать
Интересно, можно ли  заменить их функциями?
Как я уже писал ранее, надо открыть базу и посмотреть соответствующие опкоды. Для разбора опкодов можно взять базу для GTA3, большинство опкодов для VC и тройки одинаковые. А база для тройки разобрана намного больше.

опкод 01F0: set_max_wanted_level_to 6 - CWanted::SetMaximumWantedLevel

опкод 010D: set_player $PLAYER_CHAR wanted_level_to 6 - CPlayerPed::SetWantedLevel
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Март 29, 2020, 03:51:48 pm

Спасибо большое за ваш ответ уважаемый kenking.
Хорошо, что у нас есть база, где можно посмотреть функции, жаль, что с ней мало кто может работать продуктивно.   
Нужны знания ассемблера, он гораздо сложнее с++.

Изучаю sdk plugin. Вот, что выяснил.
Код: Javascript
  1. CCamera* cam;
  2. cam = (CCamera*)0x7E4688;
  3. //float res = cam->CarZoomIndicator; // режим камеры в авто от 0 до 5, 4 пропускает.
  4. //float res = cam->CarZoomValue;// что-то с зумом в авто, насколько приближенная к авто.
  5. //float res = cam->DistanceToWater;// странная дистанция до воды.
  6. //float res = player->GetHeading();// получить угол педа
  7. CWeapon weapon = ped->m_aWeapons[ped->m_nActiveWeaponSlot];
  8. int ammo = weapon.m_nTotalAmmo;// кол-во патронов в текущем оружии.
  9.  
  10. Также научился немного  работать с огнём.
  11. int fire;// переменная хранить id огня.
  12. CPed* ped = findpedinpool(p);//  получить указатель на педа.
  13. Command<COMMAND_START_CHAR_FIRE>(CPools::GetPedRef(ped), &fire);// создать огонь на педе.
  14.  
  15. CVehicle* car = findcarinpool(p);// получить указатель на авто.
  16. Command<COMMAND_START_CAR_FIRE>(CPools::GetVehicleRef(car), &fire);// создать огонь на авто.
  17.  
  18. float x = lua_tonumber(L, 1);
  19. float y = lua_tonumber(L, 2); float z = lua_tonumber(L, 3);
  20. int fire;// переменная хранить id огоня.
  21. CVector pos = { x,y,z };
  22.  
  23. Command<COMMAND_START_SCRIPT_FIRE>( pos.x, pos.y, pos.z, &fire);// создать огонь на координатах.
  24.  
  25. Command<COMMAND_REMOVE_SCRIPT_FIRE>(fire);// удалить огонь.
  26.  
  27.  
У меня возникли вопросы, при вызове этих функции, нет никакого эффекта

Код: Javascript
  1. CWeapon weapon = ped->m_aWeapons[ped->m_nActiveWeaponSlot];
  2. weapon.InitialiseWeapons();
  3. weapon.Shutdown();*/
  4. //weapon.ShutdownWeapons();
  5. weapon.Reload();
  6.  

может кто-то из вас с ними работает? Скажите, пожалуйста, как они действуют, на что они влияют?   
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Апрель 04, 2020, 05:41:32 pm
Если долго мучиться, что-нибудь получится. Искал в базе, вот нашёл.

Нашёл скриптовую команду игрок целиться в педа, проверяем педа.
Код: Javascript
  1. bool check_target = Command<COMMAND_IS_PLAYER_TARGETTING_CHAR>(CWorld::PlayerInFocus, CPools::GetPedRef(ped));
  2.  

Также научился изменять характеристики оружия, пока урон.

Код: Javascript
  1.         CWeapon weapon = ped->m_aWeapons[ped->m_nActiveWeaponSlot];
  2.         eWeaponType type = weapon.m_nType;
  3.         CWeaponInfo* w = CWeaponInfo::GetWeaponInfo(type);
  4.         w->m_nDamage = 500
  5.  

размер обоймы пока изменить не удалось.

Выяснил, что Shutdown помогает удалить текущее оружие.

Код: Javascript
  1. ped->SetAmmo((eWeaponType)tipe, 0);
  2. CWeapon weapon = ped->m_aWeapons[ped->m_nActiveWeaponSlot];
  3. ped->RemoveWeaponModel(idweapon);
  4. weapon.Shutdown();
  5. weapon.UpdateWeapons();
  6.  
  7.  

такой прогресс.
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Апрель 16, 2020, 09:25:28 am
Возникла такая ситуация. Функция и скриптовая команда, при установке количество денег педа, при его смерти, выпадает сумма денег, которая отличается от установленной, в чём причина такой ситуации?


Код: Javascript
  1. ped->m_nPedMoney = 100;
  2. ped->CreateDeadPedMoney();
  3.  
  4.  
  5. Command<COMMAND_SET_CHAR_MONEY>(CPools::GetPedRef(ped), 0);
  6. this_thread::sleep_for(chrono::milliseconds(1));
  7. Command<COMMAND_SET_CHAR_MONEY>(CPools::GetPedRef(ped), 100);
  8.  
Название: Re: Написание плагина. Настройка проекта
Отправлено: kenking от Апрель 16, 2020, 11:28:48 am
Цитировать
при установке количество денег педа, при его смерти, выпадает сумма денег, которая отличается от установленной, в чём причина такой ситуации?
Функцию CPed::CreateDeadPedMoney открой в IDA (нажми F5 для генерации псевдокода на С++)
Название: Re: Написание плагина. Настройка проекта
Отправлено: egor230 от Апрель 29, 2020, 11:21:23 am
Спасибо за уделённое время kenking, с этой функцией, в ней есть некий рандом.
Код: Javascript
  1. pedmoney = this->wPedMoney;
  2. if ( pedmoney >= 10u ){
  3. x = this->physical.entity.replacement.m_matrix.pos.x;
  4. у = this->physical.entity.m_placement.m_matrix.pos;
  5. z = this->physical.entity, replacement.m_matrix.pos.z;
  6. v4 = ((signed int)(0x66666667 * (unsigned       int64)pedmoney >> 32) >> 3) + ((unsigned int)pedmoney >> 31) + 1;
  7. if ( V4 >= 7 )
  8.  v4 = 7;
  9.  v5 = 0;
  10. for ( pedmoney_ = pedmoney / v4; v5 < v4; -H-v5 )
  11. {
  12.   v9 = sin((double)(unsigned    int8) *and() * 0.024543693);
  13.  if ( v8 & 0x400 )
  14. {
  15.   deg2rad(v7);
  16.   v9 = sin(v9);
  17. }
  18. vl0 = v9;
  19. x = 1.5 * vl0 + x;
  20. vl3 = cos((double)(unsigned     int8)rand() * 0.024543693);
  21. if ( vl2 & 0x400 )
  22. {
  23. deg2rad(v11);
  24. v13 = cos(v13);
  25. }
  26. v14 = v13; у = 1.5 * vl4 + y;
  27. z = eWorld::FindGroundZFor3DCoord(x, y, z, &a4) + 0.5; if ( a4 )
  28. {
  29. vl5 = rand();
  30. CPickups::GenerateNewOne(pedmoney_, x, y, z, wMIDMoney, 8, pedmoney_ + (vl5 & 3), 0, 0, 0);
  31.    }
  32.   }
  33. v1->wPedMoney = 0;
  34.  }
  35.