small clean up [skip ci]

also no compiler err's
This commit is contained in:
Skull Merlin
2022-03-18 03:19:50 +02:00
parent aabe0b427b
commit 369b0f3a1c
63 changed files with 3 additions and 9442 deletions

View File

@ -1,103 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "command.hpp"
#include "scheduler.hpp"
#include "network.hpp"
#include "party.hpp"
#include "game/game.hpp"
#include "game/scripting/execution.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include <utils/cryptography.hpp>
namespace bots
{
namespace
{
bool can_add()
{
if (party::get_client_count() < *game::mp::svs_numclients)
{
return true;
}
return false;
}
// TODO: when scripting comes, fix this to use better notifies
void bot_team_join(const int entity_num)
{
const game::scr_entref_t entref{static_cast<uint16_t>(entity_num), 0};
scheduler::once([entref]()
{
scripting::notify(entref, "luinotifyserver", {"team_select", 2});
scheduler::once([entref]()
{
auto* _class = utils::string::va("class%d", utils::cryptography::random::get_integer() % 5);
scripting::notify(entref, "luinotifyserver", {"class_select", _class});
}, scheduler::pipeline::server, 2s);
}, scheduler::pipeline::server, 2s);
}
void spawn_bot(const int entity_num)
{
game::SV_SpawnTestClient(&game::mp::g_entities[entity_num]);
if (game::Com_GetCurrentCoDPlayMode() == game::CODPLAYMODE_CORE)
{
bot_team_join(entity_num);
}
}
void add_bot()
{
if (!can_add())
{
return;
}
// SV_BotGetRandomName
const auto* const bot_name = game::SV_BotGetRandomName();
auto* bot_ent = game::SV_AddBot(bot_name);
if (bot_ent)
{
spawn_bot(bot_ent->s.entityNum);
}
else if (can_add()) // workaround since first bot won't ever spawn
{
add_bot();
}
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_sp())
{
return;
}
command::add("spawnBot", [](const command::params& params)
{
if (!game::SV_Loaded() || game::VirtualLobby_Loaded()) return;
auto num_bots = 1;
if (params.size() == 2)
{
num_bots = atoi(params.get(1));
}
for (auto i = 0; i < (num_bots > *game::mp::svs_numclients ? *game::mp::svs_numclients : num_bots); i++)
{
scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i);
}
});
}
};
}
REGISTER_COMPONENT(bots::component)

View File

