new stuff and other stuff

This commit is contained in:
quaK 2022-09-17 20:19:30 +03:00
parent 745486e18c
commit 58dc53850b
21 changed files with 543 additions and 113 deletions

View File

@ -0,0 +1,150 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace binding
{
namespace
{
std::vector<std::string> custom_binds = {};
utils::hook::detour cl_execute_key_hook;
int get_num_keys()
{
return 118;
}
int key_write_bindings_to_buffer_stub(int, char* buffer, const int buffer_size)
{
auto bytes_used = 0;
const auto buffer_size_align = static_cast<std::int32_t>(buffer_size) - 4;
for (auto key_index = 0; key_index < 256; ++key_index)
{
const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1);
auto value = game::playerKeys->keys[key_index].binding;
if (value && value < get_num_keys())
{
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
"bind %s \"%s\"\n", key_button, game::command_whitelist[value]);
if (len < 0)
{
return bytes_used;
}
bytes_used += len;
}
else if (value >= get_num_keys())
{
value -= get_num_keys();
if (static_cast<size_t>(value) < custom_binds.size() && !custom_binds[value].empty())
{
const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used),
"bind %s \"%s\"\n", key_button, custom_binds[value].data());
if (len < 0)
{
return bytes_used;
}
bytes_used += len;
}
}
}
buffer[bytes_used] = 0;
return bytes_used;
}
int get_binding_for_custom_command(const char* command)
{
auto index = 0;
for (auto& bind : custom_binds)
{
if (bind == command)
{
return index;
}
index++;
}
custom_binds.emplace_back(command);
index = static_cast<unsigned int>(custom_binds.size()) - 1;
return index;
}
int key_get_binding_for_cmd_stub(const char* command)
{
// original binds
for (auto i = 0; i < get_num_keys(); i++)
{
if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i]))
{
return i;
}
}
// custom binds
return get_num_keys() + get_binding_for_custom_command(command);
}
std::optional<std::string> get_custom_binding_for_key(int key)
{
key -= get_num_keys();
if (static_cast<size_t>(key) < custom_binds.size() && !custom_binds[key].empty())
{
return { custom_binds[key] };
}
return {};
}
void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time)
{
if (key >= get_num_keys())
{
const auto bind = get_custom_binding_for_key(key);
if (!bind.has_value())
{
return;
}
return game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", bind.value().data()));
}
cl_execute_key_hook.invoke<void>(local_client_num, key, down, time);
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_dedi())
{
return;
}
// write all bindings to config file
utils::hook::jump(0x9A9F70_b, key_write_bindings_to_buffer_stub);
// links a custom command to an index
utils::hook::jump(0x9A8EA0_b, key_get_binding_for_cmd_stub);
// execute custom binds
cl_execute_key_hook.create(0x32A3B0_b, &cl_execute_key_stub);
}
};
}
REGISTER_COMPONENT(binding::component)

View File

