Вопрос ConVars и versus scene в них

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
23 Апр 2025
Сообщения
3
Реакции
0
Я только начинаю во всём разбираться, не судите строго!

Начну сразу с темы: я не понимаю как выставлять по путям из ConVars выбранный экран противника. Если с погодой и речкой ещё просто, то с versus(ами - экранами противника) я так и не разобрался..

Что я делал:
К примеру возьмём dota_hud_versus_scene_international2024 - инт 24 года, чекнул все convars и нашёл dota_versus_scene_override_layout_file - подумал что вставив в него путь на этот versus я смогу на клиенте сделать ченджер для экрана противников, но дота просто крашится
(путь нашёл через S2V: panorama/layout/hud/versus/dota_hud_versus_scene_international2024.vxml_c )
3gdoYuf.md.png

Пример кода:
example:
Expand Collapse Copy
const std::string target_convar_name = "dota_versus_scene_override_layout_file";
    
    const std::string layout_path_to_set = "hud/versus/dota_hud_versus_scene_default.vxml_c"; // я использовал разные варианты - везде крашило

    if (vmt.cvar->g_convars.count(target_convar_name)) {
        CCvarNode* convar_node = vmt.cvar->g_convars[target_convar_name];

        if (convar_node) {
            uintptr_t convar_value_storage_address = reinterpret_cast<uintptr_t>(convar_node) + 0x40;
            
            if (Memory::write_string(convar_value_storage_address, layout_path_to_set)) {
                LOG::INFO("ConVar '{}' set to: \"{}\"", target_convar_name, layout_path_to_set);
            } else {
                LOG::ERR("FAILED to set ConVar '{}' to: \"{}\"", target_convar_name, layout_path_to_set);
            }
        } else {
            LOG::ERR("ConVar '{}' node is null.", target_convar_name);
        }
    } else {
        LOG::ERR("ConVar '{}' not found.", target_convar_name);
    }



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

upd:и ещё - видел на форуме что можно легко "сделать" доту плюс в экстернал чите - есть пример кода? насколько я понимаю там нужен отдельный паттерн или нет?
 
Я только начинаю во всём разбираться, не судите строго!

Начну сразу с темы: я не понимаю как выставлять по путям из ConVars выбранный экран противника. Если с погодой и речкой ещё просто, то с versus(ами - экранами противника) я так и не разобрался..

Что я делал:
К примеру возьмём dota_hud_versus_scene_international2024 - инт 24 года, чекнул все convars и нашёл dota_versus_scene_override_layout_file - подумал что вставив в него путь на этот versus я смогу на клиенте сделать ченджер для экрана противников, но дота просто крашится
(путь нашёл через S2V: panorama/layout/hud/versus/dota_hud_versus_scene_international2024.vxml_c )
3gdoYuf.md.png

Пример кода:
example:
Expand Collapse Copy
const std::string target_convar_name = "dota_versus_scene_override_layout_file";
   
    const std::string layout_path_to_set = "hud/versus/dota_hud_versus_scene_default.vxml_c"; // я использовал разные варианты - везде крашило

    if (vmt.cvar->g_convars.count(target_convar_name)) {
        CCvarNode* convar_node = vmt.cvar->g_convars[target_convar_name];

        if (convar_node) {
            uintptr_t convar_value_storage_address = reinterpret_cast<uintptr_t>(convar_node) + 0x40;
           
            if (Memory::write_string(convar_value_storage_address, layout_path_to_set)) {
                LOG::INFO("ConVar '{}' set to: \"{}\"", target_convar_name, layout_path_to_set);
            } else {
                LOG::ERR("FAILED to set ConVar '{}' to: \"{}\"", target_convar_name, layout_path_to_set);
            }
        } else {
            LOG::ERR("ConVar '{}' node is null.", target_convar_name);
        }
    } else {
        LOG::ERR("ConVar '{}' not found.", target_convar_name);
    }



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