@ -1,317 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "game/scripting/entity.hpp"
#include "game/scripting/execution.hpp"
#include "game/scripting/lua/value_conversion.hpp"
#include "game/scripting/lua/error.hpp"
#include <utils/hook.hpp>
#include "logfile.hpp"
namespace logfile
{
std::unordered_map<const char*, sol::protected_function> vm_execute_hooks;
namespace
{
utils::hook::detour scr_player_killed_hook;
utils::hook::detour scr_player_damage_hook;
std::vector<sol::protected_function> player_killed_callbacks;
std::vector<sol::protected_function> player_damage_callbacks;
utils::hook::detour vm_execute_hook;
char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END
bool hook_enabled = true;
sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent)
{
if (!ent)
{
return {};
}
const scripting::entity player{game::Scr_GetEntityId(ent->s.entityNum, 0)};
return scripting::lua::convert(state, player);
}
std::string get_weapon_name(unsigned int weapon, bool isAlternate)
{
char output[1024] = {0};
game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024);
return output;
}
sol::lua_value convert_vector(lua_State* state, const float* vec)
{
if (!vec)
{
return {};
}
const auto vec_ = scripting::vector(vec);
return scripting::lua::convert(state, vec_);
}
std::string convert_mod(const int meansOfDeath)
{
const auto value = reinterpret_cast<game::scr_string_t**>(0x140FEC3F0)[meansOfDeath];
const auto string = game::SL_ConvertToString(*value);
return string;
}
void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor,
game::mp::gentity_s* attacker, int damage, const int meansOfDeath, const unsigned int weapon,
const bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration)
{
{
const std::string hitloc = reinterpret_cast<const char**>(0x140FEC4D0)[hitLoc];
const auto mod_ = convert_mod(meansOfDeath);
const auto weapon_ = get_weapon_name(weapon, isAlternate);
for (const auto& callback : player_killed_callbacks)
{
const auto state = callback.lua_state();
const auto self_ = convert_entity(state, self);
const auto inflictor_ = convert_entity(state, inflictor);
const auto attacker_ = convert_entity(state, attacker);
const auto dir = convert_vector(state, vDir);
const auto result = callback(self_, inflictor_, attacker_, damage,
mod_, weapon_, dir, hitloc, psTimeOffset, deathAnimDuration);
scripting::lua::handle_error(result);
if (result.valid() && result.get_type() == sol::type::number)
{
damage = result.get<int>();
}
}
if (damage == 0)
{
return;
}
}
scr_player_killed_hook.invoke<void>(self, inflictor, attacker, damage, meansOfDeath,
weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration);
}
void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor,
game::mp::gentity_s* attacker, int damage, int dflags, const int meansOfDeath,
const unsigned int weapon, const bool isAlternate, const float* vPoint,
const float* vDir, const unsigned int hitLoc, const int timeOffset)
{
{
const std::string hitloc = reinterpret_cast<const char**>(0x140FEC4D0)[hitLoc];
const auto mod_ = convert_mod(meansOfDeath);
const auto weapon_ = get_weapon_name(weapon, isAlternate);
for (const auto& callback : player_damage_callbacks)
{
const auto state = callback.lua_state();
const auto self_ = convert_entity(state, self);
const auto inflictor_ = convert_entity(state, inflictor);
const auto attacker_ = convert_entity(state, attacker);
const auto point = convert_vector(state, vPoint);
const auto dir = convert_vector(state, vDir);
const auto result = callback(self_, inflictor_, attacker_,
damage, dflags, mod_, weapon_, point, dir, hitloc);
scripting::lua::handle_error(result);
if (result.valid() && result.get_type() == sol::type::number)
{
damage = result.get<int>();
}
}
if (damage == 0)
{
return;
}
}
scr_player_damage_hook.invoke<void>(self, inflictor, attacker, damage, dflags,
meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset);
}
void client_command_stub(const int clientNum)
{
auto self = &game::mp::g_entities[clientNum];
char cmd[1024] = {0};
game::SV_Cmd_ArgvBuffer(0, cmd, 1024);
if (cmd == "say"s || cmd == "say_team"s)
{
auto hidden = false;
std::string message(game::ConcatArgs(1));
hidden = message[1] == '/';
message.erase(0, hidden ? 2 : 1);
scheduler::once([cmd, message, self]()
{
const scripting::entity level{*game::levelEntityId};
const scripting::entity player{game::Scr_GetEntityId(self->s.entityNum, 0)};
scripting::notify(level, cmd, {player, message});
scripting::notify(player, cmd, {message});
}, scheduler::pipeline::server);
if (hidden)
{
return;
}
}
// ClientCommand
return utils::hook::invoke<void>(0x140336000, clientNum);
}
void g_shutdown_game_stub(const int freeScripts)
{
{
const scripting::entity level{*game::levelEntityId};
scripting::notify(level, "shutdownGame_called", {1});
}
// G_ShutdownGame
return utils::hook::invoke<void>(0x140345A60, freeScripts);
}
unsigned int local_id_to_entity(unsigned int local_id)
{
const auto variable = game::scr_VarGlob->objectVariableValue[local_id];
return variable.u.f.next;
}
bool execute_vm_hook(const char* pos)
{
if (vm_execute_hooks.find(pos) == vm_execute_hooks.end())
{
hook_enabled = true;
return false;
}
if (!hook_enabled && pos > reinterpret_cast<char*>(vm_execute_hooks.size()))
{
hook_enabled = true;
return false;
}
const auto hook = vm_execute_hooks[pos];
const auto state = hook.lua_state();
const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
std::vector<sol::lua_value> args;
const auto top = game::scr_function_stack->top;
for (auto* value = top; value->type != game::SCRIPT_END; --value)
{
args.push_back(scripting::lua::convert(state, *value));
}
const auto result = hook(self, sol::as_args(args));
scripting::lua::handle_error(result);
return true;
}
void vm_execute_stub(utils::hook::assembler& a)
{
const auto replace = a.newLabel();
const auto end = a.newLabel();
a.pushad64();
a.mov(rcx, r14);
a.call_aligned(execute_vm_hook);
a.cmp(al, 0);
a.jne(replace);
a.popad64();
a.jmp(end);
a.bind(end);
a.movzx(r15d, byte_ptr(r14));
a.inc(r14);
a.mov(dword_ptr(rbp, 0xA4), r15d);
a.jmp(SELECT_VALUE(0x140376663, 0x140444653));
a.bind(replace);
a.popad64();
a.mov(r14, reinterpret_cast<char*>(empty_function));
a.jmp(end);
}
}
void add_player_damage_callback(const sol::protected_function& callback)
{
player_damage_callbacks.push_back(callback);
}
void add_player_killed_callback(const sol::protected_function& callback)
{
player_killed_callbacks.push_back(callback);
}
void clear_callbacks()
{
player_damage_callbacks.clear();
player_killed_callbacks.clear();
vm_execute_hooks.clear();
}
void enable_vm_execute_hook()
{
hook_enabled = true;
}
void disable_vm_execute_hook()
{
hook_enabled = false;
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_sp())
{
return;
}
utils::hook::call(0x14048191D, client_command_stub);
scr_player_damage_hook.create(0x14037DC50, scr_player_damage_stub);
scr_player_killed_hook.create(0x14037DF30, scr_player_killed_stub);
utils::hook::call(0x140484EC0, g_shutdown_game_stub);
utils::hook::call(0x1404853C1, g_shutdown_game_stub);
utils::hook::jump(SELECT_VALUE(0x140376655, 0x140444645), utils::hook::assemble(vm_execute_stub), true);
}
};
}
REGISTER_COMPONENT(logfile::component)