@ -6,6 +6,7 @@
#include "version.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
// Fonts used in game:
// fonts/blender_pro_bold.ttf, fonts/blender_pro_book.ttf, fonts/blender_pro_heavy.ttf, fonts/blender_pro_medium.ttf
@ -16,8 +17,6 @@ namespace branding
namespace
{
float color[4] = { 0.666f, 0.666f, 0.666f, 0.666f };
game::dvar_t* branding;
}
class component final : public component_interface
@ -38,12 +37,12 @@ namespace branding
scheduler::once([]()
{
branding = game::Dvar_RegisterBool("branding", true, game::DvarFlags::DVAR_FLAG_SAVED, "Show branding in the top left corner");
dvars::branding = game::Dvar_RegisterBool("branding", true, game::DvarFlags::DVAR_FLAG_SAVED, "Show branding in the top left corner");
}, scheduler::pipeline::renderer);
scheduler::loop([]()
{
if (branding && branding->current.enabled)
if (dvars::branding && dvars::branding->current.enabled)
{
const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20);
if (font)

View File

@ -18,7 +18,8 @@ namespace command
{
namespace
{
utils::hook::detour client_command_hook;
utils::hook::detour client_command_mp_hook;
utils::hook::detour client_command_sp_hook;
utils::hook::detour parse_commandline_hook;
std::unordered_map<std::string, std::function<void(params&)>> handlers;
@ -35,7 +36,7 @@ namespace command
}
}
void client_command(const int client_num)
void client_command_mp(const int client_num)
{
params_sv params = {};
@ -45,7 +46,22 @@ namespace command
handlers_sv[command](client_num, params);
}
client_command_hook.invoke<void>(client_num);
client_command_mp_hook.invoke<void>(client_num);
}
void client_command_sp(const int client_num, const char* s)
{
game::SV_Cmd_TokenizeString(s);
params_sv params = {};
const auto command = utils::string::to_lower(s);
if (handlers_sv.find(command) != handlers_sv.end())
{
handlers_sv[command](client_num, params);
}
game::SV_Cmd_EndTokenizedString();
client_command_sp_hook.invoke<void>(client_num, s);
}
// Shamelessly stolen from Quake3
@ -109,8 +125,8 @@ namespace command
const auto current = game::Dvar_ValueToString(dvar, dvar->current);
const auto reset = game::Dvar_ValueToString(dvar, dvar->reset);
console::info("\"%s\" is: \"%s\" default: \"%s\" hash: 0x%08lX type: %i\n",
args[0], current, reset, dvar->hash, dvar->type);
console::info("\"%s\" is: \"%s\" default: \"%s\" checksum: 0x%08lX type: %i\n",
args[0], current, reset, dvar->checksum, dvar->type);
const auto dvar_info = dvars::dvar_get_description(dvar);
@ -134,16 +150,23 @@ namespace command
void client_println(int client_num, const std::string& text)
{
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
utils::string::va("f \"%s\"", text.data()));
if (game::Com_GameMode_GetActiveGameMode() == game::GAME_TYPE_SP)
{
game::CG_Utils_GameMessage(client_num, text.data(), 0); // why is nothing printed?
}
else
{
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
utils::string::va("f \"%s\"", text.data()));
}
}
bool check_cheats(int client_num)
bool cheats_ok(int client_num)
{
const auto sv_cheats = game::Dvar_FindVar("sv_cheats");
if (!sv_cheats || !sv_cheats->current.enabled)
{
client_println(client_num, "Cheats are not enabled on this server");
client_println(client_num, "GAME_CHEATSNOTENABLED");
return false;
}
@ -289,7 +312,8 @@ namespace command
void post_unpack() override
{
utils::hook::jump(0xBB1DC0_b, dvar_command_stub, true);
client_command_hook.create(0xB105D0_b, &client_command);
//client_command_mp_hook.create(0xB105D0_b, &client_command_mp);
//client_command_sp_hook.create(0x483130_b, &client_command_sp);
add_commands();
}
@ -302,6 +326,76 @@ namespace command
{
*reinterpret_cast<int*>(1) = 0;
});
add("god", []()
{
if (!game::SV_Loaded())
{
return;
}
game::g_entities[0].flags ^= 1;
client_println(0,
game::g_entities[0].flags & 1
? "GAME_GODMODE_ON"
: "GAME_GODMODE_OFF");
});
add("demigod", []()
{
if (!game::SV_Loaded())
{
return;
}
game::g_entities[0].flags ^= 2;
client_println(0,
game::g_entities[0].flags & 2
? "GAME_DEMI_GODMODE_ON"
: "GAME_DEMI_GODMODE_OFF");
});
add("notarget", []()
{
if (!game::SV_Loaded())
{
return;
}
game::g_entities[0].flags ^= 4;
client_println(0,
game::g_entities[0].flags & 4
? "GAME_NOTARGETON"
: "GAME_NOTARGETOFF");
});
add("noclip", []()
{
if (!game::SV_Loaded())
{
return;
}
game::g_entities[0].client->flags ^= 1;
client_println(0,
game::g_entities[0].client->flags & 1
? "GAME_NOCLIPON"
: "GAME_NOCLIPOFF");
});
add("ufo", []()
{
if (!game::SV_Loaded())
{
return;
}
game::g_entities[0].client->flags ^= 1;
client_println(0,
game::g_entities[0].client->flags & 1
? "GAME_UFOON"
: "GAME_UFOOFF");
});
}
};
}

