[ARZ] API для работы с моделями из новых аттачей

SR_team

like pancake
Автор темы
BH Team
4,807
6,491
В начале этого (2024) года, на аризоне появилась новая система загрузки моделей для аттачей. Нужна она что бы не разруливать конфликты FLA и SAMP. Данная система предоставляет альтернативные id для создания объектов.

Объекты прописываются в json файле arizona/NamedModels.json.
Загрузить и использовать модели из своего кода можно воспользовавшись функциями экспортируемыми из vorbisFile.dll. Объявление функций приложено ниже в аттаче.

is_simple_model_existsПроверяет, что модель с данным id прописана в json
get_simple_models_countРазмер пула моделей (для перебора всех). В пуле могут быть пробелы!
request_simple_model_loadАсинхронный запрос на загрузку модели. После него надо подождать, пока модель загрузится
load_simple_modelЗагрузка модели с блокировкой основного потока. Ждать загрузки не надо, но будет микрофриз, как с самповскими объектами
unload_simple_modelУдаление модели
get_simple_modelПолучение указателя на CBaseModelInfo модели (вернет NULL, если модель еще не загружена)
get_simple_model_infoПолучение информации о модели (используемые DFF, TXD, etc...)
find_simple_models_by_nameПоиск id'ов по названию DFF. (например можно найти все ретекстуры часов, использующие общую модель)

Алсо, по загрузке моделей. Под капотом все модели shared_ptr, и запросы на загрузку не теряются. Соответственно, после первого запроса на загрузку, модель 100% загрузится и повторять запрос не надо, если вы не вызывали выгрузку модели. Т.к. shared_ptr не отдается наружу (из-за возможных различий в ABI), то его счетчик инткерминтируется/декриминтируется при запросах на загрузку/выгрузку моделей.
 

Вложения

  • SimpleModelLoaderAPI.zip
    1.4 KB · Просмотры: 72

Lance_Sterling

Известный
989
351
круто, модель я загрузил, а как создать теперь объект? айди отличаются в списке и в игре
1727720516741.png

1727720595485.png

подгружаю модель, возвращает true
эмулирую аттач этого объекта
1727720552885.png

чота нихуя не получается, мне лень отслеживать неизвестные рпц/пакеты, чо делать, есть функции?

@SR_team
 

SR_team

like pancake
Автор темы
BH Team
4,807
6,491
круто, модель я загрузил, а как создать теперь объект? айди отличаются в списке и в игре
Посмотреть вложение 253189
Посмотреть вложение 253191
подгружаю модель, возвращает true
эмулирую аттач этого объекта
Посмотреть вложение 253190
чота нихуя не получается, мне лень отслеживать неизвестные рпц/пакеты, чо делать, есть функции?

@SR_team
На сайте серверные id'ы. Данное API предоставляет тебе доступ к CBaseModelInfo модели. Через него например можно создать кламп/атомик вызвав функцию CBaseModelInfo::CreateInstance. И уже кламп/атомик можно рендерить
 
  • Нравится
Реакции: Lance_Sterling

chapo

чопа сребдс // TG/IG: @moujeek
Модератор
9,034
11,876
@SR_team, есть ли возможность получить айди подгруженного объекта для того что бы в дальнейшем например создать его на карте через createObject?
Пробовал так, но всегда получаю -1;
Lua:
local ffi = require('ffi');

ffi.cdef([[
    typedef struct CBaseModelInfo CBaseModelInfo;
    #pragma pack(push, 8);
    struct CBaseModelInfo {
        void* vtbl;
        unsigned int m_dwKey;
        short m_wUsageCount;
        short m_wTxdIndex;
        char m_nAlpha;
        char m_n2dfxCount;
        short m_w2dfxIndex;
        short m_wObjectInfoIndex;
        unsigned __int16 m_nMdlFlags;
        struct CColModel *m_pColModel;
        float m_fDrawDistance;
        struct RpClump *m_pRwObject;
    };
    #pragma pack(pop);

    bool is_simple_model_exists( int modelId );
    bool load_simple_model( int modelId );
    CBaseModelInfo *get_simple_model( int modelId );
]]);

local vorbis = ffi.load('vorbisFile.dll');

local CModelInfo__ms_modelInfoPtrs = ffi.cast("CBaseModelInfo**", ffi.cast("uintptr_t*", 0x40122D)[0]);

