Гайд Продолжение серии. шема(оффсеты)+локал игрок

Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
774
Реакции[?]
330
Поинты[?]
62K
из-за требований в начале кода: "// c++23 - tested on clang 18.1.5 / msvc 19.40.33808"


нет, м2, но на нём много скульных баз в рантайме


нет, дебаг, так как при попытке собрать релиз 560 ошибок;

вот результат: 6 + 127 + 10 + 41 = 184 / 60 = 3 минуты

schema_registration: 5690ms
printing & saving schema dump: 127322ms
rtti_saving: 9678ms
saving info...
info_saving: 40806ms
дебаг билд для дебаггинга существует а не для быстрой работы. собирай релиз. 560 ошибок у тебя наверно потому что ты с++latest не поставил в релизе(там в настройках проекта сверху можно выбрать конфигурацию и платформу(у каждой связки конфигурация-платформа разные настройки. в этом и вся их суть - дебаг это не магический какойто особенный режим это просто "шаблончик" настроек где выключены всякие оптимизации и тд; релиз тоже самое тоже шаблончик с настройками с оптимизациями и тд))(ты только в дебаге поставил я так понимаю)(можно также выбрать опцию All Configurations - она показывает/разрешает менять настройки со всех конфигураций, можно и на дебаг и на релиз сразу поставить c++latest и тд и тп)
1715526826533.png
и "tested on clang 18.1.5 / msvc 19.40.33808" это не требование это версии на которых я тестил(это самые последние версии компиляторов на данный момент); это не минимальные версии где работает
 
Начинающий
Статус
Оффлайн
Регистрация
14 Янв 2024
Сообщения
31
Реакции[?]
1
Поинты[?]
2K
560 ошибок у тебя наверно потому что ты с++latest не поставил в релизе
да, в релизе стоял 14 стандарт;

новый результат (релиз): 1 + 25 + 1 + 2 = 29 секунд, релиз в ~6 раз быстрее

schema_registration: 1109ms
printing & saving schema dump: 25296ms
rtti_saving: 885ms
saving info...
info_saving: 2285ms
 
