Гайд Сущности в доте для чайников

🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
Спасибо, а где взять CEntityIdentity, Member? И что за C_BaseEntity, просто класс или шо?
Посмотреть вложение 208491
Мужик, ну тут уже тебе буквально пасту вкинули.

CBaseEntity - можно считать основой всех ентити. Класс от которого идет Inheritance, пример (это прямо с моего сдкгена).
C++:
// Aligment: 183
// Size: 6216
class C_DOTA_BaseNPC : public C_NextBotCombatCharacter, C_BaseCombatCharacter, C_BaseFlex, C_BaseAnimatingOverlay, C_BaseAnimating, C_BaseModelEntity, C_BaseEntity, CEntityInstance, IHandleEntity
Вот тебе с анти-пастой маленькой класс CEntityIdentity

C++:
// Aligment: 11
// Size: 120
class CEntityIdentity
{
public:
    // MNetworkEnable
    // MNetworkChangeCallback "entityIdentityNameChanged"
    int32_t m_nameStringableIndex; // 0x14
    CUtlSymbolLarge m_name; // 0x18
    CUtlSymbolLarge m_designerName; // 0x20
    uint32_t m_flags; // 0x30
    uint32_t m_fDataObjectTypes; // 0x38
    // MNetworkDisable
    // MNetworkChangeAccessorFieldPathIndex
    ChangeAccessorFieldPathIndex_t m_PathIndex; // 0x3c
    CEntityIdentity* m_pPrev; // 0x50
    CEntityIdentity* m_pNext; // 0x58
    CEntityIdentity* m_pPrevByClass; // 0x60
    CEntityIdentity* m_pNextByClass; // 0x68
    V_uuid_t* m_pId; // 0x70
};
Я не знаю точно, но предполагаю что Member это что-то типо
C++:
template <typename T>
T Member(std::uintptr_t offset)
{
    return reinterpret_cast<T>(reinterpret_cast<std::uintptr_t>(this) + offset);
}
Интересно, как ты реализовал SchemaMember, ты на инициализации хака проходишь по всей схеме и делаешь класс-хранитель что все хранит, так как ты сделал или же дергаешь в рантайме из схемы?


Просто у меня примерно такое же.

Я взял std::unordered_map<std::uintptr_t, std::uintptr_t>, в него первым парамом hash строки "client.dll\C_BaseEntity\m_iHealth" и второй оффсет.
 
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
760
Реакции[?]
328
Поинты[?]
60K
Мужик, ну тут уже тебе буквально пасту вкинули.

CBaseEntity - можно считать основой всех ентити. Класс от которого идет Inheritance, пример (это прямо с моего сдкгена).
C++:
// Aligment: 183
// Size: 6216
class C_DOTA_BaseNPC : public C_NextBotCombatCharacter, C_BaseCombatCharacter, C_BaseFlex, C_BaseAnimatingOverlay, C_BaseAnimating, C_BaseModelEntity, C_BaseEntity, CEntityInstance, IHandleEntity
Вот тебе с анти-пастой маленькой класс CEntityIdentity

C++:
// Aligment: 11
// Size: 120
class CEntityIdentity
{
public:
    // MNetworkEnable
    // MNetworkChangeCallback "entityIdentityNameChanged"
    int32_t m_nameStringableIndex; // 0x14
    CUtlSymbolLarge m_name; // 0x18
    CUtlSymbolLarge m_designerName; // 0x20
    uint32_t m_flags; // 0x30
    uint32_t m_fDataObjectTypes; // 0x38
    // MNetworkDisable
    // MNetworkChangeAccessorFieldPathIndex
    ChangeAccessorFieldPathIndex_t m_PathIndex; // 0x3c
    CEntityIdentity* m_pPrev; // 0x50
    CEntityIdentity* m_pNext; // 0x58
    CEntityIdentity* m_pPrevByClass; // 0x60
    CEntityIdentity* m_pNextByClass; // 0x68
    V_uuid_t* m_pId; // 0x70
};
Я не знаю точно, но предполагаю что Member это что-то типо
C++:
template <typename T>
T Member(std::uintptr_t offset)
{
    return reinterpret_cast<T>(reinterpret_cast<std::uintptr_t>(this) + offset);
}


Интересно, как ты реализовал SchemaMember, ты на инициализации хака проходишь по всей схеме и делаешь класс-хранитель что все хранит, так как ты сделал или же дергаешь в рантайме из схемы?


Просто у меня примерно такое же.

Я взял std::unordered_map<std::uintptr_t, std::uintptr_t>, в него первым парамом hash строки "client.dll\C_BaseEntity\m_iHealth" и второй оффсет.
типо того. оффсеты в пачке хранятся(в мапе) и из мапы оффсет беру если он там есть либо получаю из шемы и кладу в мапу. это так просто лайтовый бета альфа дизайн для тестов. на коленях наебашил.
но это конечно говно дизайн, ща нормальный сделаю если не лень будет скину если че
Спасибо, а где взять CEntityIdentity, Member? И что за C_BaseEntity, просто класс или шо?
Посмотреть вложение 208491
CEntityIdentity это элемент энтитисистемы(считай паспорт сущности). у этой хуйни есть указатель на саму сущность(сущность = крип герой абилка итем и тд) то есть хп мана и другие ее свойства). все сущности наследуют от C_BaseEntity. также у CEntityIdentity(паспорт) есть указатель на следующий "паспорт". если он равен нулю значит это последний "паспорт". указатель на первый "паспорт" лежит в энтитисистеме на 0x210. берешь первый паспорт и бегаешь по нему и последующим пока ноль не встретишь, и у каждого берешь и работаешь с сущностью.
все чужие классы(то есть классы приложухи в которую я инжекчусь) наследуют от NormalClass либо от VClass(если это виртуальный класс)
C++:
export
class NormalClass
{
public:
    template<class T>
    auto& Member(std::ptrdiff_t offset) noexcept
    {
        return *reinterpret_cast<T*>(reinterpret_cast<std::uintptr_t>(this) + offset);
    }
    