upd:и ещё - видел на форуме что можно легко "сделать" доту плюс в экстернал чите - есть пример кода? насколько я понимаю там нужен отдельный паттерн или нет?
Делаешь типо так dota_versus_scene_override_layout_file "file://{resources}/layout/hud/versus/dota_hud_versus_scene_international2024.vxml_c" насчет дота плюса это костыль в external но короче ищешь через Class Informer таблицу CDOTAPlusController и там вторую функцию
1747300823045.png
1747300834830.png
потом еще на sub_1823E1D70 и там будет чуть длинная макоронина идешь ниже чуть
1747301004595.png
у меня оно уже чуть названнотам есть GDOTAGCClientSystem(если че я их сам так назвал); то что вернет CDOTAGCClientSystem можешь получить CDOTAGCClientSystem ну внутри GDOTAGCClientSystem будет насмещении 0x598 CGCClientSharedObjectCache потом смещение 0x18 и будет несколько CGCClientSharedObjectTypeCache на смещениях 0x0 до 0x28 открываешь и смотришь в какомто из них будет CDOTAGameAccountPlus и обрати внимание что потом будет 4 byte с 2012
1747301315809.png
ну и будет что то типо такой структуры в ней будет
CDOTAGameAccountPlus:
Expand Collapse Copy
#pragma pack(push, 1)
struct CDOTAGameAccountPlus
{
    void* vftable;                  // +0x0
    void* secondary_vftable;         // +0x8
    uint64_t unknown0;               // +0x10
    uint64_t unknown1;               // +0x18
    uint32_t account_id;             // +0x20
    uint32_t original_start_date;    // +0x24
    uint32_t plus_flags;             // +0x28
    uint32_t plus_status;            // +0x2C
    uint32_t prepaid_time_start;     // +0x30
    uint32_t prepaid_time_balance;   // +0x34
    uint64_t steam_agreement_id;     // +0x38
    uint32_t next_payment_date;      // +0x40
};
#pragma pack(pop)
и короче че надо поменять plus_status и поидеи plus_flags ну я точно могу сказать в plus_status может быть 0 1 2 типо 0 у тебя нет подписки 1 есть и 2 вроде как если ты только что ее купил короче меняешь на 2 и пофакту нихуя не изменилось а потому что надо SOCache обновить как это сделать в external хуй знает как то в ксго это делали короче можешь просто выйти из игры через саму игру чтобы дота SOCache обновила и сохранила в файлик и потом заходишь в игру и дота плюс ну можешь незнаю когда игра грузится бегать по классам и искать ту самую 2012 хуй знает как сделать нормально ну а еще кто то спрашивал про дота плюс еще и еще был гайд от вольфа
1747301723276.png

https://yougame.biz/threads/329089/#post-3149438 и https://yougame.biz/threads/242900/#post-2519003
если что то не понимаешь можешь написать тут или мне в тг но сразу я не смогу ответить так как на практике буду так что потом смогу ответить ближе к 5 или 6 где то так
 
Последнее редактирование:
видел на форуме что можно легко "сделать" доту плюс в экстернал чите - есть пример кода?
Будет работать только после перезапуска доты, ты же не можешь в экстернале коллбек вызвать.

C++:
Expand Collapse Copy
struct SOID_t {
    uint64_t m_unSteamID;
    uint32_t m_iType;
};

class CProtobufSharedObjectBase : public VClass {
public:
    template <typename T>
    T get_object() const {
        return this->call_virtual<9, T>();
    };
};

class CGCClientSharedObjectTypeCache : public VClass {
public:
    CProtobufSharedObjectBase* protobufSO() const {
        return *member<CProtobufSharedObjectBase**>(0x10);
    }

    EEconTypeID econ_typeID() const {
        return Memory::read_memory<EEconTypeID>(this + 0x28).value_or(EEconTypeID::k_None);
    }
};

class CGCClientSharedObjectCache : public VClass {
public:
    CUtlVector<CGCClientSharedObjectTypeCache*> type_cache_list() const {
        return Memory::read_memory<CUtlVector<CGCClientSharedObjectTypeCache*>>(this + 0x10).value();
    }

    SOID_t get_owner() const {
        return member<SOID_t>(0x28);
    };
};

class CDOTAPlayerInventory : public VClass {
public:
    CGCClientSharedObjectCache* get_so_cache() const {
        return Memory::read_memory<CGCClientSharedObjectCache*>(this + 0xA0).value();
    }

    SOID_t get_owner() const {
        return member<SOID_t>(0x8);
    };
};

class ISharedObjectListener : public VClass {
public:
    template <typename T>
    bool dispatch_created(SOID_t soid, T* sharedObj, ESOCacheEvent ev) {
        return this->call_virtual<0, bool>(soid, *sharedObj, ev);
    }

    template <typename T>
    bool dispatch_update(SOID_t soid, T* sharedObj, ESOCacheEvent ev) {
        return this->call_virtual<1, bool>(soid, *sharedObj, ev);
    }
};

class CGCClient {
public:
    template <typename T>
    CUtlVector<T*> SOListeners() const {
        return Memory::read_memory<CUtlVector<T*>>(this + 0x270).value();
    }

    template <typename T>
    bool dispatch_SOUpdated(SOID_t soid, T* sharedObj, ESOCacheEvent ev) const {
        for (auto& listener : SOListeners<ISharedObjectListener>())
            return listener->dispatch_update(soid, sharedObj, ev);
        return 0;
    }

    template <typename T>
    bool dispatch_SOCreated(SOID_t soid, T* sharedObj, ESOCacheEvent ev) const {
        for (auto& listener : SOListeners<ISharedObjectListener>())
            return listener->dispatch_created(soid, sharedObj, ev);
        return 0;
    }
};

///////////////