View File

@ -36,7 +36,6 @@ namespace dvars
struct dvar_vector3 : dvar_base
{
float x{};
float y{};
float z{};
@ -93,22 +92,10 @@ namespace dvars
}
utils::hook::detour dvar_register_new_hook;
game::dvar_t* dvar_register_new_internal(const char* name, int hash, game::dvar_type type, unsigned int flags,
game::dvar_value* value, game::dvar_limits* domain, bool level, const char* description)
game::dvar_t* dvar_register_new(const char* name, unsigned int checksum, game::DvarType type, unsigned int flags,
game::DvarValue* value, game::DvarLimits* domain, char level, const char* description)
{
auto* dvar = dvar_register_new_hook.invoke<game::dvar_t*>(name, hash, type, flags, value, domain, level, description);
if (dvar)
{
if (name)
{
dvars::dvar_set_name(dvar, name);
}
if (description)
{
dvars::dvar_set_description(dvar, description);
}
}
auto* dvar = dvar_register_new_hook.invoke<game::dvar_t*>(name, checksum, type, flags, value, domain, level, description);
if (dvar && name && dvar_on_register_function_map.find(name) != dvar_on_register_function_map.end())
{
@ -119,11 +106,13 @@ namespace dvars
return dvar;
}
utils::hook::detour dvar_reregister_hook;
void dvar_reregister(game::dvar_t* dvar, const char* name, game::dvar_type type, unsigned int flags,
game::dvar_value* value, game::dvar_limits* domain, bool level, const char* description)
std::recursive_mutex register_var_lock;
utils::hook::detour dvar_register_variant_hook;
game::dvar_t* dvar_register_variant(const char* name, unsigned int checksum, game::DvarType type, unsigned int flags,
game::DvarValue* value, game::DvarLimits* domain, const char* description)
{
dvar_reregister_hook.invoke<game::dvar_t*>(dvar, name, type, flags, value, domain, level, description);
std::lock_guard<std::recursive_mutex> $(register_var_lock);
auto* dvar = dvar_register_variant_hook.invoke<game::dvar_t*>(name, checksum, type, flags, value, domain, description);
if (dvar)
{
@ -136,6 +125,8 @@ namespace dvars
dvars::dvar_set_description(dvar, description);
}
}
return dvar;
}
class component final : public component_interface
@ -143,9 +134,13 @@ namespace dvars
public:
void post_unpack() override
{
// the post_unpack happens too late for some dvars...
dvar_register_new_hook.create(0xCEBA60_b, dvar_register_new_internal);
dvar_reregister_hook.create(0xCEC210_b, dvar_reregister);
dvar_register_new_hook.create(0xCEBA60_b, dvar_register_new);
dvar_register_variant_hook.create(0xCEBDD0_b, dvar_register_variant);
}
int priority() override
{
return COMPONENT_MAX_PRIORITY - 1;
}
};
}

View File

@ -159,4 +159,4 @@ namespace exception
};
}
//REGISTER_COMPONENT(exception::component)
REGISTER_COMPONENT(exception::component)

View File