View File

@ -1,13 +0,0 @@
#pragma once
namespace logfile
{
extern std::unordered_map<const char*, sol::protected_function> vm_execute_hooks;
void add_player_damage_callback(const sol::protected_function& callback);
void add_player_killed_callback(const sol::protected_function& callback);
void clear_callbacks();
void enable_vm_execute_hook();
void disable_vm_execute_hook();
}

View File

@ -1,58 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "command.hpp"
#include "console.hpp"
#include <utils/hook.hpp>
namespace lui
{
class component final : public component_interface
{
public:
void post_unpack() override
{
// Don't show create cod account popup
//utils::hook::set<uint32_t>(0x14017C957, 0); // H1(1.4)
//#ifdef _DEBUG
// Enable development menus (causes issues in sp)
//utils::hook::set<uint32_t>(SELECT_VALUE(0x1400B4ABC, 0x1401AB779), 1);
//#endif
command::add("lui_open", [](const command::params& params)
{
if (params.size() <= 1)
{
console::info("usage: lui_open <name>\n");
return;
}
game::LUI_OpenMenu(0, params[1], 0, 0, 0);
});
command::add("lui_open_popup", [](const command::params& params)
{
if (params.size() <= 1)
{
console::info("usage: lui_open_popup <name>\n");
return;
}
game::LUI_OpenMenu(0, params[1], 1, 0, 0);
});
command::add("runMenuScript", [](const command::params& params)
{
const auto args_str = params.join(1);
const auto* args = args_str.data();
game::UI_RunMenuScript(0, &args);
});
}
};
}
REGISTER_COMPONENT(lui::component)

View File