function GetModelIndexByCBaseModelInfo(pModelInfo, nMin, nMax)
    assert(pModelInfo, 'pModelInfo is NULL');
    local targetKey = pModelInfo.m_dwKey;
    for i = nMin, nMax do
        print('iter', i);
        local pModel = CModelInfo__ms_modelInfoPtrs[i];
        if (pModel ~= nil) then
            print('iter-result', i, pModel.m_dwKey, targetKey);
            if (pModel.m_dwKey == targetKey) then
                return i
            end
        end
    end

    return -1;
end

local simpleModelId = 368;
local SimpleModel = {
    isModelExists = vorbis.is_simple_model_exists,
    loadModel = vorbis.load_simple_model,
    getModel = vorbis.get_simple_model
};

 sampRegisterChatCommand('aa', function()
        if (not SimpleModel.isModelExists(simpleModelId)) then
            return sampAddChatMessage('SimpleModel // Model not exists', -1);
        end
        local wasModelLoaded = SimpleModel.loadModel(simpleModelId);
        if (not wasModelLoaded) then
            return sampAddChatMessage('SimpleModel // Model was not loaded', -1);
        end
        print('loadModel', wasModelLoaded);
        local model = SimpleModel.getModel(simpleModelId);
        print('getModel', model, 'm_dwKey =', model.m_dwKey, string.format("0x%X", model.m_dwKey));
        print('Model', model.m_wObjectInfoIndex);
        print('GetModelIndexByCBaseModelInfo', GetModelIndexByCBaseModelInfo(model, 0, 24299)); -- 24299 from limit adjuster config
    end);
 

SR_team

like pancake
Автор темы
BH Team
4,807
6,491
@SR_team, есть ли возможность получить айди подгруженного объекта для того что бы в дальнейшем например создать его на карте через createObject?
Пробовал так, но всегда получаю -1;
Lua:
local ffi = require('ffi');

ffi.cdef([[
    typedef struct CBaseModelInfo CBaseModelInfo;
    #pragma pack(push, 8);
    struct CBaseModelInfo {
        void* vtbl;
        unsigned int m_dwKey;
        short m_wUsageCount;
        short m_wTxdIndex;
        char m_nAlpha;
        char m_n2dfxCount;
        short m_w2dfxIndex;
        short m_wObjectInfoIndex;
        unsigned __int16 m_nMdlFlags;
        struct CColModel *m_pColModel;
        float m_fDrawDistance;
        struct RpClump *m_pRwObject;
    };
    #pragma pack(pop);

    bool is_simple_model_exists( int modelId );
    bool load_simple_model( int modelId );
    CBaseModelInfo *get_simple_model( int modelId );
]]);

local vorbis = ffi.load('vorbisFile.dll');

local CModelInfo__ms_modelInfoPtrs = ffi.cast("CBaseModelInfo**", ffi.cast("uintptr_t*", 0x40122D)[0]);

function GetModelIndexByCBaseModelInfo(pModelInfo, nMin, nMax)
    assert(pModelInfo, 'pModelInfo is NULL');
    local targetKey = pModelInfo.m_dwKey;
    for i = nMin, nMax do
        print('iter', i);
        local pModel = CModelInfo__ms_modelInfoPtrs[i];
        if (pModel ~= nil) then
            print('iter-result', i, pModel.m_dwKey, targetKey);
            if (pModel.m_dwKey == targetKey) then
                return i
            end
        end
    end

    return -1;
end

local simpleModelId = 368;
local SimpleModel = {
    isModelExists = vorbis.is_simple_model_exists,
    loadModel = vorbis.load_simple_model,
    getModel = vorbis.get_simple_model
};

 sampRegisterChatCommand('aa', function()
        if (not SimpleModel.isModelExists(simpleModelId)) then
            return sampAddChatMessage('SimpleModel // Model not exists', -1);
        end
        local wasModelLoaded = SimpleModel.loadModel(simpleModelId);
        if (not wasModelLoaded) then
            return sampAddChatMessage('SimpleModel // Model was not loaded', -1);
        end
        print('loadModel', wasModelLoaded);
        local model = SimpleModel.getModel(simpleModelId);
        print('getModel', model, 'm_dwKey =', model.m_dwKey, string.format("0x%X", model.m_dwKey));
        print('Model', model.m_wObjectInfoIndex);
        print('GetModelIndexByCBaseModelInfo', GetModelIndexByCBaseModelInfo(model, 0, 24299)); -- 24299 from limit adjuster config
    end);
Весь смысл этой кастомной системы моделей в том, что она не занимает id в ms_modelInfoPtrs. Вместо createObject можно использовать CBaseModelInfo::CreateInstance, но он вернет голый RpClump/RpAtomic - рендерить его нужно самому, типа atomic->renderCallback(atomic); или RpClumpRender(clump);
 
  • Влюблен
Реакции: chapo