Подмена машин с Plugin SDK для одиночной игры

Mothman

Новичок
Автор темы
4
1
Насколько реально через Plugin SDK реализовать подмену создаваемых игрой машин в момент спавна в трафике, грубо говоря чтобы при спавне такси 420 спавнились рандомные машины из набора 445, 466, 516?
Я пробовал через Events::vehicleSetModelEvent, но чтобы не делал - ловил краши в момент создания модели, хотя перед этим загружал её в память, но нифига не вышло

UPD: Почти удалось с использованием следующего кода:
C++:
#include <windows.h>
#include "CCarCtrl.h"
#include "CVehicle.h"
#include "CStreaming.h"
#include "MinHook.h"

// Линкуем MinHook
#pragma comment(lib, "MinHook.x86.lib")

// Прототип оригинальной функции
typedef CVehicle* (__cdecl* GetNewVehicleDependingOnCarModel_t)(int modelId, unsigned char createdBy);
GetNewVehicleDependingOnCarModel_t pOrigGetNewVehicleDependingOnCarModel = nullptr;

// Наш хук
CVehicle* __cdecl Hooked_GetNewVehicleDependingOnCarModel(int modelId, unsigned char createdBy) {

    // Проверяем, что это именно случайный городской трафик (1 = RANDOM_CAR)
    // Благодаря этому миссии (2) и припаркованные авто (3) не сломаются
    if (createdBy == 1) {
        modelId = 400;

        // Проверяем, загружена ли модель в память игры
        if (!CStreaming::HasModelLoaded(modelId)) {
            // Запрашиваем модель с высоким приоритетом
            CStreaming::RequestModel(modelId, 2);
            // Заставляем стриминг мгновенно загрузить её из gta3.img
            CStreaming::LoadAllRequestedModels(false);
        }

        // Защита от вылета 0x004C9691: если модель почему-то не загрузилась
        // (например, критический затык стриминга), спавним оригинал во избежание краша
        if (!CStreaming::HasModelLoaded(modelId)) {
            return pOrigGetNewVehicleDependingOnCarModel(modelId, createdBy);
        }

        // Разрешаем игре удалить модель если не нужна
        CStreaming::SetModelIsDeletable(modelId);
    }

    // Передаем управление в оригинальный движок
    return pOrigGetNewVehicleDependingOnCarModel(modelId, createdBy);
}

void InitHooks() {
    // Инициализируем MinHook
    if (MH_Initialize() != MH_OK && MH_Initialize() != MH_ERROR_ALREADY_INITIALIZED) {
        return;
    }

    // Ставим хук на CCarCtrl::GetNewVehicleDependingOnCarModel (0x421440)
    void* target = (void*)0x421440;
    if (MH_CreateHook(target, reinterpret_cast<void*>(&Hooked_GetNewVehicleDependingOnCarModel), reinterpret_cast<void**>(&pOrigGetNewVehicleDependingOnCarModel)) == MH_OK) {
        MH_EnableHook(target);
    }
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        InitHooks();
    }
    return TRUE;
}
Но есть один нюанс: если модель 400 загружена в память до появления первой рандомной машины, то всё работает и весь трафик в одних Лендсталкерах. Если же я пытаюсь хоть как-то взаимодействовать с CStreaming, при этом даже просто проверяя загружена ли модель - игра нахуй вылетает. Как это исправить? И да, я использовал в том числе и нейронку, чтобы дойти до такого результата
 
Последнее редактирование:

Mothman

Новичок
Автор темы
4
1
как будто бы проще поставить хук на CVehicle::SetModelIndex и в аргументе подменять ID модели
Попробую, но пока самым оптимальным вариантом кажется CCarCtrl::GetNewVehicleDependingOnCarModel, так как он позволяет ловить именно машины из траффика не трогая созданные системой парковок, скриптами и т.п. И метод реально рабочий, но только если модель уже загружена в память. А любое взаимодействие с CStreaming, даже CStreaming::HasModelLoaded шлёт меня нах почему-то
 
  • Нравится
Реакции: вайега52