Вопрос Проверка класса сущности

Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
324
Реакции[?]
24
Поинты[?]
12K
Как эффективно проверять приналежность объекта к своему классу?
Ну вот я делаю итерацию например стандартным методом :
C++:
for(const C_BaseEntity* ent = EntitySystem->GetBaseEntity(i++); i <GetHighestEntityIndex(); ent = EntitySystem->GetBaseEntity(i))
{
...
}
Я лично делаю через проверку и сравнение строки entity->instance->0x8->0x0->0x0 с 'C_DOTA_BaseNPC_Hero'

Есть ли другие варианты ещё? Заметил что вроде как есть поле C_DOTA_BaseNPC::m_iUnitType.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
779
Реакции[?]
331
Поинты[?]
63K
вот это то что ты написал entity->instance->0x8->0x0->0x0
это (мои названия. хз как по факту называется) у айдентити лежит на 0x8 ClassTemplate*, там есть всякое говно включая шема биндинг класса, можешь там покопаться. там инфа вроде есть о бейз классе
C++:
class ClassInfo
{
    const char* name_1{};
    const char* name_2{};
    const char* name_3{};
    ClassTemplate* cls_template{};
    ClassInfo* base_class{};
    CSchemaClassBinding* binding{};
};

class ClassTemplate//na (identity + 8) lezhit ukazatel na eto
{
    void* some_base_shit_unk{};
    void* unk_1{};
    void* unk_2{};
    void* unk_3{};
    void* unk_4{};
    ClassInfo* class_info{};//tut binding est'
    //at 0x108 is ClassMetaDef* metadef;
};

class ClassMetaDef
{
    const char* server_name{};
    const char* client_name{};
    ClassTemplate* class_template{};
    const char* scoped_name{};
    void* unk{};
    std::uint32_t id{};
public:
    std::string_view GetClientName() const noexcept
    {
        if (!client_name)
            return {};
        return client_name;
    }
    const auto& GetClassTemplate() const
    {
        if (!class_template)
            throw std::runtime_error{std::format(R"(ClassMetaDef::class_template is nullptr for "{}"!)", GetClientName())};
        return *class_template;
    }
};
можешь по именам в шема биндингах сравнивать
C++:
bool helper_check_hierarchy_for_name(const CSchemaClassBinding& binding, std::string_view name) noexcept
{
    for (const auto& parent_node : binding.GetParents())
    {
        if (const auto* parent = parent_node.GetParent(); parent)
        {
            if (parent->GetName() == name || helper_check_hierarchy_for_name(*parent, name))
                return true;
        }
    }
    return false;
}
... entity vvv ...
    bool IsInstanceOfClass(std::string_view cls) const
    {
        const auto& binding = GetBinding();
        if (binding.GetName() == cls)
            return true;
        else
            return helper_check_hierarchy_for_name(binding, cls);
        return false;
    }
а по факту если хочешь можешь заранее часто встречающиеся биндинги из шемы брать определенных классов(крип хуип и так далее) и сразу напрямую сравнивать указатели в классинфо.
либо можешь тем же самым путём пойти и темплейты а не биндинги сравнивать. метадефы лежат в таблице в CNetworkGameClient, в метадефе есть указатель на темплейту
 
Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
324
Реакции[?]
24
Поинты[?]
12K
вот это то что ты написал entity->instance->0x8->0x0->0x0
это (мои названия. хз как по факту называется) у айдентити лежит на 0x8 ClassTemplate*, там есть всякое говно включая шема биндинг класса, можешь там покопаться. там инфа вроде есть о бейз классе
C++:
class ClassInfo
{
    const char* name_1{};
    const char* name_2{};
    const char* name_3{};
    ClassTemplate* cls_template{};
    ClassInfo* base_class{};
    CSchemaClassBinding* binding{};
};

class ClassTemplate//na (identity + 8) lezhit ukazatel na eto
{
    void* some_base_shit_unk{};
    void* unk_1{};
    void* unk_2{};
    void* unk_3{};
    void* unk_4{};
    ClassInfo* class_info{};//tut binding est'
    //at 0x108 is ClassMetaDef* metadef;
};

class ClassMetaDef
{
    const char* server_name{};
    const char* client_name{};
    ClassTemplate* class_template{};
    const char* scoped_name{};
    void* unk{};
    std::uint32_t id{};
public:
    std::string_view GetClientName() const noexcept
    {
        if (!client_name)
            return {};
        return client_name;
    }
    const auto& GetClassTemplate() const
    {
        if (!class_template)
            throw std::runtime_error{std::format(R"(ClassMetaDef::class_template is nullptr for "{}"!)", GetClientName())};
        return *class_template;
    }
};
можешь по именам в шема биндингах сравнивать
C++:
bool helper_check_hierarchy_for_name(const CSchemaClassBinding& binding, std::string_view name) noexcept
{
    for (const auto& parent_node : binding.GetParents())
    {
        if (const auto* parent = parent_node.GetParent(); parent)
        {
            if (parent->GetName() == name || helper_check_hierarchy_for_name(*parent, name))
                return true;
        }
    }
    return false;
}
... entity vvv ...
    bool IsInstanceOfClass(std::string_view cls) const
    {
        const auto& binding = GetBinding();
        if (binding.GetName() == cls)
            return true;
        else
            return helper_check_hierarchy_for_name(binding, cls);
        return false;
    }