@ -1,141 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include <utils/hook.hpp>
#include "game/scripting/entity.hpp"
#include "game/scripting/functions.hpp"
#include "game/scripting/event.hpp"
#include "game/scripting/lua/engine.hpp"
#include "game/scripting/execution.hpp"
#include "scheduler.hpp"
#include "scripting.hpp"
namespace scripting
{
std::unordered_map<int, std::unordered_map<std::string, int>> fields_table;
std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table;
namespace
{
utils::hook::detour vm_notify_hook;
utils::hook::detour scr_load_level_hook;
utils::hook::detour g_shutdown_game_hook;
utils::hook::detour scr_add_class_field_hook;
utils::hook::detour scr_set_thread_position_hook;
utils::hook::detour process_script_hook;
std::string current_file;
void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value,
game::VariableValue* top)
{
if (!game::VirtualLobby_Loaded())
{
const auto* string = game::SL_ConvertToString(string_value);
if (string)
{
event e;
e.name = string;
e.entity = notify_list_owner_id;
for (auto* value = top; value->type != game::SCRIPT_END; --value)
{
e.arguments.emplace_back(*value);
}
if (e.name == "entitydeleted")
{
scripting::clear_entity_fields(e.entity);
}
lua::engine::notify(e);
}
}
vm_notify_hook.invoke<void>(notify_list_owner_id, string_value, top);
}
void scr_load_level_stub()
{
scr_load_level_hook.invoke<void>();
if (!game::VirtualLobby_Loaded())
{
lua::engine::start();
}
}
void g_shutdown_game_stub(const int free_scripts)
{
lua::engine::stop();
return g_shutdown_game_hook.invoke<void>(free_scripts);
}
void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t _name, unsigned int canonicalString, unsigned int offset)
{
const auto name = game::SL_ConvertToString(_name);
if (fields_table[classnum].find(name) == fields_table[classnum].end())
{
fields_table[classnum][name] = offset;
}
scr_add_class_field_hook.invoke<void>(classnum, _name, canonicalString, offset);
}
void process_script_stub(const char* filename)
{
const auto file_id = atoi(filename);
if (file_id)
{
current_file = scripting::find_token(file_id);
}
else
{
current_file = filename;
}
process_script_hook.invoke<void>(filename);
}
void scr_set_thread_position_stub(unsigned int threadName, const char* codePos)
{
const auto function_name = scripting::find_token(threadName);
script_function_table[current_file][function_name] = codePos;
scr_set_thread_position_hook.invoke<void>(threadName, codePos);
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_sp())
{
return;
}
vm_notify_hook.create(SELECT_VALUE(0x140379A00, 0x1404479F0), vm_notify_stub);
scr_add_class_field_hook.create(SELECT_VALUE(0x140370370, 0x14043E2C0), scr_add_class_field_stub);
scr_set_thread_position_hook.create(SELECT_VALUE(0x14036A180, 0x140437D10), scr_set_thread_position_stub);
process_script_hook.create(SELECT_VALUE(0x1403737E0, 0x1404417E0), process_script_stub);
scr_load_level_hook.create(SELECT_VALUE(0x1402A5BE0, 0x1403727C0), scr_load_level_stub);
g_shutdown_game_hook.create(SELECT_VALUE(0x140277D40, 0x140345A60), g_shutdown_game_stub);
scheduler::loop([]()
{
lua::engine::run_frame();
}, scheduler::pipeline::server);
}
};
}
REGISTER_COMPONENT(scripting::component)

View File

@ -1,8 +0,0 @@
#pragma once
#include <utils/concurrency.hpp>
namespace scripting
{
extern std::unordered_map<int, std::unordered_map<std::string, int>> fields_table;
extern std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table;
}

View File

@ -1,50 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "dvars.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/nt.hpp>
#include <utils/hook.hpp>
#include <utils/flags.hpp>
namespace shaders
{
namespace
{
game::dvar_t* disable_shader_caching = nullptr;
bool shader_should_show_dialog_stub()
{
return !disable_shader_caching->current.enabled;
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (!game::environment::is_mp())
{
return;
}
const auto has_flag = utils::flags::has_flag("noshadercaching");
disable_shader_caching = dvars::register_bool("disable_shader_caching", has_flag, game::DVAR_FLAG_SAVED, true);
if (has_flag)
{
dvars::override::set_bool("disable_shader_caching", 1);
dvars::override::set_from_string("disable_shader_caching", "1");
}
utils::hook::jump(0x14007E710, shader_should_show_dialog_stub);
}
};
}
REGISTER_COMPONENT(shaders::component)

View File

@ -1,53 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace slowmotion
{
namespace
{
void scr_cmd_set_slow_motion()
{
if (game::Scr_GetNumParam() < 1)
{
return;
}
int duration = 1000;
float end = 1.0f;
const float start = game::Scr_GetFloat(0);
if (game::Scr_GetNumParam() >= 2)
{
end = game::Scr_GetFloat(1u);
}
if (game::Scr_GetNumParam() >= 3)
{
duration = static_cast<int>(game::Scr_GetFloat(2u) * 1000.0f);
}
game::SV_SetConfigstring(10, utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end));
game::Com_SetSlowMotion(start, end, duration);
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (!game::environment::is_dedi())
{
return;
}
utils::hook::jump(0x140365480, scr_cmd_set_slow_motion); // H1(1.4)
}
};
}
REGISTER_COMPONENT(slowmotion::component)

View File

