hl2sdk
hl2sdk copied to clipboard
Source 2 - Reverse 9/2022 ConVar / ConCommand changes
ConVars and ConCommands in Source 2 got a rework with a Dota 2 update a couple of months ago. The implementation seems to be fully rewritten.
Some snippets from a Russian Cheat Forum:
enum class EConvarType : std::uint8_t
{
BOOL = 0,
INT32,
UINT32,
INT64,
UINT64,
FLOAT,
DOUBLE,
STRING,
COLOR_RGBA,
UNK_SOME_TWO_FLOATS,
UNK_SOME_THREE_FLOATS,
UNK_SOME_FOUR_FLOATS,
UNK_SOME_THREE_FLOATS_AGAIN,
};
struct CvarNode
{
ConVariable* var{};
int some_leaf_like_index_shit{};
};
union ConVarValue
{
bool boolean{};
std::uint64_t u64;
std::int64_t i64;
std::uint32_t u32;
std::int32_t i32;
float flt;
double dbl;
const char* str;
std::uint32_t clr_rgba;
std::array<float, 2> two_floats;
std::array<float, 3> three_floats;
std::array<float, 4> four_floats;
};
struct ConVariable
{
const char* name{};
void* next_convar_node_like_shit{};
void* unk1{};
void* unk2{};
const char* help{};
EConvarType type{};
int unk_maybe_number_of_times_changed{};
int flags{};
int unk4{};
int CALLBACK_INDEX{};
int unk5{};
ConVarValue value{};
}
struct ConCmd
{
const char* name{};
const char* help{};
int flags{};
void* accessor{};
void* accessor_related_shit_maybe{};
int shit_unk{};
int CallbackListIndex{};
};
struct ConCMDID
{
static inline constexpr auto BAD_ID = 0xFFFF;
std::uint64_t impl{};
bool IsGood() const noexcept
{
return impl != BAD_ID;
}
void Invalidate() noexcept
{
impl = BAD_ID;
}
};
struct ConCMDRegistrationInfo
{
const char* cmd_name{};
const char* help_str{};
std::uint64_t flags{};
void* callback{};
void* unk1{};
void* unk2{};
void* unk3{};
void* output_id_holder{};
};
ConCommandSource2(const std::string_view& name, const std::string_view& desc, void(* callback)(void*, const CCommand&))
{
ICvar::ConCMDRegistrationInfo info{};
info.cmd_name = name.data();
info.help_str = desc.data();
info.callback = callback;
info.output_id_holder = this;
Constructor::Invoke(&info);
}
...
//CCvar VVV
private:
//search for xrefs for constructed concmd variables.
static inline constexpr auto UnRegisterCMDVFTable_Index = 38;
public:
auto UnRegisterCMD(const ConCMDID& id)
{
CallVFunc<UnRegisterCMDVFTable_Index>(id);
}
struct ConVarID
{
static inline constexpr auto BAD_ID = 0xFFFFFFFF;
std::uint64_t impl{};
void* var_ptr{};
bool IsGood() const noexcept
{
return impl != BAD_ID;
}
void Invalidate() noexcept
{
impl = BAD_ID;
}
};
using t_CvarCallback = void(*)(const ConVarID& id, int unk1, const ConVarValue* val, const ConVarValue* old_val);
/*
t_CvarCallback GetCVarCallback(int index)
{
if (index)
{
auto table = Member<void*>(0x80);
if (table)
return *reinterpret_cast<t_CvarCallback*>(reinterpret_cast<std::uintptr_t>(table) + 24 * index);
}
return nullptr;
}
*/
/*
auto CCvar::GetCvarList() const noexcept
{
return std::span<const CvarNode>{ Member<const CvarNode*>(0x40), Member<std::uint16_t>(0x58) };
}
*/
for (const auto& [cvar_node, idx] : ICvar::Create()->GetCvarList() | indexed_range)
{
if (cvar_node.var)
{
if (make_stringview(cvar_node.var->name) == "dota_camera_distance")
{
const auto old_val = cvar_node.var->value;
cvar_node.var->value.flt = 2222.0f;
if (auto cb = ICvar::Create()->GetCVarCallback(cvar_node.var->CALLBACK_INDEX); cb)
cb(ICvar::ConVarID{ .impl = static_cast<std::uint64_t>(idx), .var_ptr = (void*)&cvar_node},
0, &cvar_node.var->value, & old_val);
}
if (make_stringview(cvar_node.var->name) == "sv_cheats")
{
const auto old_val = cvar_node.var->value;
cvar_node.var->value.boolean = true;
if (auto cb = ICvar::Create()->GetCVarCallback(cvar_node.var->CALLBACK_INDEX); cb)
cb(ICvar::ConVarID{ .impl = static_cast<std::uint64_t>(idx), .var_ptr = (void*)&cvar_node },
0, &cvar_node.var->value, &old_val);
}
}
}