а по факту если хочешь можешь заранее часто встречающиеся биндинги из шемы брать определенных классов(крип хуип и так далее) и сразу напрямую сравнивать указатели в классинфо.
либо можешь тем же самым путём пойти и темплейты а не биндинги сравнивать. метадефы лежат в таблице в CNetworkGameClient, в метадефе есть указатель на темплейту
Там мне бы хотелось чтото легкое, просто чтобы узнать является ли данная сущность героем или крипом. Я смотрел в джаваскриптовые, и там какая-то непонятная херня вызывается.

Ну да, я по твоему старому гайду делал так собственно.
C++:
bool C_BaseEntity::IsHero()
{
    return !strcmp(this->instance->ClassData->Data->BaseClass, "C_DOTA_BaseNPC_Hero");
}
По твоему это лучший способ проверки?
 
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
вот это то что ты написал entity->instance->0x8->0x0->0x0
это (мои названия. хз как по факту называется) у айдентити лежит на 0x8 ClassTemplate*, там есть всякое говно включая шема биндинг класса, можешь там покопаться. там инфа вроде есть о бейз классе
Код:
class ClassInfo
{
    const char* name_1{};
    const char* name_2{};
    const char* name_3{};
    ClassTemplate* cls_template{};
    ClassInfo* base_class{};
    CSchemaClassBinding* binding{};
};

class ClassTemplate//na (identity + 8) lezhit ukazatel na eto
{
    void* some_base_shit_unk{};
    void* unk_1{};
    void* unk_2{};
    void* unk_3{};
    void* unk_4{};
    ClassInfo* class_info{};//tut binding est'
    //at 0x108 is ClassMetaDef* metadef;
};

class ClassMetaDef
{
    const char* server_name{};
    const char* client_name{};
    ClassTemplate* class_template{};
    const char* scoped_name{};
    void* unk{};
    std::uint32_t id{};
public:
    std::string_view GetClientName() const noexcept
    {
        if (!client_name)
            return {};
        return client_name;
    }
    const auto& GetClassTemplate() const
    {
        if (!class_template)
            throw std::runtime_error{std::format(R"(ClassMetaDef::class_template is nullptr for "{}"!)", GetClientName())};
        return *class_template;
    }
};
можешь по именам в шема биндингах сравнивать
C++:
bool helper_check_hierarchy_for_name(const CSchemaClassBinding& binding, std::string_view name) noexcept
{
    for (const auto& parent_node : binding.GetParents())
    {
        if (const auto* parent = parent_node.GetParent(); parent)
        {
            if (parent->GetName() == name || helper_check_hierarchy_for_name(*parent, name))
                return true;
        }
    }
    return false;
}
... entity vvv ...
    bool IsInstanceOfClass(std::string_view cls) const
    {
        const auto& binding = GetBinding();
        if (binding.GetName() == cls)
            return true;
        else
            return helper_check_hierarchy_for_name(binding, cls);
        return false;
    }
а по факту если хочешь можешь заранее часто встречающиеся биндинги из шемы брать определенных классов(крип хуип и так далее) и сразу напрямую сравнивать указатели в классинфо.
либо можешь тем же самым путём пойти и темплейты а не биндинги сравнивать. метадефы лежат в таблице в CNetworkGameClient, в метадефе есть указатель на темплейту
0x8 - CEntityClass

C++:
class CEntityClassInfo
{
public:
    const char          *m_pszClassname;        // 0x0000
    const char          *m_pszCPPClassname;     // 0x0008
    const char          *m_pszDescription;      // 0x0010
    CEntityClass        *m_pClass;              // 0x0014
    CEntityClassInfo    *m_pBaseClassInfo;      // 0x0018
    CSchemaClassBinding *m_pSchemaClassBinding; // 0x0028
    PAD(16)                                     // 0x0030
};                                              // Size: 0x0040
static_assert(sizeof(CEntityClassInfo) == 0x40);

class CEntityClass
{

    CPanoramaGameScriptScope* m_pPanoramaGameScriptScope;
    // Тут пады сами соберете.
    CEntityClassInfo   *m_pClassInfo;                                    // 0x0028
    CEntityClassInfo   *m_pBaseClassInfo;                                // 0x0030
};
В общем, структура очень полезная и там если расковырять фулл структуру, не нужно будет сравнять по имени или сверять хеши что ты заранее сделаешь на компил-тайме название биндингов. Помимо всего остального там очень много другого полезного, что может очень сильно бустать, но это уже другая история.

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

Ну да, я по твоему старому гайду делал так собственно.
C++:
bool C_BaseEntity::IsHero()
{
    return !strcmp(this->instance->ClassData->Data->BaseClass, "C_DOTA_BaseNPC_Hero");
}
По твоему это лучший способ проверки?
Тогда уж так, если лень реверсить и думать. Выбери лучший хешер, что умеет в норм скорость и сиди сверяй.
(Или ебани сверку по TypeName vftable :), так же по компайл тайму хешеру, в общем способов куча, главное желание.)

C++:
bool IsHero() {
    return HASH(GetSchemaBindingClass()->GetName()) == COMPILETIME_HASH("C_DOTA_BaseNPC_Hero"))
}
 
Последнее редактирование:
Сверху Снизу