@ -1,60 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "game/game.hpp"
#include <utils/thread.hpp>
namespace thread_names
{
namespace
{
void set_thread_names()
{
static std::unordered_map<int, std::string> thread_names =
{
{game::THREAD_CONTEXT_MAIN, "Main"},
{game::THREAD_CONTEXT_BACKEND, "Backend"}, // Renderer
{game::THREAD_CONTEXT_WORKER0, "Worker0"},
{game::THREAD_CONTEXT_WORKER1, "Worker1"},
{game::THREAD_CONTEXT_WORKER2, "Worker2"},
{game::THREAD_CONTEXT_WORKER3, "Worker3"},
{game::THREAD_CONTEXT_WORKER4, "Worker4"},
{game::THREAD_CONTEXT_WORKER5, "Worker5"},
{game::THREAD_CONTEXT_WORKER6, "Worker6"},
{game::THREAD_CONTEXT_WORKER7, "Worker7"},
{game::THREAD_CONTEXT_SERVER, "Server"},
{game::THREAD_CONTEXT_CINEMATIC, "Cinematic"},
{game::THREAD_CONTEXT_DATABASE, "Database"},
{game::THREAD_CONTEXT_STREAM, "Stream"},
{game::THREAD_CONTEXT_SNDSTREAMPACKETCALLBACK, "Snd stream packet callback"},
{game::THREAD_CONTEXT_STATS_WRITE, "Stats write"},
};
for (const auto& thread_name : thread_names)
{
const auto id = game::threadIds[thread_name.first];
if (id)
{
utils::thread::set_name(id, thread_name.second);
}
}
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
set_thread_names();
scheduler::once(set_thread_names, scheduler::pipeline::main);
scheduler::once(set_thread_names, scheduler::pipeline::renderer);
scheduler::once(set_thread_names, scheduler::pipeline::server);
}
};
}
REGISTER_COMPONENT(thread_names::component)

View File

@ -1,180 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include "scheduler.hpp"
#include "command.hpp"
#include "ui_scripting.hpp"
#include "game/ui_scripting/lua/engine.hpp"
#include "game/ui_scripting/execution.hpp"
#include "game/ui_scripting/lua/error.hpp"
#include <utils/string.hpp>
#include <utils/hook.hpp>
namespace ui_scripting
{
namespace
{
std::unordered_map<game::hks::cclosure*, sol::protected_function> converted_functions;
utils::hook::detour hksi_lual_error_hook;
utils::hook::detour hksi_lual_error_hook2;
utils::hook::detour hks_start_hook;
utils::hook::detour hks_shutdown_hook;
utils::hook::detour hks_allocator_hook;
utils::hook::detour hks_frame_hook;
bool error_hook_enabled = false;
void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...)
{
char va_buffer[2048] = {0};
va_list ap;
va_start(ap, fmt);
vsprintf_s(va_buffer, fmt, ap);
va_end(ap);
const auto formatted = std::string(va_buffer);
if (!error_hook_enabled)
{
return hksi_lual_error_hook.invoke<void>(s, formatted.data());
}
else
{
throw std::runtime_error(formatted);
}
}
void* hks_start_stub(char a1)
{
const auto _1 = gsl::finally([]()
{
ui_scripting::lua::engine::start();
});
return hks_start_hook.invoke<void*>(a1);
}
void hks_shutdown_stub()
{
ui_scripting::lua::engine::stop();
hks_shutdown_hook.invoke<void*>();
}
void* hks_allocator_stub(void* userData, void* oldMemory, unsigned __int64 oldSize, unsigned __int64 newSize)
{
const auto closure = reinterpret_cast<game::hks::cclosure*>(oldMemory);
if (converted_functions.find(closure) != converted_functions.end())
{
converted_functions.erase(closure);
}
return hks_allocator_hook.invoke<void*>(userData, oldMemory, oldSize, newSize);
}
void hks_frame_stub()
{
const auto state = *game::hks::lua_state;
if (state)
{
ui_scripting::lua::engine::run_frame();
}
}
}
int main_function_handler(game::hks::lua_State* state)
{
const auto value = state->m_apistack.base[-1];
if (value.t != game::hks::TCFUNCTION)
{
return 0;
}
const auto closure = reinterpret_cast<game::hks::cclosure*>(value.v.cClosure);
if (converted_functions.find(closure) == converted_functions.end())
{
return 0;
}
const auto function = converted_functions[closure];
const auto count = static_cast<int>(state->m_apistack.top - state->m_apistack.base);
const auto arguments = get_return_values(count);
const auto s = function.lua_state();
std::vector<sol::lua_value> converted_args;
for (const auto& argument : arguments)
{
converted_args.push_back(lua::convert(s, argument));
}
const auto results = function(sol::as_args(converted_args));
lua::handle_error(results);
for (const auto& result : results)
{
push_value(lua::convert({s, result}));
}
return results.return_count();
}
void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function)
{
converted_functions[closure] = function;
}
void clear_converted_functions()
{
converted_functions.clear();
}
void enable_error_hook()
{
error_hook_enabled = true;
}
void disable_error_hook()
{
error_hook_enabled = false;
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_dedi())
{
return;
}
hks_start_hook.create(SELECT_VALUE(0x1400E4B40, 0x140176A40), hks_start_stub);
hks_shutdown_hook.create(SELECT_VALUE(0x1400DD3D0, 0x14016CA80), hks_shutdown_stub);
hksi_lual_error_hook.create(SELECT_VALUE(0x1400A5EA0, 0x14012F300), hksi_lual_error_stub);
hks_allocator_hook.create(SELECT_VALUE(0x14009B570, 0x14012BAC0), hks_allocator_stub);
hks_frame_hook.create(SELECT_VALUE(0x1400E37F0, 0x1401755B0), hks_frame_stub);
if (game::environment::is_mp())
{
hksi_lual_error_hook2.create(0x1401366B0, hksi_lual_error_stub);
}
command::add("lui_restart", []()
{
utils::hook::invoke<void>(SELECT_VALUE(0x1400DD3D0, 0x14016CA80));
utils::hook::invoke<void>(SELECT_VALUE(0x1400E6170, 0x1401780D0));
});
}
};
}
REGISTER_COMPONENT(ui_scripting::component)