@ -75,7 +75,7 @@ namespace fastfiles
void post_unpack() override
{
db_try_load_x_file_internal_hook.create(0x3BBC40_b, db_try_load_x_file_internal_stub);
#if defined(DEBUG) and defined (XFILE_DEBUG)
#if defined(DEBUG) and defined(XFILE_DEBUG)
db_init_load_x_file_hook.create(0x9E8D10_b, db_init_load_x_file_stub);
#else
db_load_x_zone_hook.create(0x3BA920_b, db_load_x_zone_stub);

View File

@ -278,8 +278,17 @@ namespace game_console
if (matches.size() > 24)
{
draw_hint_box(1, dvars::con_inputHintBoxColor->current.vector);
draw_hint_text(0, utils::string::va("%i matches (too many to show here)", matches.size()),
draw_hint_text(0, utils::string::va("%i matches (too many to show here). Press SHIFT + TAB to show more", matches.size()),
dvars::con_inputDvarMatchColor->current.vector);
if (game::playerKeys[0].keys[game::keyNum_t::K_SHIFT].down && game::playerKeys[0].keys[game::keyNum_t::K_TAB].down)
{
console::info("]%s\n", con.buffer);
for (size_t i = 0; i < matches.size(); i++)
{
console::info("\t%s\n", matches[i].data());
}
}
}
else if (matches.size() == 1)
{
@ -304,7 +313,7 @@ namespace game_console
color_white, 0);
const auto offset_y = height + 3.f;
const auto line_count_ = dvar->type == game::dvar_type::enumeration
const auto line_count_ = dvar->type == game::DvarType::enumeration
? dvar->domain.enumeration.stringCount + 1
: 1;
@ -334,11 +343,15 @@ namespace game_console
if (dvar)
{
draw_hint_text(static_cast<int>(i), game::Dvar_ValueToString(dvar, dvar->current),
const auto value = game::Dvar_ValueToString(dvar, dvar->current);
draw_hint_text(static_cast<int>(i), value,
dvars::con_inputDvarValueColor->current.vector, offset_value);
draw_hint_text(static_cast<int>(i), dvars::dvar_get_description(dvar).data(),
dvars::con_inputDvarValueColor->current.vector, offset_description);
if (strlen(value) < 0x18)
{
draw_hint_text(static_cast<int>(i), dvars::dvar_get_description(dvar).data(),
dvars::con_inputDvarValueColor->current.vector, offset_description);
}
}
}
@ -554,7 +567,7 @@ namespace game_console
return false;
}
if (key < 32)
if (key < ' ')
{
return false;
}

View File

@ -0,0 +1,74 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "dvars.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
namespace renderer
{
namespace
{
utils::hook::detour r_init_draw_method_hook;
utils::hook::detour r_update_front_end_dvar_options_hook;
int get_fullbright_technique()
{
switch (dvars::r_fullbright->current.integer)
{
case 2:
return game::TECHNIQUE_LIT;
default:
return game::TECHNIQUE_UNLIT;
}
}
void gfxdrawmethod()
{
game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD;
game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_LIT;
game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE;
game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_LIT;
}
void r_init_draw_method_stub()
{
gfxdrawmethod();
}
bool r_update_front_end_dvar_options_stub()
{
if (dvars::r_fullbright->modified)
{
game::Dvar_ClearModified(dvars::r_fullbright);
game::R_SyncRenderThread();
gfxdrawmethod();
}
return r_update_front_end_dvar_options_hook.invoke<bool>();
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_dedi())
{
return;
}
dvars::r_fullbright = game::Dvar_RegisterInt("r_fullbright", 0, 0, 2, game::DVAR_FLAG_SAVED, "Toggles rendering without lighting");
r_init_draw_method_hook.create(0xDE9260_b, &r_init_draw_method_stub);
r_update_front_end_dvar_options_hook.create(0xE28B60_b, &r_update_front_end_dvar_options_stub);
}
};
}
REGISTER_COMPONENT(renderer::component)

View File

@ -56,7 +56,6 @@ namespace system_check
static std::unordered_map<std::string, std::string> sp_zone_hashes =
{
// Steam doesn't necessarily deliver this file :(
{"patch_common.ff", "A427FDFBFCF16B0BA662459383C48AE15C884B9B44C61C12B98E062FBC4C6DB3"},
};

View File

