Автор Тема: Написание плагина. Настройка проекта  (Прочитано 77120 раз)

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #60 : Август 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

Оффлайн DK

  • Новичок
  • **
  • Сообщений: 234
  • Репутация: +328/-0
    • dk22pac
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #61 : Август 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).
Поэтому мы и определяем конструктор и добавляем туда инжект наших функций.

Уже говорил об этом тут и тут

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. }

Нет. Просто в первом варинте используется лямбда-выражение.
А во втором - отдельно создается функция Process.
4) Как я понял, если надо, чтобы два действия обрабатывались одновременно, надо "вклиниваться" в два разных процесса?

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

Есть функция CTheScripts::IsPlayerOnAMission().
Про этот класс я уже говорил.
Пока что вызвать можно так:
Код: C++
  1. plugin::Call<bool, 0x464D50>();
Или добавить её в класс.
« Последнее редактирование: Август 16, 2016, 07:45:09 pm от DK »
Plugin-SDK https://github.com/DK22Pac/plugin-sdk

Discord-сервер по plugin-sdk и программированию в GTA
RU https://discord.gg/QEesDGb
ENG https://discord.gg/zaVqFQv

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #62 : Август 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 разобрался, эти вопросы снимаются.
Код подредактировал.

Остальные вопросы всё ещё неразрешимы пока. Просьба помочь разобраться.
« Последнее редактирование: Август 24, 2016, 03:44:17 pm от kenking »

Оффлайн DK

  • Новичок
  • **
  • Сообщений: 234
  • Репутация: +328/-0
    • dk22pac
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #63 : Август 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;
« Последнее редактирование: Август 24, 2016, 08:11:13 pm от DK »
Plugin-SDK https://github.com/DK22Pac/plugin-sdk

Discord-сервер по plugin-sdk и программированию в GTA
RU https://discord.gg/QEesDGb
ENG https://discord.gg/zaVqFQv

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #64 : Август 26, 2016, 09:41:52 am »
Спасибо за пояснения и новую базу. Буду разбираться.

Когда-то меня просили написать скрипт для SA, чтобы у дополнительно установленных моделей типа zr350, фары открывались на разный угол. Ну т.е. задавать каждой модели в .ini файле свой угол открытия фар, т.к. есть модели у которых он значительно отличается и получается при использовании плагина Александра GTA SA Vehicle Special Abilities Editor и новых моделей, фары у некоторых моделей открываются не полностью или наоборот поворачиваются на лишние градусы. Для VC и GTA III я такую возможность сделал (только там не считывание угла с .ini для каждой модели, а значение угла "зашивается" в саму модель путём названия вспомогательного дамми, т.е. получается надо редактировать саму модель).


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

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

так вот, если можно, то просьба показать, как это реализовать на С++ на примере хотя бы возможности цеплять прицепы к моделям, где изначально эта возможность не имелась.
« Последнее редактирование: Август 26, 2016, 10:00:04 am от kenking »

Оффлайн DK

  • Новичок
  • **
  • Сообщений: 234
  • Репутация: +328/-0
    • dk22pac
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #65 : Август 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



PS Соединять LANDSTALKER и ARTICT2 не желательно  :P Наверное, лучше ещё добавить настройку офсета под каждую модель.
« Последнее редактирование: Август 30, 2016, 12:26:40 am от DK »
Plugin-SDK https://github.com/DK22Pac/plugin-sdk

Discord-сервер по plugin-sdk и программированию в GTA
RU https://discord.gg/QEesDGb
ENG https://discord.gg/zaVqFQv

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #66 : Август 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


Оффлайн DK

  • Новичок
  • **
  • Сообщений: 234
  • Репутация: +328/-0
    • dk22pac
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #67 : Август 30, 2016, 05:57:49 pm »
Обнови проект.
Plugin-SDK https://github.com/DK22Pac/plugin-sdk

Discord-сервер по plugin-sdk и программированию в GTA
RU https://discord.gg/QEesDGb
ENG https://discord.gg/zaVqFQv

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #68 : Август 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}

Оффлайн mfisto

  • Скриптер
  • Главный Модератор
  • Новичок
  • *****
  • Сообщений: 176
  • Репутация: +19/-0
  • Не пью, не курю, за компьютером сижу...
    • mfistof
    • Просмотр профиля
    • Empire of CJ
Re: Написание плагина. Настройка проекта
« Ответ #69 : Август 31, 2016, 12:31:25 am »
Есть плагин fastman92 лимит-аджастер. Там тоже есть попытка сделать дополнительные модели. Проект отличный, можно расширять карту, воду, кол-во авто итд. Так вот к чему это я, может вам объединиться с ним касательно части новых фишек для авто. Возможно его дело пойдет быстрее.
I know everything and nothing...

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #70 : Сентябрь 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 и угол, на который должны открываться у неё фары?

Оффлайн DK

  • Новичок
  • **
  • Сообщений: 234
  • Репутация: +328/-0
    • dk22pac
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #71 : Сентябрь 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.
Plugin-SDK https://github.com/DK22Pac/plugin-sdk

Discord-сервер по plugin-sdk и программированию в GTA
RU https://discord.gg/QEesDGb
ENG https://discord.gg/zaVqFQv

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #72 : Сентябрь 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);


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


Оффлайн DK

  • Новичок
  • **
  • Сообщений: 234
  • Репутация: +328/-0
    • dk22pac
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #73 : Сентябрь 02, 2016, 05:14:35 pm »
Обьяви структуру, которая будет содержать все нужные параметры, и создай вектор для хранения этих структур.
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;
« Последнее редактирование: Сентябрь 02, 2016, 10:10:11 pm от DK »
Plugin-SDK https://github.com/DK22Pac/plugin-sdk

Discord-сервер по plugin-sdk и программированию в GTA
RU https://discord.gg/QEesDGb
ENG https://discord.gg/zaVqFQv

Оффлайн kenking

  • Новичок
  • **
  • Сообщений: 237
  • Репутация: +16/-0
    • Просмотр профиля
Re: Написание плагина. Настройка проекта
« Ответ #74 : Сентябрь 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 ==========

По второму примеру всё отлично, за исключением того, что проекция на поверхности стоит под одним и тем же углом, т.е. не поворачивается вместе с авто. Это заметно, если сделать проекцию овальной, а не круглой или заменить текстуру на квадратную. Можно это, как-то исправить? У Дениса в скрипте проекция поворачивается вместе с авто.