View File

@ -1,12 +0,0 @@
#pragma once
#include "game/ui_scripting/lua/value_conversion.hpp"
namespace ui_scripting
{
int main_function_handler(game::hks::lua_State* state);
void add_converted_function(game::hks::cclosure* closure, const sol::protected_function& function);
void clear_converted_functions();
void enable_error_hook();
void disable_error_hook();
}

View File

@ -1,474 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "dvars.hpp"
#include "updater.hpp"
#include "version.h"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/nt.hpp>
#include <utils/concurrency.hpp>
#include <utils/http.hpp>
#include <utils/cryptography.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
#define MASTER "https://master.fed0001.xyz/h1-mod/"
#define FILES_PATH "files.json"
#define FILES_PATH_DEV "files-dev.json"
#define DATA_PATH "data/"
#define DATA_PATH_DEV "data-dev/"
#define ERR_UPDATE_CHECK_FAIL "Failed to check for updates"
#define ERR_DOWNLOAD_FAIL "Failed to download file "
#define ERR_WRITE_FAIL "Failed to write file "
#define BINARY_NAME "h1-mod.exe"
namespace updater
{
namespace
{
game::dvar_t* cl_auto_update;
bool has_tried_update = false;
struct status
{
bool done;
bool success;
};
struct file_data
{
std::string name;
std::string data;
};
struct update_data_t
{
bool restart_required{};
bool cancelled{};
status check{};
status download{};
std::string error{};
std::string current_file{};
std::vector<std::string> required_files{};
};
utils::concurrency::container<update_data_t> update_data;
std::string get_branch()
{
return GIT_BRANCH;
}
std::string select(const std::string& main, const std::string& develop)
{
if (get_branch() == "develop")
{
return develop;
}
return main;
}
std::string get_data_path()
{
if (get_branch() == "develop")
{
return DATA_PATH_DEV;
}
return DATA_PATH;
}
void set_update_check_status(bool done, bool success, const std::string& error = {})
{
update_data.access([done, success, error](update_data_t& data_)
{
data_.check.done = done;
data_.check.success = success;
data_.error = error;
});
}
void set_update_download_status(bool done, bool success, const std::string& error = {})
{
update_data.access([done, success, error](update_data_t& data_)
{
data_.download.done = done;
data_.download.success = success;
data_.error = error;
});
}
bool check_file(const std::string& name, const std::string& sha)
{
std::string data;
if (!utils::io::read_file(name, &data))
{
return false;
}
if (utils::cryptography::sha1::compute(data, true) != sha)
{
return false;
}
return true;
}
std::string load_binary_name()
{
// utils::nt::library self;
// return self.get_name();
// returns the game's name and not the client's
return BINARY_NAME;
}
std::string get_binary_name()
{
static const auto name = load_binary_name();
return name;
}
std::string get_time_str()
{
return utils::string::va("%i", uint32_t(time(nullptr)));
}
std::optional<std::string> download_file(const std::string& name)
{
return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str());
}
bool is_update_cancelled()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.cancelled;
});
}
bool write_file(const std::string& name, const std::string& data)
{
if (get_binary_name() == name &&
utils::io::file_exists(name) &&
!utils::io::move_file(name, name + ".old"))
{
return false;
}
#ifdef DEBUG
return utils::io::write_file("update_test/" + name, data);
#else
return utils::io::write_file(name, data);
#endif
}
void delete_old_file()
{
utils::io::remove_file(get_binary_name() + ".old");
}
void reset_data()
{
update_data.access([](update_data_t& data_)
{
data_ = {};
});
}
std::string get_mode_flag()
{
if (game::environment::is_mp())
{
return "-multiplayer";
}
if (game::environment::is_sp())
{
return "-singleplayer";
}
return {};
}
}
// workaround
void relaunch()
{
if (!utils::io::file_exists(BINARY_NAME))
{
utils::nt::terminate(0);
return;
}
STARTUPINFOA startup_info;
PROCESS_INFORMATION process_info;
ZeroMemory(&startup_info, sizeof(startup_info));
ZeroMemory(&process_info, sizeof(process_info));
startup_info.cb = sizeof(startup_info);
char current_dir[MAX_PATH];
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
char buf[1024] = {0};
const auto command_line = utils::string::va("%s %s", GetCommandLineA(), get_mode_flag().data());
strcpy_s(buf, 1024, command_line);
CreateProcess(BINARY_NAME, buf, nullptr, nullptr, false, NULL, nullptr, current_dir,
&startup_info, &process_info);
if (process_info.hThread && process_info.hThread != INVALID_HANDLE_VALUE) CloseHandle(process_info.hThread);
if (process_info.hProcess && process_info.hProcess != INVALID_HANDLE_VALUE) CloseHandle(process_info.hProcess);
utils::nt::terminate(0);
}
void set_has_tried_update(bool tried)
{
has_tried_update = tried;
}
bool get_has_tried_update()
{
return has_tried_update;
}
bool auto_updates_enabled()
{
return cl_auto_update->current.enabled;
}
bool is_update_check_done()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.check.done;
});
}
bool is_update_download_done()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.download.done;
});
}
bool get_update_check_status()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.check.success;
});
}
bool get_update_download_status()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.download.success;
});
}
bool is_update_available()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.required_files.size() > 0;
});
}
bool is_restart_required()
{
return update_data.access<bool>([](update_data_t& data_)
{
return data_.restart_required;
});
}
std::string get_last_error()
{
return update_data.access<std::string>([](update_data_t& data_)
{
return data_.error;
});
}
std::string get_current_file()
{
return update_data.access<std::string>([](update_data_t& data_)
{
return data_.current_file;
});
}
void cancel_update()
{
#ifdef DEBUG
printf("[Updater] Cancelling update\n");
#endif
return update_data.access([](update_data_t& data_)
{
data_.cancelled = true;
});
}
void start_update_check()
{
cancel_update();
reset_data();
#ifdef DEBUG
printf("[Updater] starting update check\n");
#endif
scheduler::once([]()
{
const auto files_data = utils::http::get_data(MASTER + select(FILES_PATH, FILES_PATH_DEV) + "?" + get_time_str());
if (is_update_cancelled())
{
reset_data();
return;
}
if (!files_data.has_value())
{
set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL);
return;
}
rapidjson::Document j;
j.Parse(files_data.value().data());
if (!j.IsArray())
{
set_update_check_status(true, false, ERR_UPDATE_CHECK_FAIL);
return;
}
std::vector<std::string> required_files;
const auto files = j.GetArray();
for (const auto& file : files)
{
if (!file.IsArray() || file.Size() != 3 || !file[0].IsString() || !file[2].IsString())
{
continue;
}
const auto name = file[0].GetString();
const auto sha = file[2].GetString();
if (!check_file(name, sha))
{
if (get_binary_name() == name)
{
update_data.access([](update_data_t& data_)
{
data_.restart_required = true;
});
}
#ifdef DEBUG
printf("[Updater] need file %s\n", name);
#endif
required_files.push_back(name);
}
}
update_data.access([&required_files](update_data_t& data_)
{
data_.check.done = true;
data_.check.success = true;
data_.required_files = required_files;
});
}, scheduler::pipeline::async);
}
void start_update_download()
{
#ifdef DEBUG
printf("[Updater] starting update download\n");
#endif
if (!is_update_check_done() || !get_update_check_status() || is_update_cancelled())
{
return;
}
scheduler::once([]()
{
const auto required_files = update_data.access<std::vector<std::string>>([](update_data_t& data_)
{
return data_.required_files;
});
std::vector<file_data> downloads;
for (const auto& file : required_files)
{
update_data.access([file](update_data_t& data_)
{
data_.current_file = file;
});
#ifdef DEBUG
printf("[Updater] downloading file %s\n", file.data());
#endif
const auto data = download_file(file);
if (is_update_cancelled())
{
reset_data();
return;
}
if (!data.has_value())
{
set_update_download_status(true, false, ERR_DOWNLOAD_FAIL + file);
return;
}
downloads.push_back({file, data.value()});
}
for (const auto& download : downloads)
{
if (!write_file(download.name, download.data))
{
set_update_download_status(true, false, ERR_WRITE_FAIL + download.name);
return;
}
}
set_update_download_status(true, true);
}, scheduler::pipeline::async);
}
class component final : public component_interface
{
public:
void post_unpack() override
{
delete_old_file();
cl_auto_update = dvars::register_bool("cg_auto_update", true, game::DVAR_FLAG_SAVED, true);
}
};
}
REGISTER_COMPONENT(updater::component)