@ -19,7 +19,11 @@ namespace dvars
game::dvar_t* con_inputDvarInactiveValueColor = nullptr;
game::dvar_t* con_inputCmdMatchColor = nullptr;
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
game::dvar_t* branding = nullptr;
game::dvar_t* r_fullbright = nullptr;
std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain)
{
if (domain.vector.min == -FLT_MAX)
{
@ -45,16 +49,16 @@ namespace dvars
}
}
std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain)
std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain)
{
std::string str;
switch (type)
{
case game::dvar_type::boolean:
case game::DvarType::boolean:
return "Domain is 0 or 1"s;
case game::dvar_type::value:
case game::DvarType::value:
if (domain.value.min == -FLT_MAX)
{
if (domain.value.max == FLT_MAX)
@ -75,17 +79,17 @@ namespace dvars
return utils::string::va("Domain is any number from %g to %g", domain.value.min, domain.value.max);
}
case game::dvar_type::vec2:
case game::DvarType::vec2:
return dvar_get_vector_domain(2, domain);
case game::dvar_type::rgb:
case game::dvar_type::vec3:
case game::DvarType::rgb:
case game::DvarType::vec3:
return dvar_get_vector_domain(3, domain);
case game::dvar_type::vec4:
case game::DvarType::vec4:
return dvar_get_vector_domain(4, domain);
case game::dvar_type::integer:
case game::DvarType::integer:
if (domain.enumeration.stringCount == INT_MIN)
{
if (domain.integer.max == INT_MAX)
@ -106,10 +110,10 @@ namespace dvars
return utils::string::va("Domain is any integer from %i to %i", domain.integer.min, domain.integer.max);
}
case game::dvar_type::color:
case game::DvarType::color:
return "Domain is any 4-component color, in RGBA format"s;
case game::dvar_type::enumeration:
case game::DvarType::enumeration:
str = "Domain is one of the following:"s;
for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index)
@ -119,7 +123,7 @@ namespace dvars
return str;
case game::dvar_type::string:
case game::DvarType::string:
return "Domain is any text"s;
default:

View File

@ -15,8 +15,12 @@ namespace dvars
extern game::dvar_t* con_inputDvarInactiveValueColor;
extern game::dvar_t* con_inputCmdMatchColor;
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain);
std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain);
extern game::dvar_t* branding;
extern game::dvar_t* r_fullbright;
std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain);
std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain);
std::string dvar_get_name(const game::dvar_t* dvar);
std::string dvar_get_description(const game::dvar_t* dvar);
void dvar_set_name(const game::dvar_t* dvar, const std::string& name);

View File