    template<class T>
    const auto& Member(std::ptrdiff_t offset) const noexcept
    {
        return *reinterpret_cast<const T*>(reinterpret_cast<std::uintptr_t>(this) + offset);
    }
};
C++:
export
class VClass : public NormalClass
{
    VFTable VirtualMethodsTable{};
public:
    VClass() = default;

    explicit VClass(const VFTable& vftable) noexcept : VirtualMethodsTable{ vftable } {}

    template<std::size_t FunctionIndex, typename ReturnType = std::uintptr_t, typename ... ArgTypes>
    ReturnType CallVFunc(ArgTypes... Args) const
    {
        const auto func = VirtualMethodsTable.GetFunctionAt(FunctionIndex);
        if (!func)
            throw std::runtime_error{"CallVFunc -> Func at index is nullptr!"};
        return (static_cast<ReturnType(__thiscall*)(const VClass*, ArgTypes...)>(func))(this, Args...);
    }

    const VFTable& GetVMT() const noexcept
    {
        return VirtualMethodsTable;
    }
};
C++:
export
class VFTable {
    void* VTablePtr{ nullptr };
public:
    VFTable() = default;
    explicit VFTable(void* vmt) noexcept
        :
        VTablePtr{ vmt }
    {}

    VFTable(const VFTable&) = default;
    VFTable& operator=(const VFTable&) = default;

    VFTable(VFTable&& other) noexcept
        :
        VTablePtr{ other.VTablePtr }
    {
        other.VTablePtr = nullptr;
    }
    VFTable& operator=(VFTable&& other) noexcept
    {
        VTablePtr = other.VTablePtr;
        other.VTablePtr = nullptr;
        return *this;
    }
    ~VFTable() = default;

public:
    bool IsValid() const noexcept
    {
        return VTablePtr != nullptr;
    }

    void*& GetFunctionAt(std::size_t index) noexcept
    {
        return *(static_cast<void**>(VTablePtr) + index);
    }
    
    const void*& GetFunctionAt(std::size_t index) const noexcept
    {
        return *(static_cast<const void**>(VTablePtr) + index);
    }

    operator void*() noexcept
    {
        return VTablePtr;
    }