View File

@ -1,26 +0,0 @@
#pragma once
namespace updater
{
void relaunch();
void set_has_tried_update(bool tried);
bool get_has_tried_update();
bool auto_updates_enabled();
bool is_update_available();
bool is_update_check_done();
bool get_update_check_status();
bool is_update_download_done();
bool get_update_download_status();
bool is_restart_required();
std::string get_last_error();
std::string get_current_file();
void start_update_check();
void start_update_download();
void cancel_update();
}

View File

@ -1,55 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include <utils/hook.hpp>
namespace videos
{
namespace
{
utils::hook::detour playvid_hook;
std::unordered_map<std::string, std::string> video_replaces;
void playvid(const char* name, const int a2, const int a3)
{
const auto vid = video_replaces.find(name);
if (vid != video_replaces.end())
{
char path[256];
game::Sys_BuildAbsPath(path, sizeof(path), game::SF_VIDEO, vid->second.data(), ".bik");
if (game::Sys_FileExists(path))
{
name = vid->second.data();
}
}
return playvid_hook.invoke<void>(name, a2, a3);
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
playvid_hook.create(SELECT_VALUE(0x1404A9D00, 0x1405B0AF0), &playvid); // H1(1.4)
if (game::environment::is_mp())
{
video_replaces["menus_bg_comp2"] = "menus_bg_h1mod";
video_replaces["mp_menus_bg_options"] = "menus_bg_h1mod_blur";
}
else if (game::environment::is_sp())
{
video_replaces["sp_menus_bg_main_menu"] = "menus_bg_h1mod_sp";
video_replaces["sp_menus_bg_campaign"] = "menus_bg_h1mod_sp";
video_replaces["sp_menus_bg_options"] = "menus_bg_h1mod_sp";
}
}
};
}
REGISTER_COMPONENT(videos::component)