@ -33,11 +33,6 @@ namespace game
return sv_cmd_args->argv[sv_cmd_args->nesting][index];
}
bool VirtualLobby_Loaded()
{
return 0; //return *mp::virtualLobby_loaded == 1;
}
const char* g_assetNames[ASSET_TYPE_COUNT] =
{
"physicslibrary",
@ -81,13 +76,13 @@ namespace game
"attachment",
"weapon",
"vfx",
"impactfx", // not confirmed
"surfacefx", // not confirmed
"aitype", // not confirmed
"mptype", // not confirmed
"character", // not confirmed
"xmodelalias", // not confirmed
"ASSET_TYPE_UNKNOWN", // not confirmed
"impactfx",
"surfacefx",
"aitype",
"mptype",
"character",
"xmodelalias",
"ASSET_TYPE_UNKNOWN",
"rawfile",
"scriptfile",
"stringtable",

View File

@ -48,8 +48,6 @@ namespace game
int SV_Cmd_Argc();
const char* SV_Cmd_Argv(int index);
bool VirtualLobby_Loaded();
extern const char* g_assetNames[ASSET_TYPE_COUNT];
const char* DB_GetXAssetName(const XAsset* asset);
void DB_EnumXAssets(const std::int32_t type, const std::function<void(XAssetHeader)>& callback);

View File

@ -14,6 +14,14 @@ namespace game
{
};
enum GameModeType : std::uint32_t
{
GAME_TYPE_NONE = 0x0,
GAME_TYPE_SP = 0x1,
GAME_TYPE_MP = 0x2,
GAME_TYPE_CP = 0x3,
};
struct CmdArgs
{
int nesting;
@ -51,8 +59,20 @@ namespace game
DVAR_FLAG_READ = 0x2000,
};
enum dvar_type : std::int8_t
enum DvarType : std::uint8_t
{
DVAR_TYPE_BOOL = 0x0,
DVAR_TYPE_FLOAT = 0x1,
DVAR_TYPE_FLOAT_2 = 0x2,
DVAR_TYPE_FLOAT_3 = 0x3,
DVAR_TYPE_FLOAT_4 = 0x4,
DVAR_TYPE_INT = 0x5,
DVAR_TYPE_ENUM = 0x6,
DVAR_TYPE_STRING = 0x7,
DVAR_TYPE_COLOR = 0x8,
DVAR_TYPE_FLOAT_3_COLOR = 0x9,
DVAR_TYPE_COUNT = 0xA,
boolean = 0,
value = 1,
vec2 = 2,
@ -62,10 +82,10 @@ namespace game
enumeration = 6,
string = 7,
color = 8,
rgb = 9 // Color without alpha
rgb = 9, // Color without alpha
};
union dvar_value
union DvarValue
{
bool enabled;
int integer;
@ -94,7 +114,7 @@ namespace game
float max;
};
union dvar_limits
union DvarLimits
{
$A37BA207B3DDD6345C554D4661813EDD enumeration;
$9CA192F9DB66A3CB7E01DE78A0DEA53D integer;
@ -104,17 +124,17 @@ namespace game
struct dvar_t
{
int hash; // 0
unsigned int flags; // 4
bool unk; // 8 tls value?
dvar_type type; // 9
bool modified; // 10
dvar_value current; // 16
dvar_value latched; // 32
dvar_value reset; // 48
dvar_limits domain; // 64
char unk2; // 80 always 0?
void* unk3; // 88 some pointer related to hash?
unsigned int checksum;
unsigned int flags;
char level;
DvarType type;
bool modified;
DvarValue current;
DvarValue latched;
DvarValue reset;
DvarLimits domain;
bool(__fastcall* domainFunc)(dvar_t*, DvarValue);
dvar_t* hashNext;
}; static_assert(sizeof(dvar_t) == 96);
enum svscmd_type
@ -271,7 +291,7 @@ namespace game
int down;
int unk;
int repeats;
int unk2;
int binding;
};
struct field_t
@ -438,13 +458,13 @@ namespace game
ASSET_TYPE_ATTACHMENT = 38,
ASSET_TYPE_WEAPON = 39,
ASSET_TYPE_VFX = 40,
ASSET_TYPE_IMPACT_FX = 41, // not confirmed
ASSET_TYPE_SURFACE_FX = 42, // not confirmed
ASSET_TYPE_AITYPE = 43, // not confirmed + unused
ASSET_TYPE_MPTYPE = 44, // not confirmed + unused
ASSET_TYPE_CHARACTER = 45, // not confirmed + unused
ASSET_TYPE_XMODELALIAS = 46, // not confirmed + unused
ASSET_TYPE_UNKNOWN = 47, // not confirmed + unused
ASSET_TYPE_IMPACT_FX = 41,
ASSET_TYPE_SURFACE_FX = 42,
ASSET_TYPE_AITYPE = 43, // unused
ASSET_TYPE_MPTYPE = 44, // unused
ASSET_TYPE_CHARACTER = 45, // unused
ASSET_TYPE_XMODELALIAS = 46, // unused
ASSET_TYPE_UNKNOWN = 47, // unused
ASSET_TYPE_RAWFILE = 48,
ASSET_TYPE_SCRIPTFILE = 49,
ASSET_TYPE_STRINGTABLE = 50,
@ -1468,6 +1488,26 @@ namespace game
TTFDef* ttfDef;
};
enum MaterialTechniqueType
{
TECHNIQUE_UNLIT = 8,
TECHNIQUE_EMISSIVE = 10,
TECHNIQUE_LIT = 13,
};
enum GfxDrawSceneMethod
{
GFX_DRAW_SCENE_STANDARD = 0x1,
};
struct GfxDrawMethod
{
int drawScene;
int baseTechType;
int emissiveTechType;
int forceTechType;
};
namespace demonware
{
enum DWOnlineStatus

View File

@ -10,9 +10,15 @@ namespace game
WEAK symbol<void()> Com_Quit_f{ 0xBADC90 };
WEAK symbol<bool()> Com_FrontEndScene_IsActive{ 0x5AEBA0 };
WEAK symbol<GameModeType()> Com_GameMode_GetActiveGameMode{ 0x5AFD50 };
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{ 0xB7C290 };
WEAK symbol<void(int localClientNum, void(*))> Cbuf_AddCall{ 0xB7C220 };
WEAK symbol<void(int localClientNum, const char* msg, int flags)> CG_Utils_GameMessage{ 0x1D7FC0 };
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{ 0xB7D040 };
WEAK symbol<void(const char* cmdName, void(), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{ 0xB7C8F0 };
WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{ 0xB7D630 };
@ -41,12 +47,17 @@ namespace game
WEAK symbol<void(const char* name, const char* string)> Dvar_SetCommand{ 0xCECB30 };
WEAK symbol<dvar_t* (const char* name)> Dvar_FindVar{ 0xCEA460 };
WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{ 0xCE9E90 };
WEAK symbol<void(char* buffer, int index)> Dvar_GetCombinedString{ 0xBB1F30 };
WEAK symbol<const char* (dvar_t* dvar, dvar_value value)> Dvar_ValueToString{ 0xCEED00 };
WEAK symbol<const char* (dvar_t* dvar, DvarValue value)> Dvar_ValueToString{ 0xCEED00 };
WEAK symbol<int(const char* name)> Dvar_GenerateChecksum{ 0xCEA520 };
#define Dvar_GenerateHash(name) \
Dvar_GenerateChecksum(name);
WEAK symbol<const char* (int, int, int)> Key_KeynumToString{ 0x9A95E0 };
WEAK symbol<bool()> LUI_CoD_InFrontEnd{ 0x615080 };
WEAK symbol<unsigned int(int controllerIndex)> Live_SyncOnlineDataFlags{ 0xDC5CE0 };
WEAK symbol<Material* (const char* material)> Material_RegisterHandle{ 0xE11CE0 };
@ -82,6 +93,9 @@ namespace game
WEAK symbol<CmdArgs> sv_cmd_args{ 0x5D65C20 };
WEAK symbol<CmdArgs> cmd_args{ 0x5D65B70 };
WEAK symbol<cmd_function_s*> cmd_functions{ 0x5D65CC8 };
WEAK symbol<const char*> command_whitelist{ 0x14D1B70 };
WEAK symbol<GfxDrawMethod> gfxDrawMethod{ 0x83E86A8 };
WEAK symbol<int> keyCatchers{ 0x2246C34 };
WEAK symbol<PlayerKeyState> playerKeys{ 0x523BA0C };

View File

@ -32,4 +32,9 @@ public:
{
return true;
}
virtual int priority()
{
return 0;
}
};

View File

@ -1,8 +1,12 @@
#include <std_include.hpp>
#include "component_loader.hpp"
void component_loader::register_component(std::unique_ptr<component_interface>&& component_)
void component_loader::register_component(std::unique_ptr<component_interface>&& component_, [[maybe_unused]] const std::string& name)
{
#ifdef DEBUG
printf("registering component: %s\n", name.data());
#endif
get_components().push_back(std::move(component_));
}
@ -33,8 +37,6 @@ bool component_loader::post_load()
if (handled) return true;
handled = true;
clean();
try
{
for (const auto& component_ : get_components())
@ -65,7 +67,7 @@ void component_loader::post_unpack()
catch (std::exception& e)
{
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
quick_exit(-1);
quick_exit(EXIT_FAILURE);
}
}
}
@ -78,7 +80,15 @@ void component_loader::pre_destroy()
for (const auto& component_ : get_components())
{
component_->pre_destroy();
try
{
component_->pre_destroy();
}
catch (std::exception& e)
{
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
quick_exit(EXIT_FAILURE);
}
}
}
@ -99,6 +109,17 @@ void component_loader::clean()
}
}
void component_loader::sort()
{
auto& components = get_components();
std::ranges::stable_sort(components, [](const std::unique_ptr<component_interface>& a,
const std::unique_ptr<component_interface>& b)
{
return a->priority() > b->priority();
});
}
void* component_loader::load_import(const std::string& library, const std::string& function)
{
void* function_ptr = nullptr;

View File

@ -1,6 +1,8 @@
#pragma once
#include "component_interface.hpp"
#define COMPONENT_MAX_PRIORITY 999
class component_loader final
{
public:
@ -22,6 +24,17 @@ public:
{
register_component(std::make_unique<T>());
}
installer(const std::string& component_name)
{
register_component(
std::make_unique<T>(),
std::string(
component_name.begin(),
component_name.begin() + component_name.find("::")
)
);
}
};
template <typename T>
@ -38,13 +51,14 @@ public:
return nullptr;
}
static void register_component(std::unique_ptr<component_interface>&& component);
static void register_component(std::unique_ptr<component_interface>&& component, const std::string& name = "(unnamed)");
static bool post_start();
static bool post_load();
static void post_unpack();
static void pre_destroy();
static void clean();
static void sort();
static void* load_import(const std::string& library, const std::string& function);
@ -54,8 +68,9 @@ private:
static std::vector<std::unique_ptr<component_interface>>& get_components();
};
#define REGISTER_COMPONENT(name) \
namespace \
{ \
static component_loader::installer<name> __component; \
#define REGISTER_COMPONENT(name) \
namespace \
{ \
static component_loader::installer<name> __component = component_loader::installer<name>(#name); \
}

View File

@ -36,7 +36,8 @@ FARPROC load_binary(uint64_t* base_address)
}
else if (function == "SystemParametersInfoA")
{
return system_parameters_info_a;
// post_unpack called from SteamAPI_Init
//return system_parameters_info_a;
}
return component_loader::load_import(library, function);
@ -118,6 +119,9 @@ int main()
remove_crash_file();
{
component_loader::sort();
component_loader::clean();
auto premature_shutdown = true;
const auto _ = gsl::finally([&premature_shutdown]()
{
@ -129,7 +133,7 @@ int main()
try
{
if (!component_loader::post_start()) return 0;
if (!component_loader::post_start()) return EXIT_FAILURE;
uint64_t base_address{};
entry_point = load_binary(&base_address);
@ -146,14 +150,14 @@ int main()
}
game::base_address = base_address;
if (!component_loader::post_load()) return 0;
if (!component_loader::post_load()) return EXIT_FAILURE;
premature_shutdown = false;
}
catch (std::exception& e)
{
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
return 1;
return EXIT_FAILURE;
}
}

View File

@ -101,3 +101,5 @@
#include "resource.hpp"
using namespace std::literals;
#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

View File

@ -3,6 +3,8 @@
#include <utils/nt.hpp>
#include "loader/component_loader.hpp"
namespace steam
{
uint64_t callbacks::call_id_ = 0;
@ -111,12 +113,14 @@ namespace steam
bool SteamAPI_Init()
{
const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath();
if (steam_path.empty()) return true;
if (steam_path.empty()) return false;
::utils::nt::library::load(steam_path / "tier0_s64.dll");
::utils::nt::library::load(steam_path / "vstdlib_s64.dll");
::utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll");
::utils::nt::library::load(steam_path / "steamclient64.dll");
component_loader::post_unpack();
return true;
}