    template<typename ReturnType = decltype(VTablePtr)>
    ReturnType GetPtr() const noexcept
    {
        return SmartCast<ReturnType>(VTablePtr);
    }
};
 
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
типо того. оффсеты в пачке хранятся(в мапе) и из мапы оффсет беру если он там есть либо получаю из шемы и кладу в мапу. это так просто лайтовый бета альфа дизайн для тестов. на коленях наебашил.
но это конечно говно дизайн, ща нормальный сделаю если не лень будет скину если че
Кстати да, над будет тоже сделать попытку цепление из схемы, если в мапе не нашло, а то я прост выбиваю щас рантайм еррор, где внутри какаю хеш нетвера. Для тестов и дебага, самое то, ясен хуй на релизе над будет переделывать.
Код:
throw std::runtime_error(fmt::format("{}: {}", std::source_location::current(), hash);
 
Немодератор раздела «Создание читов Minecraft»
Пользователь
Статус
Оффлайн
Регистрация
20 Янв 2021
Сообщения
356
Реакции[?]
109
Поинты[?]
4K
всё ещё нихуя не понял, да и похуй
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
760
Реакции[?]
328
Поинты[?]
60K
Кстати да, над будет тоже сделать попытку цепление из схемы, если в мапе не нашло, а то я прост выбиваю щас рантайм еррор, где внутри какаю хеш нетвера. Для тестов и дебага, самое то, ясен хуй на релизе над будет переделывать.
Код:
throw std::runtime_error(fmt::format("{}: {}", std::source_location::current(), hash);
чтобы не писать каждый раз эту хуйню лучше ебани кастомный класс исключения наследующий от std::exception сделай ему аргументом в конструкторе
(const std::source_location& loc = std::source_location_current())
и потом просто храни эту локацию и потом при надобности изнутри форматируй. в итоге будет
throw MyException(hash);
...
catch(const MyException& ex) Log(ex.format()) blablabla
там правда баганная хуита эта std::source_location в имплементации майкрософтов особенно с модулями
тем не менее кр4 я сделал эту хуиту(на коленях тоже правда за полчаса) вроде работает.
в ините
std::ranges::for_each(schema_offsets_manager::GetOffsetTable(), schema_offset_interface::fill);
а там где оффсет нужен
C++:
    class m_hAssignedHero : public schema_offset<CHandle<C_DOTA_BaseNPC>, "client.dll/C_DOTAPlayerController/m_hAssignedHero"> {};
    C_DOTA_BaseNPC* GetAssignedHero() const
    {
        const auto handle = SchemaMember2Test<m_hAssignedHero>();
        if (handle.IsValid())
            return CGameEntitySystem::GetInstance().GetEntityByHandle(handle);
        else
            return nullptr;
    }
в итоге если путь оффсета кривой то на ините сразу выдает мол иди нахуй
[Dota2Test] Initialization failed(std::runtime_error): CSchemaRuntimeGetter: netvar not found(client.dll/C_DOTAPXlayerController/m_hAssignedHero)!
а оффсет в итоге статик(то есть прямой доступ без всяких индексов поисков хуюисков резолвов), и один раз только инитится
валидацию правильности на компайл тайме(что два слеша например должно быть и что строка не пустая и тд и тп) не стал делать лень было
C++:
template<char... characters>
constexpr std::size_t helper_string_find_either(const std::string_view& str)
{
    for (std::size_t pos{}; const auto & character : str)
    {
        if (((character == characters) || ...))
            return pos;
        ++pos;
    }
    return std::string_view::npos;
}

constexpr auto split_path_into_relative_paths(const std::string_view& FullPath)
{
    std::vector<std::string> result{};
    std::string_view FullPath_copy{ FullPath };
    std::size_t pos{ helper_string_find_either<'\\', '/'>(FullPath_copy) };
    while (pos != std::string_view::npos)
    {
        if (const auto path = FullPath_copy.substr(0, pos); !path.empty())
            result.push_back(std::string{ path });
        FullPath_copy = FullPath_copy.substr(pos + 1);
        pos = helper_string_find_either<'\\', '/'>(FullPath_copy);
    }
    result.push_back(std::string{ FullPath_copy });
    return result;
}

std::size_t GetOffset(const std::string_view& name)
{
    if (const auto& paths = split_path_into_relative_paths(name); paths.size() == 3)
    {
        const auto& mod = paths.at(0);
        const auto& cls = paths.at(1);
        const auto& var = paths.at(2);

        for (const auto* scope : CSchemaSystem::GetInstance().GetTypeScopes())
        {
            if (scope)
            {
                if (scope->GetName() == mod)
                {
                    for (const auto* Class : scope->GetClasses())
                    {
                        if (Class)
                        {
                            if (Class->GetName() == cls)
                            {
                                for (const auto& member : Class->GetMembers())
                                {
                                    if (member.GetName() == var)
                                    {
                                        return member.GetOffset();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    throw std::runtime_error{ std::format("CSchemaRuntimeGetter: netvar not found({})", name) };
}

export
class schema_offset_interface
{
public:
    virtual void SetOffset(std::ptrdiff_t _offset) noexcept = 0;

    std::string_view name{};
    schema_offset_interface(const std::string_view& _name) : name{ _name } {}

    static void fill(schema_offset_interface* iface)
    {
        iface->SetOffset(GetOffset(iface->name));
    }
};

export
class schema_offsets_manager
{
public:
    static auto& GetOffsetTable()
    {
        static std::vector<schema_offset_interface*> table{};
        return table;
    }
    static void push(schema_offset_interface& obj)
    {
        GetOffsetTable().push_back(&obj);
    }
};

export
template<class X, TemplateStringClass path>
class schema_offset_base : public schema_offset_interface
{
    using schema_offset_interface::schema_offset_interface;

    class registrant
    {
    public:
        registrant()
        {
            static schema_offset_base<X, path> instance{ path };
            schema_offsets_manager::push(instance);
        }
    };
    static inline registrant _registrant{};

public:
    void SetOffset(std::ptrdiff_t _offset) noexcept override { X::GetOffset() = _offset; }
};

export
template<class Type, TemplateStringClass path>
class schema_offset :
    public schema_offset_base<schema_offset<Type, path>, path>
{
public:
    static inline std::ptrdiff_t offset{};
    using TType = Type;
    static auto& GetOffset() noexcept
    {
        return offset;
    }
};
единственное что разве что авторег(аллокация и популяция таблицы с оффсетами) на хипе(std::vector) сделан а не на статике(в модулях сложно его на статике сделать) поэтому может до вызова main кинуть исключение(= не сможешь отреагировать) если оперативки не хватит но с другой стороны если оперативки не хватит тебе и так пизда. ну и авторег в такой форме токо на мсвс работает(на кленге и гсс компилятор оптимизирует член к хуям если на него референса нет, поэтому надо референсить(просто в коде упомянуть его как-нибудь просто чтобы компилятор увидел что это не мусор а задействованный член)) но мне на кленг и гсс похуй потому что они говно по саппорту новых фич версус мсвс
 
Последнее редактирование:
🤡
Пользователь
Статус
Оффлайн
Регистрация
28 Апр 2014
Сообщения
127
Реакции[?]
163
Поинты[?]
21K
чтобы не писать каждый раз эту хуйню лучше ебани кастомный класс исключения наследующий от std::exception сделай ему аргументом в конструкторе
(const std::source_location& loc = std::source_location_current())
и потом просто храни эту локацию и потом при надобности изнутри форматируй. в итоге будет
throw MyException(hash);
...
catch(const MyException& ex) Log(ex.format()) blablabla
там правда баганная хуита эта std::source_location в имплементации майкрософтов особенно с модулями
тем не менее кр4 я сделал эту хуиту(на коленях тоже правда за полчаса) вроде работает.
в ините
std::ranges::for_each(schema_offsets_manager::GetOffsetTable(), schema_offset_interface::fill);
а там где оффсет нужен
C++:
    class m_hAssignedHero : public schema_offset<CHandle<C_DOTA_BaseNPC>, "client.dll/C_DOTAPlayerController/m_hAssignedHero"> {};
    C_DOTA_BaseNPC* GetAssignedHero() const
    {
        const auto handle = SchemaMember2Test<m_hAssignedHero>();
        if (handle.IsValid())
            return CGameEntitySystem::GetInstance().GetEntityByHandle(handle);
        else
            return nullptr;
    }
в итоге если путь оффсета кривой то на ините сразу выдает мол иди нахуй
[Dota2Test] Initialization failed(std::runtime_error): CSchemaRuntimeGetter: netvar not found(client.dll/C_DOTAPXlayerController/m_hAssignedHero)!
а оффсет в итоге статик(то есть прямой доступ без всяких индексов поисков хуюисков резолвов), и один раз только инитится
валидацию правильности на компайл тайме(что два слеша например должно быть и что строка не пустая и тд и тп) не стал делать лень было
C++:
template<char... characters>
constexpr std::size_t helper_string_find_either(const std::string_view& str)
{
    for (std::size_t pos{}; const auto & character : str)
    {
        if (((character == characters) || ...))
            return pos;
        ++pos;
    }
    return std::string_view::npos;
}

constexpr auto split_path_into_relative_paths(const std::string_view& FullPath)
{
    std::vector<std::string> result{};
    std::string_view FullPath_copy{ FullPath };
    std::size_t pos{ helper_string_find_either<'\\', '/'>(FullPath_copy) };
    while (pos != std::string_view::npos)
    {
        if (const auto path = FullPath_copy.substr(0, pos); !path.empty())
            result.push_back(std::string{ path });
        FullPath_copy = FullPath_copy.substr(pos + 1);
        pos = helper_string_find_either<'\\', '/'>(FullPath_copy);
    }
    result.push_back(std::string{ FullPath_copy });
    return result;
}

std::size_t GetOffset(const std::string_view& name)
{
    if (const auto& paths = split_path_into_relative_paths(name); paths.size() == 3)
    {
        const auto& mod = paths.at(0);
        const auto& cls = paths.at(1);
        const auto& var = paths.at(2);

        for (const auto* scope : CSchemaSystem::GetInstance().GetTypeScopes())
        {
            if (scope)
            {
                if (scope->GetName() == mod)
                {
                    for (const auto* Class : scope->GetClasses())
                    {
                        if (Class)
                        {
                            if (Class->GetName() == cls)
                            {
                                for (const auto& member : Class->GetMembers())
                                {
                                    if (member.GetName() == var)
                                    {
                                        return member.GetOffset();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    throw std::runtime_error{ std::format("CSchemaRuntimeGetter: netvar not found({})", name) };
}

export
class schema_offset_interface
{
public:
    virtual void SetOffset(std::ptrdiff_t _offset) noexcept = 0;

    std::string_view name{};
    schema_offset_interface(const std::string_view& _name) : name{ _name } {}

    static void fill(schema_offset_interface* iface)
    {
        iface->SetOffset(GetOffset(iface->name));
    }
};

export
class schema_offsets_manager
{
public:
    static auto& GetOffsetTable()
    {
        static std::vector<schema_offset_interface*> table{};
        return table;
    }
    static void push(schema_offset_interface& obj)
    {
        GetOffsetTable().push_back(&obj);
    }
};

export
template<class X, TemplateStringClass path>
class schema_offset_base : public schema_offset_interface
{
    using schema_offset_interface::schema_offset_interface;

    class registrant
    {
    public:
        registrant()
        {
            static schema_offset_base<X, path> instance{ path };
            schema_offsets_manager::push(instance);
        }
    };
    static inline registrant _registrant{};

public:
    void SetOffset(std::ptrdiff_t _offset) noexcept override { X::GetOffset() = _offset; }
};

export
template<class Type, TemplateStringClass path>
class schema_offset :
    public schema_offset_base<schema_offset<Type, path>, path>
{
public:
    static inline std::ptrdiff_t offset{};
    using TType = Type;
    static auto& GetOffset() noexcept
    {
        return offset;
    }
};
единственное что разве что авторег(аллокация и популяция таблицы с оффсетами) на хипе(std::vector) сделан а не на статике(в модулях сложно его на статике сделать) поэтому может до вызова main кинуть исключение(= не сможешь отреагировать) если оперативки не хватит но с другой стороны если оперативки не хватит тебе и так пизда. ну и авторег в такой форме токо на мсвс работает(на кленге и гсс компилятор оптимизирует член к хуям если на него референса нет, поэтому надо референсить(просто в коде упомянуть его как-нибудь просто чтобы компилятор увидел что это не мусор а задействованный член)) но мне на кленг и гсс похуй потому что они говно по саппорту новых фич версус мсвс
Интересное решение. Но к сожалению мне не пойдет, т.к. в итоге будет юзаться не мсвс на релизе и это может поебать код. А так, я даж что-то себе да приберу, ty. На счет не хватка памяти, мужик, в таких случаях там и так пол хака поебетьсе. Уж слишком много хранит хак в памяти, базару ноль, некоторые вещи я потом мб вынесу, но не сейчас. Я стараюсь memprof юзать от мсвс дабы следить где я какаю, поэтому один раз переписывал систему хранения ентити. Я вообще изначально заюзал enTT (на гите лежат сурсы), чтобы создать систему хранения ентити в хаке (projectiles, entities с кастом флагами и т.п. как пример hero, player_controller, tree, courier и т.п., чтобы в случае опр. надобности быстро дергать именно нужные ентити), в итоге увидел, что либо я напастил хуево, либо enTT как-то странно написан. Потратил день, нехуя не понял в чем моя ошибка и написал с нуля entity_manager свой. С тех пор не испытывал проблем.

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

Я так понимаю у тебя модульный хак или отдельная либа в хаке которая дергает export'ы? Интересно. А так, спасибо, что-то да спизжу для себя.


(П.С. Я понимаю, что код ты написал по быстрому, но все таки лестница из скобок не очень, зачем она если можно код упростить? Оно становиться более читаемым, имхо)
C++:
std::size_t GetOffset(const std::string_view& name)
{
    if (const auto& paths = split_path_into_relative_paths(name); paths.size() == 3)
    {
        const auto& mod = paths.at(0);
        const auto& cls = paths.at(1);
        const auto& var = paths.at(2);

        for (const auto* scope : CSchemaSystem::GetInstance().GetTypeScopes())
        {
            if (!scope && scope->GetName() != mod)
                continue;

                for (const auto* Class : scope->GetClasses())
                {
                    if (!Class && Class->GetName() != cls)
                        continue;

                        for (const auto& member : Class->GetMembers())
                        {
                                if (member.GetName() == var)
                                {
                                        return member.GetOffset();
                                }
                        }
                }
         }
    }
    throw std::runtime_error{ std::format("CSchemaRuntimeGetter: netvar not found({})", name) };
}
 
Последнее редактирование:
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
760
Реакции[?]
328
Поинты[?]
60K
Интересное решение. Но к сожалению мне не пойдет, т.к. в итоге будет юзаться не мсвс на релизе и это может поебать код. А так, я даж что-то себе да приберу, ty. На счет не хватка памяти, мужик, в таких случаях там и так пол хака поебетьсе. Уж слишком много хранит хак в памяти, базару ноль, некоторые вещи я потом мб вынесу, но не сейчас. Я стараюсь memprof юзать от мсвс дабы следить где я какаю, поэтому один раз переписывал систему хранения ентити. Я вообще изначально заюзал enTT (на гите лежат сурсы), чтобы создать систему хранения ентити в хаке (projectiles, entities с кастом флагами и т.п. как пример hero, player_controller, tree, courier и т.п., чтобы в случае опр. надобности быстро дергать именно нужные ентити), в итоге увидел, что либо я напастил хуево, либо enTT как-то странно написан. Потратил день, нехуя не понял в чем моя ошибка и написал с нуля entity_manager свой. С тех пор не испытывал проблем.

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

Я так понимаю у тебя модульный хак или отдельная либа в хаке которая дергает export'ы? Интересно. А так, спасибо, что-то да спизжу для себя.


(П.С. Я понимаю, что код ты написал по быстрому, но все таки лестница из скобок не очень, зачем она если можно код упростить? Оно становиться более читаемым, имхо)
C++:
std::size_t GetOffset(const std::string_view& name)
{
    if (const auto& paths = split_path_into_relative_paths(name); paths.size() == 3)
    {
        const auto& mod = paths.at(0);
        const auto& cls = paths.at(1);
        const auto& var = paths.at(2);

        for (const auto* scope : CSchemaSystem::GetInstance().GetTypeScopes())
        {
            if (!scope && scope->GetName() != mod)
                continue;

                for (const auto* Class : scope->GetClasses())
                {
                    if (!Class && Class->GetName() != cls)
                        continue;

                        for (const auto& member : Class->GetMembers())
                        {
                                if (member.GetName() == var)
                                {
                                        return member.GetOffset();
                                }
                        }
                }
         }
    }
    throw std::runtime_error{ std::format("CSchemaRuntimeGetter: netvar not found({})", name) };
}
да там уебанская лестница, у меня два модуля, старый(runtime с SchemaMember) и новый(runtime_rework с SchemaMember2Test) я из старого скопипастил этот говнокод для теста))
бтв
C++:
 if (!scope && scope->GetName() != mod)
                continue;
ты наверно имел ввиду ||, то есть если (либо nullptr либо нейм != нужному) то скип. а получилось &&, то есть (если нуллптр И нуллптр->нейм не равен нужному)
как видишь уже сразу у тебя баг получился халявный от твоего способа)) понятно что на скорую руку но тем не менее) если бы ты два условия ебанул в две строки отдельно вполне вероятно что ты бы этого бага не допустил)
эта лесенка с if(Class) if(Scope) фиксится(по уму) ваще по-другому - надо референсы итерировать а не указатели. чек и скип вынести под капот и тогда просто даже возможности тут ошибиться не будет(не будет чеков на нуллптр они под колпаком). и до кучи еще и все эти сравнения имён можно в FindScope, FindClass какой-нибудь захуярить просто(которые еще и детальные исключения будут выкидывать мол Scope или Class не найдет вместо общего "не удалось найти нетвар"). тогда и чека на имя не будет. и чека на то нашло масштаб или нет тоже не будет ибо нахуй он нужен когда можно исключение кинуть что не найден масштаб/класс(а можно еще и его поймать и rethrow'нуть с доп инфой что мол "не найден класс A пока искал нетвар A/B/C")
тем не менее я лично предпочитаю лесенки и очень очень сильно не навижу любые выражения контроля кроме return в самом конце. я стараюсь вообще никогда не писать continue break(ну break нормальная тема впринципе когда из цикла надо выйти при этом не возвращаясь из функции но такая нужда редко появляется) и тд, а также return который не в самом конце. я стараюсь такую лесенку наоборот делать в которой очень четко проявляется одна конкретная ветвь(когда все условия соблюдены). таким образом логика максимально ясная получается - при соблюдении абсолютно всех условий получается "вот это", а в любом другом случае - "вот то"(кидается исключение например). а когда условия еще и разделены максимально на разные строки(if a && b -> if a + if b), то еще чётче логика прослеживается.
так что сам стиль "лестница" имба. и в нормальном коде лестниц таких огромных и не будет. тут лестница просто потому что мне лень было делать референсы вместо указателей и всякие Find'ы.
я сначала тоже лестницу не юзал, юзал всякие continue и тд, потом как увидел какое-то ужасное говнокодище с кучей continue return и тд где тупо просто не понятно что происходит нахуй(даже если логика овер простая) и перестал.
ну кр4 мораль не в читаемости а в корректности. лучше рабочий код чем читабельный. но довольно часто эти две вещи очень сильно взаимосвязаны(лестница корректнее всяких continue и тд(потому что логика чистейшая без всяких прыжков хуйков continue и тд и следовательно сложнее ошибиться потому что все максимально чётко видно(ну по крайней мере я так считаю) и прорисовывается одна чёткая успешная ветвь. с continue ты как-будто фильтруешь, отсеиваешь ненужные(и методом исключения приходишь к нужному), пробираешься сквозь джунгли, а с лесенкой ты наоборот сразу выбираешь только нужное и не обращаешь внимания на ненужное, идёшь на свет вдалеке и тебе пофигу на темноту вокруг), но при этом она сама по себе тоже говно - нужно итерировать референсы просто вместо указателей + юзать Find'ы, вот это будет и читаемо и корректно)

я фулл модули везде юзаю хедеры для лохов)) не знаю почему пидарасы из комитета с++ решили токо к с++20 завезти нормальную систему пакаг. хедеры это мусор Сшный, куда не глянь джаваскрипт джава шарп питон везде модули/пакаги а в с++ хедеры блядь.
и ты не так понял - на кленге и гсс работает, там просто дополнительно зареференсить надо, чтобы компилятор не игнорил(ну то есть код компилится но конструктор у static inline члена не вызывается ибо компилятор решает что это мусор и оптимизирует(убирает) к хуям(потому что он не видит нигде что ты этот член используешь. поэтому и надо его "задействовать" чтобы компилятор понял что это не мусор)). ну в общем гсс и кленг с одной стороны умные а с другой туповатые(умные потому что оптимизируют а тупые потому что никто их не просил этого делать)
ну и саппорт новых фич(в частности модулей и концептов) нищий немножко в гсс и кленге

C++:
class shit
{
    class xxx{}
    static inline xxx cock{};//компилятор оптимизирует подумав что это мусор(если нигде нет упомянания cock)
    //shit(){cock;}//а вот если референснуть переменную cock то компилятор уже не будет эту хуйню оптимизировать(я бы даже сказал ошибочно оптимизировать ибо это нихуя не оптимизация). на мсвс и так работает а на кленге и гсс нужно будет раскомментить эту строку
}
на с++ сложно накакать, как ты это делаешь? юзай RAII ни одной каки не будет и быть не может. задай всему масштаб(основной масштаб чита это его жизнь(жизнь это период от инита до деинита)) и всё. ты тупо не сможешь накакать, потому что все вещи будут зарождаться в масштабе и в нём же умирать.

любой ресурс(оперативка и тд) должен кто-то держать. когда держатель(ака менеджер) дохнет(а дохнет он при выходе из чита) - все что он держит тоже дохнет. с таким дизайном каки просто невозможны. если у тебя ресурс - держи его(желательно еще и централизованно - то есть в менеджере), не выкидывай его. не выкидываешь ресурсы = не срёшь. подыхаешь = убиваешь всех кого держишь(и они убивают всех кого они держат, и так далее)
на, накидал тебе ночного говнокода, потести внимательно, вроде нет ликов
C++:
#define _CRTDBG_MAP_ALLOC 1
#include <stdlib.h>
#include <crtdbg.h>
#include <Windows.h>


#include <iostream>
#include <vector>
#include <thread>
#include <array>

template<class T>
class Singleton
{
    static inline T* instance{ nullptr };
public:
    static bool HasInstance() noexcept { return instance != nullptr; }
private:
    template<class... Args>
    static void Create(T& real_instance, Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
    {
        static_assert(std::is_nothrow_constructible_v<T>, "Singleton requires -> T has public default noexcept constructor and destructor.");
        if (!HasInstance())
        {
            T temp{ std::forward<Args>(args)... };
            using std::swap;
            swap(temp, real_instance);
            instance = &real_instance;
        }
    }
public:
    static void Destroy() noexcept
    {
        if (HasInstance())
        {
            GetInstance().~T();
            instance = nullptr;
        }
    }
public:
    static auto& GetInstance() noexcept
    {
        return *instance;
    }

    class Adaptor
    {
        union { T instance_impl_nodestruct; };
        T& GetInstanceImpl() noexcept
        {
            return instance_impl_nodestruct;
        }
    public:
        template<class... Args>
        Adaptor(Args&&... args) noexcept(std::is_nothrow_constructible_v<T, Args...>)
        {
            Create(GetInstanceImpl(), std::forward<Args>(args)...);
        }
        Adaptor(const Adaptor&) = delete;
        Adaptor& operator=(const Adaptor&) = delete;
        Adaptor(Adaptor&&) noexcept = delete;
        Adaptor& operator=(Adaptor&&) noexcept = delete;
        ~Adaptor() noexcept { Destroy(); }

        operator const T& () const noexcept { return GetInstance(); }
    };

public:
    Singleton() = default;
protected:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    Singleton(Singleton&&) noexcept = default;
    Singleton& operator=(Singleton&&) noexcept = default;
    ~Singleton() = default;
};

class IResource
{
public:
    virtual ~IResource() noexcept = default;
};

class resourceman
    :
    public Singleton<resourceman>
{
    friend class Singleton<resourceman>;

    class StupidCock
    {
        std::string name{};
        bool is_valid{ false };
    public:
        void Destroy()
        {
            if (is_valid)
                std::cout << "~StupidCock: " << name << std::endl;
        }
    public:
        StupidCock() noexcept = default;
        StupidCock(const std::string_view& _name) : name{ _name }, is_valid{ true } {}
        StupidCock(const StupidCock&) = delete;
        StupidCock& operator=(const StupidCock&) = delete;
        StupidCock(StupidCock&& other) noexcept
            : name{ std::move(other.name) }
        {
            is_valid = other.is_valid;
            other.is_valid = false;
        }
        StupidCock& operator=(StupidCock&& other) noexcept
        {
            Destroy();
            name = std::move(other.name);
            is_valid = other.is_valid;
            other.is_valid = false;
            return *this;
        }
        ~StupidCock()
        {
            Destroy();
        }
    };
private:
    std::vector<std::unique_ptr<IResource>> resources{};
    StupidCock stupid_cock{};
public:
    resourceman() noexcept = default;
protected:
    resourceman(const std::string_view& _shit) : stupid_cock{ "cock???" }
    {
        if (_shit == "shit")
            throw std::runtime_error{"SHIT GONE DOWN!!!"};
    }
    resourceman(const resourceman&) = delete;
    resourceman& operator=(const resourceman&) = delete;
    resourceman(resourceman&& other) noexcept
        :
        resources{ std::move(other.resources) },
        stupid_cock{ std::move(other.stupid_cock) }
    {}
    resourceman& operator=(resourceman&& other) noexcept
    {
        resources = std::move(other.resources);
        stupid_cock = std::move(other.stupid_cock);
        return *this;
    }
public:
    ~resourceman() noexcept
    {}
    friend void swap(resourceman& a, resourceman& b) noexcept
    {
        auto temp_a{ std::move(a) };
        a = std::move(b);
        b = std::move(temp_a);
    }
public:
    template<class T, class... Args>
    static auto& emplace(Args&&... args)
    {
        auto result = std::make_unique<T>(std::forward<Args>(args)...);
        const auto result_ptr = result.get();
        GetInstance().resources.push_back(std::move(result));
        return *result_ptr;
    }
};


class Shit : public IResource
{
    std::string name{};
public:
    Shit(const std::string_view& _name) : name{ _name } {}
    Shit(const Shit&) = default;
    Shit(Shit&&) noexcept = default;
    ~Shit()
    {
        std::cout << "~Shit" << std::endl;
    }
    std::string_view GetName() const noexcept { return name; }
};

class Entity : public IResource
{
    std::string name{};
public:
    Entity(const std::string_view& _name) : name{ _name } {}
    Entity(const Entity&) = default;
    Entity(Entity&&) noexcept = default;
    ~Entity()
    {
        std::cout << "~Entity" << std::endl;
    }
    std::string_view GetName() const noexcept { return name; }
};

class I_Need_To_Be_Closed : public IResource
{
    using large_arr = std::array<char, (1 << 24)>;
    std::unique_ptr<large_arr> shit{};
public:
    I_Need_To_Be_Closed(const std::string_view& name)
        : shit{ std::make_unique<large_arr>() }
    {
        if (name == "shit")
            throw std::runtime_error{ "WOOO SHITTTT" };
    }
    I_Need_To_Be_Closed(const I_Need_To_Be_Closed&) = delete;
    I_Need_To_Be_Closed(I_Need_To_Be_Closed&&) noexcept = default;
    ~I_Need_To_Be_Closed()
    {
        std::cout << "~I_Need_To_Be_Closed" << std::endl;
    }
};

void submain()
{
    resourceman::Adaptor resources
    {
        "shi"
        //uncomment for testing VVV
        //"t"
    };
    std::cout << "Shit -> " << resourceman::emplace<Shit>("cunt").GetName() << std::endl;
    const auto lambda = []()
    {
        try
        {
            std::cout << "Entity -> " << resourceman::emplace<Entity>("cock").GetName() << std::endl;
            resourceman::emplace<I_Need_To_Be_Closed>
            (
                "shi"
                //uncomment for testing VVV
                //"t"
            );
        }
        catch (const std::exception& ex)
        {
            std::cout << "other_thread: " << ex.what() << std::endl;
        }

    };
    HANDLE Xthread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)+lambda, 0, 0, 0);
    if (Xthread != NULL)
    {
        WaitForSingleObject(Xthread, INFINITE);
        CloseHandle(Xthread);
    }
    //std::jthread Xthread{ lambda };//performs some sort of CRT allocations under the hood so fuck it
}
void truemain()
{
    _CrtMemState sOld{};
    try
    {
        _CrtMemCheckpoint(&sOld);
        submain();
    }
    catch (const std::exception& ex)
    {
        std::cout << ex.what() << std::endl;
    }
    _CrtMemState sNew{};
    _CrtMemState sDiff{};
    _CrtMemCheckpoint(&sNew);
    _CrtMemDifference(&sDiff, &sOld, &sNew);
    OutputDebugString(L"-----------_CrtMemDumpStatistics ---------\n");
    _CrtMemDumpStatistics(&sDiff);
    OutputDebugString(L"-----------_CrtMemDumpAllObjectsSince ---------\n");
    _CrtMemDumpAllObjectsSince(&sOld);
    OutputDebugString(L"-----------_CrtDumpMemoryLeaks ---------\n");
    _CrtDumpMemoryLeaks();
}
int main()
{
    printf("one-time 4k bytes CRT allocation <----(caused by printf)...\n");
    truemain();
    return 0;
}
 
Последнее редактирование:
Новичок
Статус
Оффлайн
Регистрация
22 Сен 2020
Сообщения
1
Реакции[?]
0
Поинты[?]
0
Мой русский не очень хорош, поэтому я переведу это с помощью переводчика. В общем, я пытаюсь найти структуру энтити с помощью Cheat Engine, я получаю несколько динамических адресов, у них есть Health, Mana, Armor, Attack Speed..., все это похоже на класс mcDota, проблема в том, что я не могу найти статический адрес.
Нужно ли мне искать в client.dll + offset или ?
 
Пользователь
Статус
Оффлайн
Регистрация
8 Апр 2022
Сообщения
644
Реакции[?]
102
Поинты[?]
65K
Мой русский не очень хорош, поэтому я переведу это с помощью переводчика. В общем, я пытаюсь найти структуру энтити с помощью Cheat Engine, я получаю несколько динамических адресов, у них есть Health, Mana, Armor, Attack Speed..., все это похоже на класс mcDota, проблема в том, что я не могу найти статический адрес.
Нужно ли мне искать в client.dll + offset или ?
for finding offsets you can use schema system(https://yougame.biz/threads/139802/) or datamap(
Пожалуйста, авторизуйтесь для просмотра ссылки.
)
 
Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
309
Реакции[?]
24
Поинты[?]
12K
Мой русский не очень хорош, поэтому я переведу это с помощью переводчика. В общем, я пытаюсь найти структуру энтити с помощью Cheat Engine, я получаю несколько динамических адресов, у них есть Health, Mana, Armor, Attack Speed..., все это похоже на класс mcDota, проблема в том, что я не могу найти статический адрес.
Нужно ли мне искать в client.dll + offset или ?
Next time just write in English, don't think others can't speak it. As for your problem(if the Google Translator translated it correcly) I understand that you haven't been able to find the Entity list, right? If so, try to find global CGameEntitySystem pointer(that is g_pEntitySystem or g_pGameEntitySystem in client.dylib in IDA), then find it in your client.dll of the game.
Have a look at ent_find xref which will lead you to a function, look at(if in IDA) qword_somenumbers and grab them and "throw these numbers" in Reclass to see if its what you wanted to find(remember you have to derefference(read the value from the address) of a pointer to get the value. So, if you have g_pEntitySystem you have to derefference it( *g_pEntitySystem, read the value ) to get the EntitySystem. And on offset 0x210(you'd figure this out if you looked at ent_find xref leading to some function) there is FirstEntity in the game.Then you'd have to just rebuild the entity identity iterator.

C++:
first_ent = g_pEntitySystem +0x210;
do
{
ent = first_ent + (Offset size of CEntityIdentity)
...
}while(ent)
The method above is called "simple iterator by offset( ent + offset)"


You could also try the McDota's method via Indexes( which I myself prefer)

( for int i = 0; i < HighestEntityIndex<++i )

Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
760
Реакции[?]
328
Поинты[?]
60K
Next time just write in English, don't think others can't speak it. As for your problem(if the Google Translator translated it correcly) I understand that you haven't been able to find the Entity list, right? If so, try to find global CGameEntitySystem pointer(that is g_pEntitySystem or g_pGameEntitySystem in client.dylib in IDA), then find it in your client.dll of the game.
Have a look at ent_find xref which will lead you to a function, look at(if in IDA) qword_somenumbers and grab them and "throw these numbers" in Reclass to see if its what you wanted to find(remember you have to derefference(read the value from the address) of a pointer to get the value. So, if you have g_pEntitySystem you have to derefference it( *g_pEntitySystem, read the value ) to get the EntitySystem. And on offset 0x210(you'd figure this out if you looked at ent_find xref leading to some function) there is FirstEntity in the game.Then you'd have to just rebuild the entity identity iterator.

C++:
first_ent = g_pEntitySystem +0x210;
do
{
ent = first_ent + (Offset size of CEntityIdentity)
...
}while(ent)
The method above is called "simple iterator by offset( ent + offset)"


You could also try the McDota's method via Indexes( which I myself prefer)

( for int i = 0; i < HighestEntityIndex<++i )

Пожалуйста, авторизуйтесь для просмотра ссылки.
not
i = 0; i < HighestEntityIndex; ++i
but
i = 0; i <= HighestEntityIndex; ++i
note the "less or equal to" instead of "less"
(lwss skips worldent(index 0) and starts from index 1 instead)
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
309
Реакции[?]
24
Поинты[?]
12K
Там крч уже итерация в ent_find не напрямую через
mov rcx, g_pEntitySystem
mov rax, [rcx + 0x210]

А там функу какуюто вставили, ну крч в любом случае меняйте себе оффсеты

04.11.2022


48 83 EC 28 83 BA 38 04 00 00 02 7D 12 48 8D ? ? ? ? ? 48 83 C4 28 48 FF 25 ? ? ? ? 48 8B 82 40 04 00 00 48 8D
оффсет 0x4B
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
760
Реакции[?]
328
Поинты[?]
60K
Там крч уже итерация в ent_find не напрямую через
mov rcx, g_pEntitySystem
mov rax, [rcx + 0x210]

А там функу какуюто вставили, ну крч в любом случае меняйте себе оффсеты

04.11.2022


48 83 EC 28 83 BA 38 04 00 00 02 7D 12 48 8D ? ? ? ? ? 48 83 C4 28 48 FF 25 ? ? ? ? 48 8B 82 40 04 00 00 48 8D
оффсет 0x4B
эта функция то же самое делает через 0x210)) так что ничего не поменялось впринципе
1667563491500.png
1667563502200.png
 
Начинающий
Статус
Оффлайн
Регистрация
30 Мар 2020
Сообщения
309
Реакции[?]
24
Поинты[?]
12K
Ну у меня в итерации после worldent ( worldent = GetBaseEntity(++i) )вылазит ошибка потому что this war 0xFFFF87777 /// 0x284r884828482
 
Участник
Статус
Оффлайн
Регистрация
23 Май 2019
Сообщения
760
Реакции[?]
328
Поинты[?]
60K
Ну у меня в итерации после worldent ( worldent = GetBaseEntity(++i) )вылазит ошибка потому что this war 0xFFFF87777 /// 0x284r884828482
дебажь логай код скидывай блаблабла так ничего нельзя сказать без информации
 
Сверху Снизу