void Hacks::set_dota_plus(bool unlocked) {
    const auto inventory = vmt.gc_client->SOListeners<CDOTAPlayerInventory>()[1];
    const auto so_cache = inventory->get_so_cache();
    auto type_cache_list = so_cache->type_cache_list();

    for (const auto& type_cache : type_cache_list) {
        if (type_cache->econ_typeID() != EEconTypeID::k_CDOTAGameAccountPlus)
            continue;

        const auto protobufSO = type_cache->protobufSO();
        const auto dota_plus = protobufSO->get_object<CSODOTAGameAccountPlus*>();

        dota_plus->set_plus_flags(!unlocked);
        dota_plus->set_plus_status(unlocked);

        dota_plus->set_original_start_date(static_cast<uint32_t>(std::time(nullptr)));
        dota_plus->set_prepaid_time_balance(UINT32_MAX);

        vmt.gc_client->dispatch_SOUpdated(so_cache->get_owner(), protobufSO, ESOCacheEvent::eSOCacheEvent_Incremental);
    }
}
 
Будет работать только после перезапуска доты, ты же не можешь в экстернале коллбек вызвать.

C++:
Expand Collapse Copy
struct SOID_t {
    uint64_t m_unSteamID;
    uint32_t m_iType;
};

class CProtobufSharedObjectBase : public VClass {
public:
    template <typename T>
    T get_object() const {
        return this->call_virtual<9, T>();
    };
};

class CGCClientSharedObjectTypeCache : public VClass {
public:
    CProtobufSharedObjectBase* protobufSO() const {
        return *member<CProtobufSharedObjectBase**>(0x10);
    }

    EEconTypeID econ_typeID() const {
        return Memory::read_memory<EEconTypeID>(this + 0x28).value_or(EEconTypeID::k_None);
    }
};

class CGCClientSharedObjectCache : public VClass {
public:
    CUtlVector<CGCClientSharedObjectTypeCache*> type_cache_list() const {
        return Memory::read_memory<CUtlVector<CGCClientSharedObjectTypeCache*>>(this + 0x10).value();
    }

    SOID_t get_owner() const {
        return member<SOID_t>(0x28);
    };
};

class CDOTAPlayerInventory : public VClass {
public:
    CGCClientSharedObjectCache* get_so_cache() const {
        return Memory::read_memory<CGCClientSharedObjectCache*>(this + 0xA0).value();
    }

    SOID_t get_owner() const {
        return member<SOID_t>(0x8);
    };
};

class ISharedObjectListener : public VClass {
public:
    template <typename T>
    bool dispatch_created(SOID_t soid, T* sharedObj, ESOCacheEvent ev) {
        return this->call_virtual<0, bool>(soid, *sharedObj, ev);
    }

    template <typename T>
    bool dispatch_update(SOID_t soid, T* sharedObj, ESOCacheEvent ev) {
        return this->call_virtual<1, bool>(soid, *sharedObj, ev);
    }
};

class CGCClient {
public:
    template <typename T>
    CUtlVector<T*> SOListeners() const {
        return Memory::read_memory<CUtlVector<T*>>(this + 0x270).value();
    }

    template <typename T>
    bool dispatch_SOUpdated(SOID_t soid, T* sharedObj, ESOCacheEvent ev) const {
        for (auto& listener : SOListeners<ISharedObjectListener>())
            return listener->dispatch_update(soid, sharedObj, ev);
        return 0;
    }

    template <typename T>
    bool dispatch_SOCreated(SOID_t soid, T* sharedObj, ESOCacheEvent ev) const {
        for (auto& listener : SOListeners<ISharedObjectListener>())
            return listener->dispatch_created(soid, sharedObj, ev);
        return 0;
    }
};

///////////////

void Hacks::set_dota_plus(bool unlocked) {
    const auto inventory = vmt.gc_client->SOListeners<CDOTAPlayerInventory>()[1];
    const auto so_cache = inventory->get_so_cache();
    auto type_cache_list = so_cache->type_cache_list();

    for (const auto& type_cache : type_cache_list) {
        if (type_cache->econ_typeID() != EEconTypeID::k_CDOTAGameAccountPlus)
            continue;

        const auto protobufSO = type_cache->protobufSO();
        const auto dota_plus = protobufSO->get_object<CSODOTAGameAccountPlus*>();

        dota_plus->set_plus_flags(!unlocked);
        dota_plus->set_plus_status(unlocked);

        dota_plus->set_original_start_date(static_cast<uint32_t>(std::time(nullptr)));
        dota_plus->set_prepaid_time_balance(UINT32_MAX);

        vmt.gc_client->dispatch_SOUpdated(so_cache->get_owner(), protobufSO, ESOCacheEvent::eSOCacheEvent_Incremental);
    }
}

я понял, и так сойдёт, сделал
спасибо
 
Последнее редактирование:
Назад
Сверху Снизу