Начинающий
Статус
Оффлайн
Регистрация
5 Июн 2024
Сообщения
11
Реакции[?]
3
Поинты[?]
2K
Это очень круто, спасибо что делишься опытом! Может есть смысл сделать CI\CD для автодампа ассетов в gitlab\github?
Можно сделать автозапуск по выходу обновления и тригерить пайплайн
Можешь с Steamdb сколабарироваться и сделать чтобы на каждый новый апдейт дамп делался. Можешь даже просто им написать они мб сами сделают.
Вот этот человек
Пожалуйста, авторизуйтесь для просмотра ссылки.
(вроде один из главных там)
очень интересовался еще старым Source2Gen`ом от прейдога

Учитывая что достаточно дллок и запуск игры не нужен - можно даже на старые версии попробовать сделать, только сигнатура будет ломаться.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
774
Реакции[?]
330
Поинты[?]
62K
дамп от Thu Aug 08 2024 22:32:59
Пожалуйста, авторизуйтесь для просмотра ссылки.
добавил более детальный дамп CEntityClass
если кому-то надо структурки:
C++:
struct datamapField
{
    CSchemaClassBinding* enum_binding;
    const char* name;
    std::int16_t offset;
    std::int16_t unk;
    std::int8_t type;
};

struct EntInput_t
{
    const char* name;
    std::uint32_t unk1;
    std::uint32_t pad;
    union unk
    {
#pragma pack(push, 1)
        struct netvar_info_
        {
            std::uint8_t unk2;
            std::uint16_t netvar_offset;
        } netvar_info;
#pragma pack(pop)
        void* some_struct_ptr;
    } info_stuff;
    void* unk3;
    void* callback;
    void* unk4_func;
};

struct EntOutput_t
{
    const char* name;
    std::uint32_t unk1;
    std::uint32_t CEntityIOOutput_offset;
};

struct EntClassComponentOverride_t
{
    const char* pszBaseComponent;
    const char* pszOverrideComponent;
};

struct CPanoramaGameScriptFunction
{
    const char* name_;
    const char* scoped_name_;
    const char* description_;
    std::string_view name() const
    {
        if (name_)
            return name_;
        return {};
    }
    std::string_view scoped_name() const
    {
        if (scoped_name_)
            return scoped_name_;
        return {};
    }
    std::string_view description() const
    {
        if (description_)
            return description_;
        return {};
    }
    void* unk1;
    void* unk2;
    const char* double_null_terminated_param_list;//'\x00\x00'-terminated
    const char* class_name;
    void* unk3_func;
    void* actual_func;
    void* unk4;
    std::vector<std::string> get_params() const
    {
        std::vector<std::string> result{};
        if (double_null_terminated_param_list)
        {
            auto ptr = double_null_terminated_param_list;
            while (true)
            {
                std::string_view param{ ptr };
                if (param.empty())
                    break;
                ptr = param.data() + param.size() + sizeof('\x00');
                result.emplace_back(param);
            }
        }
        return result;
    }
};

struct CPanoramaGameScriptScope
{
    const char* class_name_;
    const char* class_name2_;
    const char* class_description_;
    std::string_view class_name() const
    {
        if (class_name_)
            return class_name_;
        return {};
    }
    std::string_view class_name2() const
    {
        if (class_name2_)
            return class_name2_;
        return {};
    }
    std::string_view class_description() const
    {
        if (class_description_)
            return class_description_;
        return {};
    }
    CPanoramaGameScriptScope* base_scope;
    CUtlVector<CPanoramaGameScriptFunction> functions;
};

//string xref ...ReferencedPtr
enum class EntityComponent_t : std::uint8_t
{
    ScriptComponent = 0,
    BodyComponentBaseModelEntity = 1,
    BodyComponentBaseAnimGraph = 2,
    PropDataComponent = 3,
    RenderComponent = 4,
    LightComponent = 5,
    HitboxComponent = 6,
    BodyComponentPoint = 7,
    BodyComponentSkeletonInstance = 8,
    BodyComponent = 9,
    _BodyComponentBaseAnimatingOverlay = 0xA,
    _BodyComponentBaseAnimating = 0xB,
};

const char* EntityComponent_t_NAMES[]
{
    "ScriptComponent",
    "BodyComponentBaseModelEntity",
    "BodyComponentBaseAnimGraph",
    "PropDataComponent",
    "RenderComponent",
    "LightComponent",
    "HitboxComponent",
    "BodyComponentPoint",
    "BodyComponentSkeletonInstance",
    "BodyComponent",
    "_BodyComponentBaseAnimatingOverlay",
    "_BodyComponentBaseAnimating",
};

const char* stringify_EntityComponent_t(std::uint8_t val)
{
    if (val >= std::size(EntityComponent_t_NAMES))
    {
        return "";
    }
    return EntityComponent_t_NAMES[val];
}

class CEntityClass
{
public:
    CPanoramaGameScriptScope* m_pPanoramaGameScriptScope; //0x0000
    EntInput_t* m_pInputs; //0x0008
    EntOutput_t* m_pOutputs; //0x0010
    uint32_t m_nInputCount; //0x0018
    uint32_t m_nOutputCount; //0x001C
    EntClassComponentOverride_t* m_pComponentOverrides; //0x0020
    CEntityClassInfo* m_pClassInfo; //0x0028
    CEntityClassInfo* m_pBaseClassInfo; //0x0030
    const char* m_designerName; //0x0038
    void* unk1;//0x40
    std::uint32_t m_flags;//0x48
    std::uint32_t m_nAllHelpersFlags;//0x4C
    CUtlVector<std::int16_t> m_ComponentOffsets; //0x0050
    CUtlVector<void*> m_AllHelpers; //0x0068
    void* BaseClassPlus80; //0x0080
    void* unk2;//0x0088
    datamapField* m_pDataMapFields;//0x0090
    void* unk4;//0x0098
    void* unk5;//0x00A0
    std::uint16_t m_iDataMapFieldCount;//0xA8
    std::uint16_t unk6;//0xAA
    std::uint16_t unk7;//0xAC
    std::uint16_t unk8;//0xAE
    const char* m_pszScopedName; //0x00B0
    FlattenedSerializerHandle_t* m_pFlattenedSerializer; //0x00B8
    CUtlVector<void*> EntInputMap_StringToEntInput_t;//0x00C0
    void* unk9;//0x00D8
    void* unk10;//0x00E0
    void* unk11;//0x00E8
    std::int32_t m_requiredEHandle;//0x00F0
    std::uint32_t pad;//0x00F4
    CEntityClass* m_pForwardLinkNextClass; //0x00F8
    CEntityIdentity* m_pNextClass; //0x0100
    CEntityClassNetworkInstance* m_pNetworkInstance; //0x0108
    auto inputs() const
    {
        return std::span{ m_pInputs, m_nInputCount };
    }
    auto outputs() const
    {
        return std::span{ m_pOutputs, m_nOutputCount };
    }
    auto datamap_fields() const
    {
        return std::span{ m_pDataMapFields, m_iDataMapFieldCount };
    }
};

class CEntityClassNetworkInstance
{
public:
    const char* m_pszClientName;
    const char* m_pszServerName;
    CEntityClass* m_pClass;
    const char* m_pszScopedName;
    FlattenedSerializerHandle_t* m_pSerializerHandle;
    std::int32_t m_ClassID;
    std::int32_t m_iRuntimeIndex;
    void* unk1;
    void* unk2;
};
class CEntityClassInfo
{
public:
    const char* m_pszClassname; //0x0000
    const char* m_pszCPPClassname; //0x0008
    const char* m_pszDescription; //0x0010
    CEntityClass* m_pClass; //0x0018
    CEntityClassInfo* m_pBaseClassInfo; //0x0020
    CSchemaClassBinding* m_pSchemaClassBinding; //0x0028
    void* m_pDataDescMap; //0x0030
    void* m_pPredDescMap; //0x0038
};

struct FlattenedSerializerHandle_t
{
    const char* m_pName;
    CFlattenedSerializer* serializer;
};

enum NetworkFieldChangeCallbackType : std::uint8_t
{
    OBJPTR_OBJPTR = 1,
    OBJPTR_OBJPTR_NEWVALUEPTR = 2,
    OBJPTR = 3,
    UNK_MOVRCX_MOVRDX_MOVR8D_MOVR9 = 4,
    UNK_MOVRCX_MOVRDX_MOVR8D = 5,
    UNK_MOVRCX_LEARDX = 6,
    UNK_MOVRCX_LEARDX_MOVR8 = 7,
};

struct NetworkFieldChangeCallback_t
{
    void* unk1{};
    void* fn_callback{};
    const char* name{};
    std::uint16_t unk2{};
    std::uint16_t unk3{};
    std::uint16_t unk4{};
    NetworkFieldChangeCallbackType callback_type{};
    std::uint8_t pad{};
    void* unk5{};
    std::uint32_t unk6{};
};

struct CFlattenedSerializer
{
    struct NetVarInfo
    {
        const char* name_;
        CSchemaClassBinding* type_binding;
        void* unk1;
        std::int16_t offset;
        std::int16_t maybe_flags1;
        std::int32_t maybe_flags2;
        void* unk2;
        void* unk3;
        void* unk4;
        void* unk5;
        std::int32_t unk6;
        std::int32_t unk7;
        void* unk8;
        void* unk9;
        void* unk10;
        CUtlVector<NetworkFieldChangeCallback_t>* m_pNetVarChangeCallbacks;
        void* unk11;
        void* unk12;
        void* unk13;
        void* unk14;
        const char* m_pClassName;
        const char* m_pNetvarTypeName;
        void* unk15;
        void* unk16;
        void* unk17;
        std::string_view name() const noexcept
        {
            if (name_)
                return { name_ };
            return {};
        }
        std::string_view type_name() const noexcept
        {
            if (m_pNetvarTypeName)
                return { m_pNetvarTypeName };
            return {};
        }
    };

    const char* m_pName;
    CSchemaClassBinding* m_pSchemaClassBinding;
    CUtlVector<NetVarInfo*> netvars;
};
списки классов есть либо в CNetworkGameClient, либо в CEntity2NetworkClasses(указатель на нее есть в CGameEntitySystem, на 0x1538 вроде).
нетворк сериалайзеры есть либо в CFlattenedSerializers, либо в ентити классах.
прежде всего можно регать свои коллбеки на изменение нетвара или менять оффсеты нетваров(дота берет оффсеты из нетворк сериалазйеров), например для того же вбе
PoC вбе(особо не тестил но вроде работает)
C++:
struct test_cb
{
    CUtlVector<NetworkFieldChangeCallback_t> vec{};
    NetworkFieldChangeCallback_t cb{};

    test_cb(const char* name, void* fn)
    {
        vec.capacity = 1;
        vec.data = &cb;
        vec.size = 1;
        cb.name = name;
        cb.fn_callback = fn;
        cb.callback_type = NetworkFieldChangeCallbackType::OBJPTR_OBJPTR_NEWVALUEPTR;
    }
};
void(*ConMsg)(const char*, ...) = nullptr;
test_cb cb
{
    "MyTestCallback",
    +[](void* entity, void* _, std::uint32_t* new_val)
    {
        ConMsg("entity 0x%p value %d\n", entity, *new_val);
    }
};
...
    for (const auto& ni : nc)
    {
        if (ni && ni->m_pszClientName && ni->m_pClass)
        {
            const auto& cls = *ni->m_pClass;
            if (cls.m_pFlattenedSerializer)
            {
                if (cls.m_pFlattenedSerializer->serializer)
                {
                    const auto& netvars = cls.m_pFlattenedSerializer->serializer->netvars.span();
                    if (!netvars.empty())
                    {
                        for (const auto& netvar : netvars)
                        {
                            if (netvar)
                            {
                                if (!netvar->name().empty())
                                {
                                    if (netvar->name() == "m_iTaggedAsVisibleByTeam")
                                    {
                                        netvar->m_pNetVarChangeCallbacks = &cb.vec;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 
Последнее редактирование:
Сверху Снизу