View File

@ -1,63 +0,0 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
namespace virtuallobby
{
namespace
{
game::dvar_t* virtualLobby_fovscale;
const auto get_fovscale_stub = utils::hook::assemble([](utils::hook::assembler& a)
{
const auto ret = a.newLabel();
const auto original = a.newLabel();
a.pushad64();
a.mov(rax, qword_ptr(0x1425F7210)); // virtualLobbyInFiringRange
a.cmp(byte_ptr(rax, 0x10), 1);
a.je(original);
a.call_aligned(game::VirtualLobby_Loaded);
a.cmp(al, 0);
a.je(original);
// virtuallobby
a.popad64();
a.mov(rax, ptr(reinterpret_cast<int64_t>(&virtualLobby_fovscale)));
a.jmp(ret);
// original
a.bind(original);
a.popad64();
a.mov(rax, qword_ptr(0x1413A8580));
a.jmp(ret);
a.bind(ret);
a.mov(rcx, 0x142935000);
a.jmp(0x1400B556A);
});
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (!game::environment::is_mp())
{
return;
}
virtualLobby_fovscale = dvars::register_float("virtualLobby_fovScale", 0.7f, 0.0f, 2.0f, game::DVAR_FLAG_SAVED);
utils::hook::nop(0x1400B555C, 14);
utils::hook::jump(0x1400B555C, get_fovscale_stub, true);
}
};
}
REGISTER_COMPONENT(virtuallobby::component)