Merge branch 'master' of https://git.alterware.dev/alterware/iw6-mod
This commit is contained in:
commit
e333bf7912
@ -183,10 +183,10 @@ This is a client modification for IW6!
|
|||||||
- Install [Premake5][premake5-link] and add it to your system PATH
|
- Install [Premake5][premake5-link] and add it to your system PATH
|
||||||
- Clone this repository using [Git][git-link]
|
- Clone this repository using [Git][git-link]
|
||||||
- Update the submodules using ``git submodule update --init --recursive``
|
- Update the submodules using ``git submodule update --init --recursive``
|
||||||
- Run Premake with this options ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported.
|
- Run Premake with the option ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported.
|
||||||
- Build project via solution file in `build\s1-mod.sln`.
|
- Build project via solution file in `build\iw6-mod.sln`.
|
||||||
|
|
||||||
Only x64 is supported. Do not attempt to build for Windows ARM 64.
|
Only the x64 platform is supported. Do not attempt to build for Windows ARM 64 or Win32.
|
||||||
|
|
||||||
### Premake arguments
|
### Premake arguments
|
||||||
|
|
||||||
|
@ -75,8 +75,8 @@ namespace bots
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* bot_name = game::SV_BotGetRandomName();
|
const auto* bot_name = game::SV_BotGetRandomName();
|
||||||
auto* bot_ent = game::SV_AddBot(bot_name, 26, 62, 0);
|
const auto* bot_ent = game::SV_AddBot(bot_name, 26, 62, 0);
|
||||||
if (bot_ent)
|
if (bot_ent)
|
||||||
{
|
{
|
||||||
spawn_bot(bot_ent->s.number);
|
spawn_bot(bot_ent->s.number);
|
||||||
@ -87,34 +87,13 @@ namespace bots
|
|||||||
volatile bool bot_names_received = false;
|
volatile bool bot_names_received = false;
|
||||||
std::vector<std::string> bot_names;
|
std::vector<std::string> bot_names;
|
||||||
|
|
||||||
const char* get_random_bot_name()
|
bool should_use_remote_bot_names()
|
||||||
{
|
|
||||||
if (bot_names.empty())
|
|
||||||
{
|
|
||||||
return get_bot_name_hook.invoke<const char*>();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto index = std::rand() % bot_names.size();
|
|
||||||
const auto& name = bot_names.at(index);
|
|
||||||
|
|
||||||
return utils::string::va("%.*s", static_cast<int>(name.size()), name.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_update_bot_names()
|
|
||||||
{
|
{
|
||||||
|
#ifdef ALLOW_CUSTOM_BOT_NAMES
|
||||||
return !filesystem::exists("bots.txt");
|
return !filesystem::exists("bots.txt");
|
||||||
}
|
#else
|
||||||
|
return true;
|
||||||
void update_bot_names()
|
#endif
|
||||||
{
|
|
||||||
bot_names_received = false;
|
|
||||||
|
|
||||||
game::netadr_s master{};
|
|
||||||
if (server_list::get_master_server(master))
|
|
||||||
{
|
|
||||||
console::info("Getting bots...\n");
|
|
||||||
network::send(master, "getbots");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_bot_names_from_file()
|
void parse_bot_names_from_file()
|
||||||
@ -141,6 +120,37 @@ namespace bots
|
|||||||
bot_names.emplace_back(entry);
|
bot_names.emplace_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* get_random_bot_name()
|
||||||
|
{
|
||||||
|
if (!bot_names_received && bot_names.empty())
|
||||||
|
{
|
||||||
|
// last attempt to use custom names if they can be found
|
||||||
|
parse_bot_names_from_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bot_names.empty())
|
||||||
|
{
|
||||||
|
return get_bot_name_hook.invoke<const char*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto index = std::rand() % bot_names.size();
|
||||||
|
const auto& name = bot_names.at(index);
|
||||||
|
|
||||||
|
return utils::string::va("%.*s", static_cast<int>(name.size()), name.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_bot_names()
|
||||||
|
{
|
||||||
|
bot_names_received = false;
|
||||||
|
|
||||||
|
game::netadr_s master{};
|
||||||
|
if (server_list::get_master_server(master))
|
||||||
|
{
|
||||||
|
console::info("Getting bots...\n");
|
||||||
|
network::send(master, "getbots");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
@ -159,23 +169,23 @@ namespace bots
|
|||||||
{
|
{
|
||||||
if (!game::SV_Loaded()) return;
|
if (!game::SV_Loaded()) return;
|
||||||
|
|
||||||
auto num_bots = 1;
|
std::size_t num_bots = 1;
|
||||||
if (params.size() == 2)
|
if (params.size() == 2)
|
||||||
{
|
{
|
||||||
num_bots = atoi(params.get(1));
|
num_bots = std::strtoul(params.get(1), nullptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
num_bots = std::min(num_bots, *game::mp::svs_clientCount);
|
num_bots = std::min(num_bots, static_cast<std::size_t>(*game::mp::svs_clientCount));
|
||||||
|
|
||||||
console::info("Spawning %i %s\n", num_bots, (num_bots == 1 ? "bot" : "bots"));
|
console::info("Spawning %zu %s\n", num_bots, (num_bots == 1 ? "bot" : "bots"));
|
||||||
|
|
||||||
for (auto i = 0; i < num_bots; i++)
|
for (std::size_t i = 0; i < num_bots; ++i)
|
||||||
{
|
{
|
||||||
scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i);
|
scheduler::once(add_bot, scheduler::pipeline::server, 100ms * i);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (should_update_bot_names())
|
if (should_use_remote_bot_names())
|
||||||
{
|
{
|
||||||
scheduler::on_game_initialized([]()
|
scheduler::on_game_initialized([]()
|
||||||
{
|
{
|
||||||
@ -194,6 +204,7 @@ namespace bots
|
|||||||
if (server_list::get_master_server(master) && !bot_names_received && target == master)
|
if (server_list::get_master_server(master) && !bot_names_received && target == master)
|
||||||
{
|
{
|
||||||
bot_names = utils::string::split(data, '\n');
|
bot_names = utils::string::split(data, '\n');
|
||||||
|
console::info("Got %zu names from the master server\n", bot_names.size());
|
||||||
bot_names_received = true;
|
bot_names_received = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -13,8 +13,6 @@
|
|||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
#include <version.hpp>
|
|
||||||
|
|
||||||
namespace dedicated
|
namespace dedicated
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
@ -105,12 +103,6 @@ namespace dedicated
|
|||||||
reinterpret_cast<void(*)()>(0x14046F3B0)(); // SV_CheckLoadGame
|
reinterpret_cast<void(*)()>(0x14046F3B0)(); // SV_CheckLoadGame
|
||||||
}
|
}
|
||||||
|
|
||||||
game::dvar_t* register_maxfps_stub(const char* name, int, int, int, unsigned int flags,
|
|
||||||
const char* desc)
|
|
||||||
{
|
|
||||||
return game::Dvar_RegisterInt(name, 0, 0, 0, game::DvarFlags::DVAR_FLAG_READ, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_heartbeat()
|
void send_heartbeat()
|
||||||
{
|
{
|
||||||
if (sv_lanOnly->current.enabled)
|
if (sv_lanOnly->current.enabled)
|
||||||
@ -293,7 +285,7 @@ namespace dedicated
|
|||||||
|
|
||||||
//utils::hook::set<uint8_t>(0x1402C89A0, 0xC3); // R_Init caller
|
//utils::hook::set<uint8_t>(0x1402C89A0, 0xC3); // R_Init caller
|
||||||
utils::hook::jump(0x1402C89A0, init_dedicated_server);
|
utils::hook::jump(0x1402C89A0, init_dedicated_server);
|
||||||
utils::hook::call(0x140413AD8, register_maxfps_stub);
|
dvars::override::register_int("com_maxfps", 0, 0, 0, game::DVAR_FLAG_READ);
|
||||||
|
|
||||||
// delay startup commands until the initialization is done
|
// delay startup commands until the initialization is done
|
||||||
utils::hook::call(0x140412183, execute_startup_command);
|
utils::hook::call(0x140412183, execute_startup_command);
|
||||||
@ -302,6 +294,10 @@ namespace dedicated
|
|||||||
utils::hook::call(0x140412FD3, execute_console_command);
|
utils::hook::call(0x140412FD3, execute_console_command);
|
||||||
utils::hook::nop(0x140412FE9, 5);
|
utils::hook::nop(0x140412FE9, 5);
|
||||||
|
|
||||||
|
// disable check on an unregistered relay dvar
|
||||||
|
utils::hook::nop(0x14041E9EB, 4);
|
||||||
|
utils::hook::set<std::uint8_t>(0x14041E9EF, 0xEB);
|
||||||
|
|
||||||
utils::hook::nop(0x1404DDC2E, 5); // don't load config file
|
utils::hook::nop(0x1404DDC2E, 5); // don't load config file
|
||||||
utils::hook::set<uint8_t>(0x140416100, 0xC3); // don't save config file
|
utils::hook::set<uint8_t>(0x140416100, 0xC3); // don't save config file
|
||||||
utils::hook::set<uint8_t>(0x1402E5830, 0xC3); // disable self-registration
|
utils::hook::set<uint8_t>(0x1402E5830, 0xC3); // disable self-registration
|
||||||
|
@ -18,7 +18,23 @@ namespace dvars
|
|||||||
bool value{};
|
bool value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dvar_int : dvar_base
|
||||||
|
{
|
||||||
|
int value{};
|
||||||
|
int min{};
|
||||||
|
int max{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dvar_float : dvar_base
|
||||||
|
{
|
||||||
|
float value{};
|
||||||
|
float min{};
|
||||||
|
float max{};
|
||||||
|
};
|
||||||
|
|
||||||
utils::hook::detour dvar_register_bool_hook;
|
utils::hook::detour dvar_register_bool_hook;
|
||||||
|
utils::hook::detour dvar_register_int_hook;
|
||||||
|
utils::hook::detour dvar_register_float_hook;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T* find_dvar(std::unordered_map<std::string, T>& map, const std::string& name)
|
T* find_dvar(std::unordered_map<std::string, T>& map, const std::string& name)
|
||||||
@ -35,6 +51,8 @@ namespace dvars
|
|||||||
namespace override
|
namespace override
|
||||||
{
|
{
|
||||||
static std::unordered_map<std::string, dvar_bool> register_bool_overrides;
|
static std::unordered_map<std::string, dvar_bool> register_bool_overrides;
|
||||||
|
static std::unordered_map<std::string, dvar_int> register_int_overrides;
|
||||||
|
static std::unordered_map<std::string, dvar_float> register_float_overrides;
|
||||||
|
|
||||||
void register_bool(const std::string& name, const bool value, const unsigned int flags)
|
void register_bool(const std::string& name, const bool value, const unsigned int flags)
|
||||||
{
|
{
|
||||||
@ -43,6 +61,26 @@ namespace dvars
|
|||||||
values.flags = flags;
|
values.flags = flags;
|
||||||
register_bool_overrides[name] = values;
|
register_bool_overrides[name] = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void register_int(const std::string& name, const int value, const int min, const int max, const unsigned int flags)
|
||||||
|
{
|
||||||
|
dvar_int values;
|
||||||
|
values.value = value;
|
||||||
|
values.min = min;
|
||||||
|
values.max = max;
|
||||||
|
values.flags = flags;
|
||||||
|
register_int_overrides[name] = std::move(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_float(const std::string& name, const float value, const float min, const float max, const unsigned int flags)
|
||||||
|
{
|
||||||
|
dvar_float values;
|
||||||
|
values.value = value;
|
||||||
|
values.min = min;
|
||||||
|
values.max = max;
|
||||||
|
values.flags = flags;
|
||||||
|
register_float_overrides[name] = std::move(values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_string(const std::string& dvar)
|
std::string get_string(const std::string& dvar)
|
||||||
@ -68,17 +106,49 @@ namespace dvars
|
|||||||
return dvar_register_bool_hook.invoke<const game::dvar_t*>(name, value, flags, description);
|
return dvar_register_bool_hook.invoke<const game::dvar_t*>(name, value, flags, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
game::dvar_t* dvar_register_int_stub(const char* name, int value, int min, int max, unsigned int flags, const char* description)
|
||||||
|
{
|
||||||
|
auto* var = find_dvar(override::register_int_overrides, name);
|
||||||
|
if (var)
|
||||||
|
{
|
||||||
|
value = var->value;
|
||||||
|
min = var->min;
|
||||||
|
max = var->max;
|
||||||
|
flags = var->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dvar_register_int_hook.invoke<game::dvar_t*>(name, value, min, max, flags, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
game::dvar_t* dvar_register_float_stub(const char* name, float value, float min, float max, unsigned int flags, const char* description)
|
||||||
|
{
|
||||||
|
auto* var = find_dvar(override::register_float_overrides, name);
|
||||||
|
if (var)
|
||||||
|
{
|
||||||
|
value = var->value;
|
||||||
|
min = var->min;
|
||||||
|
max = var->max;
|
||||||
|
flags = var->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dvar_register_float_hook.invoke<game::dvar_t*>(name, value, min, max, flags, description);
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
dvar_register_bool_hook.create(game::Dvar_RegisterBool, &dvar_register_bool_stub);
|
dvar_register_bool_hook.create(game::Dvar_RegisterBool, &dvar_register_bool_stub);
|
||||||
|
dvar_register_int_hook.create(game::Dvar_RegisterInt, &dvar_register_int_stub);
|
||||||
|
dvar_register_float_hook.create(game::Dvar_RegisterFloat, &dvar_register_float_stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pre_destroy() override
|
void pre_destroy() override
|
||||||
{
|
{
|
||||||
dvar_register_bool_hook.clear();
|
dvar_register_bool_hook.clear();
|
||||||
|
dvar_register_int_hook.clear();
|
||||||
|
dvar_register_float_hook.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ namespace dvars
|
|||||||
namespace override
|
namespace override
|
||||||
{
|
{
|
||||||
void register_bool(const std::string& name, bool value, unsigned int flags);
|
void register_bool(const std::string& name, bool value, unsigned int flags);
|
||||||
|
void register_int(const std::string& name, int value, int min, int max, unsigned int flags);
|
||||||
|
void register_float(const std::string& name, float value, float min, float max, unsigned int flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_string(const std::string& dvar);
|
std::string get_string(const std::string& dvar);
|
||||||
|
@ -25,6 +25,12 @@ namespace filesystem
|
|||||||
return search_paths;
|
return search_paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* sys_default_install_path_stub()
|
||||||
|
{
|
||||||
|
static auto current_path = std::filesystem::current_path().string();
|
||||||
|
return current_path.data();
|
||||||
|
}
|
||||||
|
|
||||||
std::string get_binary_directory()
|
std::string get_binary_directory()
|
||||||
{
|
{
|
||||||
const auto dir = game_module::get_host_module().get_folder();
|
const auto dir = game_module::get_host_module().get_folder();
|
||||||
@ -264,6 +270,10 @@ namespace filesystem
|
|||||||
// Set fs_basegame
|
// Set fs_basegame
|
||||||
utils::hook::inject(SELECT_VALUE(0x14041C053, 0x1404DDA13), "iw6");
|
utils::hook::inject(SELECT_VALUE(0x14041C053, 0x1404DDA13), "iw6");
|
||||||
|
|
||||||
|
#ifndef INJECT_HOST_AS_LIB
|
||||||
|
utils::hook::jump(SELECT_VALUE(0x1404351B0, 0x1404F96C0), sys_default_install_path_stub);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (game::environment::is_sp())
|
if (game::environment::is_sp())
|
||||||
{
|
{
|
||||||
utils::hook::call(0x14041B744, fs_startup_stub);
|
utils::hook::call(0x14041B744, fs_startup_stub);
|
||||||
|
@ -71,10 +71,9 @@ namespace gsc
|
|||||||
return scripting::get_token(id);
|
return scripting::get_token(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_unknown_function_error(const char* code_pos)
|
void get_unknown_function_error(char* code_pos)
|
||||||
{
|
{
|
||||||
const auto function = find_function(code_pos);
|
if (const auto function = find_function(code_pos); function.has_value())
|
||||||
if (function.has_value())
|
|
||||||
{
|
{
|
||||||
const auto& pos = function.value();
|
const auto& pos = function.value();
|
||||||
unknown_function_error = std::format(
|
unknown_function_error = std::format(
|
||||||
@ -97,7 +96,7 @@ namespace gsc
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void compile_error_stub(const char* code_pos, [[maybe_unused]] const char* msg)
|
void compile_error_stub(char* code_pos, [[maybe_unused]] const char* msg)
|
||||||
{
|
{
|
||||||
get_unknown_function_error(code_pos);
|
get_unknown_function_error(code_pos);
|
||||||
game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data());
|
game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data());
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include "game/scripting/functions.hpp"
|
#include "game/scripting/functions.hpp"
|
||||||
|
|
||||||
@ -8,7 +9,6 @@
|
|||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
#include "component/console.hpp"
|
#include "component/console.hpp"
|
||||||
#include "component/scripting.hpp"
|
|
||||||
#include "component/notifies.hpp"
|
#include "component/notifies.hpp"
|
||||||
#include "component/command.hpp"
|
#include "component/command.hpp"
|
||||||
|
|
||||||
@ -23,8 +23,6 @@ namespace gsc
|
|||||||
|
|
||||||
void* func_table[0x1000];
|
void* func_table[0x1000];
|
||||||
|
|
||||||
const game::dvar_t* developer_script = nullptr;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
#define RVA(ptr) static_cast<std::uint32_t>(reinterpret_cast<std::size_t>(ptr) - 0x140000000)
|
#define RVA(ptr) static_cast<std::uint32_t>(reinterpret_cast<std::size_t>(ptr) - 0x140000000)
|
||||||
@ -135,7 +133,7 @@ namespace gsc
|
|||||||
|
|
||||||
void vm_error_stub(int mark_pos)
|
void vm_error_stub(int mark_pos)
|
||||||
{
|
{
|
||||||
if (!developer_script->current.enabled && !force_error_print)
|
if (!dvars::com_developer_script->current.enabled && !force_error_print)
|
||||||
{
|
{
|
||||||
utils::hook::invoke<void>(0x1404E4D00, mark_pos);
|
utils::hook::invoke<void>(0x1404E4D00, mark_pos);
|
||||||
return;
|
return;
|
||||||
@ -284,8 +282,6 @@ namespace gsc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments");
|
|
||||||
|
|
||||||
utils::hook::nop(0x14043BBBE + 5, 2);
|
utils::hook::nop(0x14043BBBE + 5, 2);
|
||||||
utils::hook::call(0x14043BBBE, vm_call_builtin_function);
|
utils::hook::call(0x14043BBBE, vm_call_builtin_function);
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@ namespace gsc
|
|||||||
{
|
{
|
||||||
extern void* func_table[0x1000];
|
extern void* func_table[0x1000];
|
||||||
|
|
||||||
extern const game::dvar_t* developer_script;
|
|
||||||
|
|
||||||
void add_function(const std::string& name, game::BuiltinFunction function);
|
void add_function(const std::string& name, game::BuiltinFunction function);
|
||||||
|
|
||||||
void scr_error(const char* error);
|
void scr_error(const char* error);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
@ -10,7 +11,6 @@
|
|||||||
#include "component/filesystem.hpp"
|
#include "component/filesystem.hpp"
|
||||||
#include "component/console.hpp"
|
#include "component/console.hpp"
|
||||||
#include "component/scripting.hpp"
|
#include "component/scripting.hpp"
|
||||||
#include "component/fastfiles.hpp"
|
|
||||||
|
|
||||||
#include "script_loading.hpp"
|
#include "script_loading.hpp"
|
||||||
|
|
||||||
@ -26,8 +26,6 @@ namespace gsc
|
|||||||
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
||||||
utils::memory::allocator script_allocator;
|
utils::memory::allocator script_allocator;
|
||||||
|
|
||||||
const game::dvar_t* developer_script;
|
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
main_handles.clear();
|
main_handles.clear();
|
||||||
@ -266,11 +264,19 @@ namespace gsc
|
|||||||
|
|
||||||
void scr_begin_load_scripts_stub()
|
void scr_begin_load_scripts_stub()
|
||||||
{
|
{
|
||||||
const auto comp_mode = developer_script->current.enabled ?
|
auto build = xsk::gsc::build::prod;
|
||||||
xsk::gsc::build::dev :
|
|
||||||
xsk::gsc::build::prod;
|
|
||||||
|
|
||||||
gsc_ctx->init(comp_mode, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>>
|
if ((*dvars::com_developer) && (*dvars::com_developer)->current.integer > 0)
|
||||||
|
{
|
||||||
|
build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_maps));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dvars::com_developer_script && dvars::com_developer_script->current.enabled)
|
||||||
|
{
|
||||||
|
build = static_cast<xsk::gsc::build>(static_cast<unsigned int>(build) | static_cast<unsigned int>(xsk::gsc::build::dev_blocks));
|
||||||
|
}
|
||||||
|
|
||||||
|
gsc_ctx->init(build, []([[maybe_unused]] auto const* ctx, const auto& included_path) -> std::pair<xsk::gsc::buffer, std::vector<std::uint8_t>>
|
||||||
{
|
{
|
||||||
const auto script_name = std::filesystem::path(included_path).replace_extension().string();
|
const auto script_name = std::filesystem::path(included_path).replace_extension().string();
|
||||||
|
|
||||||
@ -331,13 +337,15 @@ namespace gsc
|
|||||||
|
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
|
dvars::com_developer = reinterpret_cast<game::dvar_t**>(SELECT_VALUE(0x141603850, 0x1419A9700));
|
||||||
|
|
||||||
// Load our scripts with an uncompressed stack
|
// Load our scripts with an uncompressed stack
|
||||||
utils::hook::call(SELECT_VALUE(0x1403DC8F0, 0x140437940), db_get_raw_buffer_stub);
|
utils::hook::call(SELECT_VALUE(0x1403DC8F0, 0x140437940), db_get_raw_buffer_stub);
|
||||||
|
|
||||||
utils::hook::call(SELECT_VALUE(0x14032D1E0, 0x1403CCED9), scr_begin_load_scripts_stub); // GScr_LoadScripts
|
utils::hook::call(SELECT_VALUE(0x14032D1E0, 0x1403CCED9), scr_begin_load_scripts_stub); // GScr_LoadScripts
|
||||||
utils::hook::call(SELECT_VALUE(0x14032D345, 0x1403CD08D), scr_end_load_scripts_stub); // GScr_LoadScripts
|
utils::hook::call(SELECT_VALUE(0x14032D345, 0x1403CD08D), scr_end_load_scripts_stub); // GScr_LoadScripts
|
||||||
|
|
||||||
developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments");
|
dvars::com_developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments");
|
||||||
|
|
||||||
if (game::environment::is_sp())
|
if (game::environment::is_sp())
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
|
||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "network.hpp"
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
|
#include "network.hpp"
|
||||||
|
#include "party.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
@ -87,14 +88,18 @@ namespace network
|
|||||||
return net_compare_base_address(a1, a2) && a1->port == a2->port;
|
return net_compare_base_address(a1, a2) && a1->port == a2->port;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reconnect_migratated_client(game::mp::client_t*, game::netadr_s* from, const int, const int, const char*,
|
void reconnect_migrated_client(game::mp::client_t*, game::netadr_s* from, const int, const int, const char*, const char*, bool)
|
||||||
const char*, bool)
|
|
||||||
{
|
{
|
||||||
// This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid
|
// This happens when a client tries to rejoin after being recently disconnected, OR by a duplicated guid
|
||||||
// We don't want this to do anything. It decides to crash seemingly randomly
|
// We don't want this to do anything. It decides to crash seemingly randomly
|
||||||
// Rather than try and let the player in, just tell them they are a duplicate player and reject connection
|
// Rather than try and let the player in, just tell them they are a duplicate player and reject connection
|
||||||
game::NET_OutOfBandPrint(game::NS_SERVER, from, "error\nYou are already connected to the server.");
|
game::NET_OutOfBandPrint(game::NS_SERVER, from, "error\nYou are already connected to the server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* memmove_stub(void* dest, const void* src, std::size_t count)
|
||||||
|
{
|
||||||
|
return std::memmove(dest, src, std::min<std::size_t>(count, 1262));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on(const std::string& command, const callback& callback)
|
void on(const std::string& command, const callback& callback)
|
||||||
@ -138,21 +143,21 @@ namespace network
|
|||||||
|
|
||||||
const char* net_adr_to_string(const game::netadr_s& a)
|
const char* net_adr_to_string(const game::netadr_s& a)
|
||||||
{
|
{
|
||||||
if (a.type == game::netadrtype_t::NA_LOOPBACK)
|
if (a.type == game::NA_LOOPBACK)
|
||||||
{
|
{
|
||||||
return "loopback";
|
return "loopback";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.type == game::netadrtype_t::NA_BOT)
|
if (a.type == game::NA_BOT)
|
||||||
{
|
{
|
||||||
return "bot";
|
return "bot";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.type == game::netadrtype_t::NA_IP || a.type == game::netadrtype_t::NA_BROADCAST)
|
if (a.type == game::NA_IP || a.type == game::NA_BROADCAST)
|
||||||
{
|
{
|
||||||
if (a.port)
|
if (a.port)
|
||||||
{
|
{
|
||||||
return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], htons(a.port));
|
return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ::htons(a.port));
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
|
return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
|
||||||
@ -189,10 +194,9 @@ namespace network
|
|||||||
a.jmp(0x14041DFBD);
|
a.jmp(0x14041DFBD);
|
||||||
}
|
}
|
||||||
|
|
||||||
game::dvar_t* register_netport_stub(const char* dvarName, int value, int min, int max, unsigned int flags,
|
game::dvar_t* register_netport_stub(const char* dvarName, int value, int min, int max, unsigned int flags, const char* description)
|
||||||
const char* description)
|
|
||||||
{
|
{
|
||||||
auto dvar = game::Dvar_RegisterInt("net_port", 27016, 0, 0xFFFFu, game::DVAR_FLAG_LATCHED, "Network port");
|
auto* dvar = game::Dvar_RegisterInt("net_port", 27016, 0, std::numeric_limits<uint16_t>::max(), game::DVAR_FLAG_LATCHED, "Network port");
|
||||||
|
|
||||||
// read net_port from command line
|
// read net_port from command line
|
||||||
command::read_startup_variable("net_port");
|
command::read_startup_variable("net_port");
|
||||||
@ -221,13 +225,13 @@ namespace network
|
|||||||
utils::hook::jump(0x14041DFB0, utils::hook::assemble(set_xuid_config_string_stub), true);
|
utils::hook::jump(0x14041DFB0, utils::hook::assemble(set_xuid_config_string_stub), true);
|
||||||
|
|
||||||
utils::hook::jump(0x14041D010, net_compare_address);
|
utils::hook::jump(0x14041D010, net_compare_address);
|
||||||
utils::hook::jump(0x14041D060, net_compare_base_address);
|
utils::hook::jump(0x14041D060, net_compare_address);
|
||||||
|
|
||||||
// don't establish secure conenction
|
// don't establish secure conenction
|
||||||
utils::hook::set<uint8_t>(0x1402ECF1D, 0xEB);
|
utils::hook::set<uint8_t>(0x1402ECF1D, 0xEB);
|
||||||
utils::hook::set<uint8_t>(0x1402ED02A, 0xEB);
|
utils::hook::set<uint8_t>(0x1402ED02A, 0xEB);
|
||||||
utils::hook::set<uint8_t>(0x1402ED34D, 0xEB);
|
utils::hook::set<uint8_t>(0x1402ED34D, 0xEB);
|
||||||
utils::hook::set<uint8_t>(0x1402C4A1F, 0xEB); //
|
utils::hook::set<uint8_t>(0x1402C4A1F, 0xEB);
|
||||||
|
|
||||||
// ignore unregistered connection
|
// ignore unregistered connection
|
||||||
utils::hook::jump(0x140471AAC, reinterpret_cast<void*>(0x140471A50));
|
utils::hook::jump(0x140471AAC, reinterpret_cast<void*>(0x140471A50));
|
||||||
@ -272,17 +276,31 @@ namespace network
|
|||||||
utils::hook::jump(0x1405019CB, 0x1405019F3);
|
utils::hook::jump(0x1405019CB, 0x1405019F3);
|
||||||
|
|
||||||
// don't try to reconnect client
|
// don't try to reconnect client
|
||||||
utils::hook::call(0x14047197E, reconnect_migratated_client);
|
utils::hook::call(0x14047197E, reconnect_migrated_client);
|
||||||
|
|
||||||
// allow server owner to modify net_port before the socket bind
|
// allow server owner to modify net_port before the socket bind
|
||||||
utils::hook::call(0x140500FD0, register_netport_stub);
|
utils::hook::call(0x140500FD0, register_netport_stub);
|
||||||
|
|
||||||
// ignore built in "print" oob command and add in our own
|
// ignore built in "print" oob command for security reasons
|
||||||
utils::hook::set<std::uint8_t>(0x1402C6AA4, 0xEB);
|
utils::hook::set<std::uint8_t>(0x1402C6AA4, 0xEB);
|
||||||
on("print", [](const game::netadr_s&, const std::string& data)
|
if (!game::environment::is_dedi())
|
||||||
{
|
{
|
||||||
console::info("%s", data.data());
|
// we need this on the client for RCon
|
||||||
});
|
on("print", [](const game::netadr_s& address, const std::string& message)
|
||||||
|
{
|
||||||
|
if (address != party::get_target())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console::info("%s", message.data());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// patch buffer overflow
|
||||||
|
utils::hook::call(0x14041D17E, memmove_stub); // NET_DeferPacketToClient
|
||||||
|
// this patches a crash found in a subroutine registered using atexit
|
||||||
|
utils::hook::set<std::uint8_t>(0x140815D4E, 0xEB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -60,54 +60,6 @@ namespace patches
|
|||||||
return com_register_dvars_hook.invoke<void>();
|
return com_register_dvars_hook.invoke<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::hook::detour dvar_register_int_hook;
|
|
||||||
|
|
||||||
game::dvar_t* dvar_register_int(const char* name, int value, const int min, const int max,
|
|
||||||
const unsigned int flags,
|
|
||||||
const char* description)
|
|
||||||
{
|
|
||||||
// enable map selection in extinction
|
|
||||||
if (!strcmp(name, "extinction_map_selection_enabled"))
|
|
||||||
{
|
|
||||||
value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable extra loadouts
|
|
||||||
else if (!strcmp(name, "extendedLoadoutsEnable"))
|
|
||||||
{
|
|
||||||
value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// show all in-game store items
|
|
||||||
else if (strstr(name, "igs_"))
|
|
||||||
{
|
|
||||||
value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dvar_register_int_hook.invoke<game::dvar_t*>(name, value, min, max, flags, description);
|
|
||||||
}
|
|
||||||
|
|
||||||
game::dvar_t* register_fovscale_stub(const char* name, float /*value*/, float /*min*/, float /*max*/,
|
|
||||||
unsigned int /*flags*/,
|
|
||||||
const char* desc)
|
|
||||||
{
|
|
||||||
// changed max value from 2.0f -> 5.0f and min value from 0.5f -> 0.1f
|
|
||||||
return game::Dvar_RegisterFloat(name, 1.0f, 0.1f, 5.0f, game::DvarFlags::DVAR_FLAG_SAVED, desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
game::dvar_t* register_cg_gun_dvars(const char* name, float /*value*/, float /*min*/, float /*max*/,
|
|
||||||
unsigned int /*flags*/, const char* desc)
|
|
||||||
{
|
|
||||||
if (name == "cg_gun_x"s)
|
|
||||||
{
|
|
||||||
return game::Dvar_RegisterFloat(name, 0.0f, -1.0f, 2.0f, game::DvarFlags::DVAR_FLAG_SAVED, desc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return game::Dvar_RegisterFloat(name, 0.0f, 0.0f, 0.0f, game::DvarFlags::DVAR_FLAG_NONE, desc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
game::dvar_t* register_network_fps_stub(const char* name, int, int, int, unsigned int flags,
|
game::dvar_t* register_network_fps_stub(const char* name, int, int, int, unsigned int flags,
|
||||||
const char* desc)
|
const char* desc)
|
||||||
{
|
{
|
||||||
@ -180,14 +132,14 @@ namespace patches
|
|||||||
{
|
{
|
||||||
if (args.size() == 1)
|
if (args.size() == 1)
|
||||||
{
|
{
|
||||||
const auto current = game::Dvar_ValueToString(dvar, dvar->current);
|
const std::string current = game::Dvar_ValueToString(dvar, dvar->current);
|
||||||
const auto reset = game::Dvar_ValueToString(dvar, dvar->reset);
|
const std::string reset = game::Dvar_ValueToString(dvar, dvar->reset);
|
||||||
console::info("\"%s\" is: \"%s^7\" default: \"%s^7\"\n", dvar->name, current, reset);
|
console::info("\"%s\" is: \"%s^7\" default: \"%s^7\"\n", dvar->name, current.data(), reset.data());
|
||||||
console::info(" %s\n", dvars::dvar_get_domain(dvar->type, dvar->domain).data());
|
console::info(" %s\n", dvars::dvar_get_domain(dvar->type, dvar->domain).data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char command[0x1000] = {0};
|
char command[0x1000]{};
|
||||||
game::Dvar_GetCombinedString(command, 1);
|
game::Dvar_GetCombinedString(command, 1);
|
||||||
game::Dvar_SetCommand(args.get(0), command);
|
game::Dvar_SetCommand(args.get(0), command);
|
||||||
}
|
}
|
||||||
@ -280,7 +232,7 @@ namespace patches
|
|||||||
LoadLibraryA("PhysXUpdateLoader64.dll");
|
LoadLibraryA("PhysXUpdateLoader64.dll");
|
||||||
|
|
||||||
// Unlock fps in main menu
|
// Unlock fps in main menu
|
||||||
utils::hook::set<BYTE>(SELECT_VALUE(0x140242DDB, 0x1402CF58B), 0xEB);
|
utils::hook::set<std::uint8_t>(SELECT_VALUE(0x140242DDB, 0x1402CF58B), 0xEB);
|
||||||
|
|
||||||
// Unlock cg_fov
|
// Unlock cg_fov
|
||||||
utils::hook::call(SELECT_VALUE(0x1401F3E96, 0x14027273C), register_cg_fov_stub);
|
utils::hook::call(SELECT_VALUE(0x1401F3E96, 0x14027273C), register_cg_fov_stub);
|
||||||
@ -289,14 +241,10 @@ namespace patches
|
|||||||
utils::hook::call(0x1401F3EC7, register_cg_fov_stub);
|
utils::hook::call(0x1401F3EC7, register_cg_fov_stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set it to 3 to display both voice dlc announcers did only show 1
|
|
||||||
game::Dvar_RegisterInt("igs_announcer", 3, 3, 3, game::DvarFlags::DVAR_FLAG_NONE,
|
|
||||||
"Show Announcer Packs. (Bitfield representing which announcer paks to show)");
|
|
||||||
|
|
||||||
// changed max value from 85 -> 1000
|
// changed max value from 85 -> 1000
|
||||||
if (!game::environment::is_dedi())
|
if (!game::environment::is_dedi())
|
||||||
{
|
{
|
||||||
game::Dvar_RegisterInt("com_maxfps", 85, 0, 1000, game::DvarFlags::DVAR_FLAG_SAVED, "Cap frames per second");
|
dvars::override::register_int("com_maxfps", 85, 0, 1000, game::DVAR_FLAG_SAVED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game::environment::is_sp())
|
if (!game::environment::is_sp())
|
||||||
@ -307,12 +255,12 @@ namespace patches
|
|||||||
|
|
||||||
// register cg_gun_ dvars with new values and flags
|
// register cg_gun_ dvars with new values and flags
|
||||||
// maybe _x can stay usable within a reasonable range? it can make scoped weapons DRASTICALLY better on high FOVs
|
// maybe _x can stay usable within a reasonable range? it can make scoped weapons DRASTICALLY better on high FOVs
|
||||||
utils::hook::call(SELECT_VALUE(0x140228DDE, 0x1402AB04C), register_cg_gun_dvars);
|
dvars::override::register_float("cg_gun_x", 0.0f, -1.0f, 2.0f, game::DVAR_FLAG_SAVED);
|
||||||
utils::hook::call(SELECT_VALUE(0x140228E0E, 0x1402AB07C), register_cg_gun_dvars);
|
dvars::override::register_float("cg_gun_y", 0.0f, 0.0f, 0.0f, game::DVAR_FLAG_NONE);
|
||||||
utils::hook::call(SELECT_VALUE(0x140228E3E, 0x1402AB0AC), register_cg_gun_dvars);
|
dvars::override::register_float("cg_gun_z", 0.0f, 0.0f, 0.0f, game::DVAR_FLAG_NONE);
|
||||||
|
|
||||||
// Register cg_fovscale with new params
|
// Register cg_fovscale with new params
|
||||||
utils::hook::call(SELECT_VALUE(0x140317079, 0x140272777), register_fovscale_stub);
|
dvars::override::register_float("cg_fovScale", 1.0f, 0.1f, 5.0f, game::DVAR_FLAG_SAVED);
|
||||||
|
|
||||||
// Patch Dvar_Command to print out values how CoD4 does it
|
// Patch Dvar_Command to print out values how CoD4 does it
|
||||||
utils::hook::jump(SELECT_VALUE(0x1403BFCB0, 0x140416A60), dvar_command_patch);
|
utils::hook::jump(SELECT_VALUE(0x1403BFCB0, 0x140416A60), dvar_command_patch);
|
||||||
@ -320,8 +268,7 @@ namespace patches
|
|||||||
// Allow executing custom cfg files with the "exec" command
|
// Allow executing custom cfg files with the "exec" command
|
||||||
utils::hook::jump(SELECT_VALUE(0x1403B39BB, 0x1403F752B), SELECT_VALUE(0x1403B3A12, 0x1403F7582));
|
utils::hook::jump(SELECT_VALUE(0x1403B39BB, 0x1403F752B), SELECT_VALUE(0x1403B3A12, 0x1403F7582));
|
||||||
//Use a relative jump to empty memory first
|
//Use a relative jump to empty memory first
|
||||||
utils::hook::jump(SELECT_VALUE(0x1403B3A12, 0x1403F7582), SELECT_VALUE(cmd_exec_stub_sp, cmd_exec_stub_mp),
|
utils::hook::jump(SELECT_VALUE(0x1403B3A12, 0x1403F7582), SELECT_VALUE(cmd_exec_stub_sp, cmd_exec_stub_mp), true);
|
||||||
true);
|
|
||||||
// Use empty memory to go to our stub first (can't do close jump, so need space for 12 bytes)
|
// Use empty memory to go to our stub first (can't do close jump, so need space for 12 bytes)
|
||||||
|
|
||||||
// Fix mouse lag
|
// Fix mouse lag
|
||||||
@ -331,10 +278,6 @@ namespace patches
|
|||||||
SetThreadExecutionState(ES_DISPLAY_REQUIRED);
|
SetThreadExecutionState(ES_DISPLAY_REQUIRED);
|
||||||
}, scheduler::pipeline::main);
|
}, scheduler::pipeline::main);
|
||||||
|
|
||||||
// Allow kbam input when gamepad is enabled
|
|
||||||
utils::hook::nop(SELECT_VALUE(0x14023D490, 0x1402C3099), 2);
|
|
||||||
utils::hook::nop(SELECT_VALUE(0x14023B3AC, 0x1402C0CE0), 6);
|
|
||||||
|
|
||||||
if (game::environment::is_sp())
|
if (game::environment::is_sp())
|
||||||
{
|
{
|
||||||
patch_sp();
|
patch_sp();
|
||||||
@ -365,7 +308,23 @@ namespace patches
|
|||||||
utils::hook::set(0x140599890, 0xC301B0); // Entitlements_IsIDUnlocked
|
utils::hook::set(0x140599890, 0xC301B0); // Entitlements_IsIDUnlocked
|
||||||
|
|
||||||
// Enable DLC items, extra loadouts and map selection in extinction
|
// Enable DLC items, extra loadouts and map selection in extinction
|
||||||
dvar_register_int_hook.create(0x1404EE270, &dvar_register_int);
|
dvars::override::register_int("extinction_map_selection_enabled", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("extendedLoadoutsEnable", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_announcer", 3, 3, 3, 0);
|
||||||
|
dvars::override::register_int("igs_swp", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_shp", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_svp", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_sve", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_svs", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_svr", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_swap", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_fo", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_td", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_sripper", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_smappacks", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_sosp", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_s1", 1, 0, 1, 0);
|
||||||
|
dvars::override::register_int("igs_crossgame", 1, 0, 1, 0);
|
||||||
|
|
||||||
// Patch game chat on resolutions higher than 1080p to use the right font
|
// Patch game chat on resolutions higher than 1080p to use the right font
|
||||||
utils::hook::call(0x14025C825, get_chat_font_handle);
|
utils::hook::call(0x14025C825, get_chat_font_handle);
|
||||||
@ -373,7 +332,7 @@ namespace patches
|
|||||||
utils::hook::call(0x1402C3699, get_chat_font_handle);
|
utils::hook::call(0x1402C3699, get_chat_font_handle);
|
||||||
|
|
||||||
dvars::aimassist_enabled = game::Dvar_RegisterBool("aimassist_enabled", true,
|
dvars::aimassist_enabled = game::Dvar_RegisterBool("aimassist_enabled", true,
|
||||||
game::DvarFlags::DVAR_FLAG_SAVED,
|
game::DVAR_FLAG_SAVED,
|
||||||
"Enables aim assist for controllers");
|
"Enables aim assist for controllers");
|
||||||
// Client side aim assist dvar
|
// Client side aim assist dvar
|
||||||
utils::hook::call(0x14013B9AC, aim_assist_add_to_target_list);
|
utils::hook::call(0x14013B9AC, aim_assist_add_to_target_list);
|
||||||
|
@ -17,10 +17,20 @@ namespace ranked
|
|||||||
utils::hook::detour bg_bot_fast_file_enabled_hook;
|
utils::hook::detour bg_bot_fast_file_enabled_hook;
|
||||||
utils::hook::detour bg_bots_using_team_difficulty_hook;
|
utils::hook::detour bg_bots_using_team_difficulty_hook;
|
||||||
|
|
||||||
int bg_bot_system_enabled_stub()
|
bool should_activate_bot_system()
|
||||||
{
|
{
|
||||||
const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string;
|
const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string;
|
||||||
if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde"))
|
if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bg_bot_system_enabled_stub()
|
||||||
|
{
|
||||||
|
if (!should_activate_bot_system())
|
||||||
{
|
{
|
||||||
return bg_bot_system_enabled_hook.invoke<int>();
|
return bg_bot_system_enabled_hook.invoke<int>();
|
||||||
}
|
}
|
||||||
@ -30,8 +40,7 @@ namespace ranked
|
|||||||
|
|
||||||
int bg_ai_system_enabled_stub()
|
int bg_ai_system_enabled_stub()
|
||||||
{
|
{
|
||||||
const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string;
|
if (!should_activate_bot_system())
|
||||||
if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde"))
|
|
||||||
{
|
{
|
||||||
return bg_ai_system_enabled_hook.invoke<int>();
|
return bg_ai_system_enabled_hook.invoke<int>();
|
||||||
}
|
}
|
||||||
@ -41,8 +50,7 @@ namespace ranked
|
|||||||
|
|
||||||
int bg_bot_fast_file_enabled_stub()
|
int bg_bot_fast_file_enabled_stub()
|
||||||
{
|
{
|
||||||
const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string;
|
if (!should_activate_bot_system())
|
||||||
if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde"))
|
|
||||||
{
|
{
|
||||||
return bg_bot_fast_file_enabled_hook.invoke<int>();
|
return bg_bot_fast_file_enabled_hook.invoke<int>();
|
||||||
}
|
}
|
||||||
@ -52,8 +60,7 @@ namespace ranked
|
|||||||
|
|
||||||
int bg_bots_using_team_difficulty_stub()
|
int bg_bots_using_team_difficulty_stub()
|
||||||
{
|
{
|
||||||
const auto* game_type = game::Dvar_FindVar("g_gametype")->current.string;
|
if (!should_activate_bot_system())
|
||||||
if (!std::strcmp(game_type, "aliens") || !std::strcmp(game_type, "horde"))
|
|
||||||
{
|
{
|
||||||
return bg_bots_using_team_difficulty_hook.invoke<int>();
|
return bg_bots_using_team_difficulty_hook.invoke<int>();
|
||||||
}
|
}
|
||||||
@ -86,7 +93,7 @@ namespace ranked
|
|||||||
game::Dvar_RegisterBool("force_ranking", true, game::DVAR_FLAG_WRITE, "Force ranking");
|
game::Dvar_RegisterBool("force_ranking", true, game::DVAR_FLAG_WRITE, "Force ranking");
|
||||||
|
|
||||||
// Fix sessionteam always returning none (SV_HasAssignedTeam_Internal)
|
// Fix sessionteam always returning none (SV_HasAssignedTeam_Internal)
|
||||||
utils::hook::set(0x140479CF0, 0xC300B0);
|
utils::hook::set<std::uint32_t>(0x140479CF0, 0xC300B0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always run bots, even if xblive_privatematch is 0
|
// Always run bots, even if xblive_privatematch is 0
|
||||||
|
@ -15,6 +15,7 @@ namespace rcon
|
|||||||
{
|
{
|
||||||
bool is_redirecting_ = false;
|
bool is_redirecting_ = false;
|
||||||
game::netadr_s redirect_target_ = {};
|
game::netadr_s redirect_target_ = {};
|
||||||
|
std::string redirect_buffer = {};
|
||||||
std::recursive_mutex redirect_lock;
|
std::recursive_mutex redirect_lock;
|
||||||
|
|
||||||
void setup_redirect(const game::netadr_s& target)
|
void setup_redirect(const game::netadr_s& target)
|
||||||
@ -23,14 +24,18 @@ namespace rcon
|
|||||||
|
|
||||||
is_redirecting_ = true;
|
is_redirecting_ = true;
|
||||||
redirect_target_ = target;
|
redirect_target_ = target;
|
||||||
|
redirect_buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_redirect()
|
void clear_redirect()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> $(redirect_lock);
|
std::lock_guard<std::recursive_mutex> $(redirect_lock);
|
||||||
|
|
||||||
|
network::send(redirect_target_, "print", redirect_buffer, '\n');
|
||||||
|
|
||||||
is_redirecting_ = false;
|
is_redirecting_ = false;
|
||||||
redirect_target_ = {};
|
redirect_target_ = {};
|
||||||
|
redirect_buffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string build_status_buffer()
|
std::string build_status_buffer()
|
||||||
@ -48,7 +53,7 @@ namespace rcon
|
|||||||
const auto client = &game::mp::svs_clients[i];
|
const auto client = &game::mp::svs_clients[i];
|
||||||
auto self = &game::mp::g_entities[i];
|
auto self = &game::mp::g_entities[i];
|
||||||
|
|
||||||
char clean_name[32] = {0};
|
char clean_name[32]{};
|
||||||
strncpy_s(clean_name, self->client->sess.cs.name, sizeof(clean_name));
|
strncpy_s(clean_name, self->client->sess.cs.name, sizeof(clean_name));
|
||||||
game::I_CleanStr(clean_name);
|
game::I_CleanStr(clean_name);
|
||||||
|
|
||||||
@ -104,9 +109,10 @@ namespace rcon
|
|||||||
|
|
||||||
if (is_redirecting_)
|
if (is_redirecting_)
|
||||||
{
|
{
|
||||||
network::send(redirect_target_, "print\n", message);
|
redirect_buffer.append(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +181,7 @@ namespace rcon
|
|||||||
|
|
||||||
const auto password = data.substr(0, pos);
|
const auto password = data.substr(0, pos);
|
||||||
const auto command = data.substr(pos + 1);
|
const auto command = data.substr(pos + 1);
|
||||||
const auto rcon_password = game::Dvar_FindVar("rcon_password");
|
const auto* rcon_password = game::Dvar_FindVar("rcon_password");
|
||||||
if (command.empty() || !rcon_password || !*rcon_password->current.string)
|
if (command.empty() || !rcon_password || !*rcon_password->current.string)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -13,7 +13,7 @@ namespace demonware
|
|||||||
{
|
{
|
||||||
auto result = new bdDMLRawData;
|
auto result = new bdDMLRawData;
|
||||||
result->country_code = "US";
|
result->country_code = "US";
|
||||||
result->country_code = "'Murica";
|
result->country = "United States of America";
|
||||||
result->region = "New York";
|
result->region = "New York";
|
||||||
result->city = "New York";
|
result->city = "New York";
|
||||||
result->latitude = 0;
|
result->latitude = 0;
|
||||||
|
@ -45,6 +45,9 @@ namespace dvars
|
|||||||
|
|
||||||
game::dvar_t* cg_legacyCrashHandling = nullptr;
|
game::dvar_t* cg_legacyCrashHandling = nullptr;
|
||||||
|
|
||||||
|
game::dvar_t* com_developer_script = nullptr;
|
||||||
|
game::dvar_t** com_developer;
|
||||||
|
|
||||||
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
|
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
|
||||||
{
|
{
|
||||||
if (domain.vector.min == -FLT_MAX)
|
if (domain.vector.min == -FLT_MAX)
|
||||||
@ -78,14 +81,14 @@ namespace dvars
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case game::dvar_type::boolean:
|
case game::dvar_type::boolean:
|
||||||
return "Domain is 0 or 1"s;
|
return "Domain is 0 or 1";
|
||||||
|
|
||||||
case game::dvar_type::value:
|
case game::dvar_type::value:
|
||||||
if (domain.value.min == -FLT_MAX)
|
if (domain.value.min == -FLT_MAX)
|
||||||
{
|
{
|
||||||
if (domain.value.max == FLT_MAX)
|
if (domain.value.max == FLT_MAX)
|
||||||
{
|
{
|
||||||
return "Domain is any number"s;
|
return "Domain is any number";
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::string::va("Domain is any number %g or smaller", domain.value.max);
|
return utils::string::va("Domain is any number %g or smaller", domain.value.max);
|
||||||
@ -113,7 +116,7 @@ namespace dvars
|
|||||||
{
|
{
|
||||||
if (domain.integer.max == INT_MAX)
|
if (domain.integer.max == INT_MAX)
|
||||||
{
|
{
|
||||||
return "Domain is any integer"s;
|
return "Domain is any integer";
|
||||||
}
|
}
|
||||||
|
|
||||||
return utils::string::va("Domain is any integer %i or smaller", domain.integer.max);
|
return utils::string::va("Domain is any integer %i or smaller", domain.integer.max);
|
||||||
@ -127,10 +130,10 @@ namespace dvars
|
|||||||
return utils::string::va("Domain is any integer from %i to %i", domain.integer.min, domain.integer.max);
|
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::dvar_type::color:
|
||||||
return "Domain is any 4-component color, in RGBA format"s;
|
return "Domain is any 4-component color, in RGBA format";
|
||||||
|
|
||||||
case game::dvar_type::enumeration:
|
case game::dvar_type::enumeration:
|
||||||
str = "Domain is one of the following:"s;
|
str = "Domain is one of the following:";
|
||||||
|
|
||||||
for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index)
|
for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index)
|
||||||
{
|
{
|
||||||
@ -140,7 +143,7 @@ namespace dvars
|
|||||||
return str;
|
return str;
|
||||||
|
|
||||||
case game::dvar_type::string:
|
case game::dvar_type::string:
|
||||||
return "Domain is any text"s;
|
return "Domain is any text";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return utils::string::va("unhandled dvar type '%i'", type);
|
return utils::string::va("unhandled dvar type '%i'", type);
|
||||||
|
@ -44,6 +44,9 @@ namespace dvars
|
|||||||
|
|
||||||
extern game::dvar_t* cg_legacyCrashHandling;
|
extern game::dvar_t* cg_legacyCrashHandling;
|
||||||
|
|
||||||
|
extern game::dvar_t* com_developer_script;
|
||||||
|
extern game::dvar_t** com_developer;
|
||||||
|
|
||||||
std::string dvar_get_vector_domain(int components, const game::dvar_limits& domain);
|
std::string dvar_get_vector_domain(int components, const game::dvar_limits& domain);
|
||||||
std::string dvar_get_domain(game::dvar_type type, const game::dvar_limits& domain);
|
std::string dvar_get_domain(game::dvar_type type, const game::dvar_limits& domain);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,21 @@
|
|||||||
|
|
||||||
#include <version.hpp>
|
#include <version.hpp>
|
||||||
|
|
||||||
|
const char* get_current_date()
|
||||||
|
{
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto current_time = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm local_time{};
|
||||||
|
|
||||||
|
(void)localtime_s(&local_time, ¤t_time);
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::put_time(&local_time, "%Y%m%d_%H%M%S");
|
||||||
|
|
||||||
|
const auto result = ss.str();
|
||||||
|
return utils::string::va("%s", result.data());
|
||||||
|
}
|
||||||
|
|
||||||
LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info)
|
LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info)
|
||||||
{
|
{
|
||||||
if (exception_info->ExceptionRecord->ExceptionCode == 0x406D1388)
|
if (exception_info->ExceptionRecord->ExceptionCode == 0x406D1388)
|
||||||
@ -38,7 +53,7 @@ LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info)
|
|||||||
| MiniDumpWithThreadInfo;
|
| MiniDumpWithThreadInfo;
|
||||||
|
|
||||||
CreateDirectoryA("minidumps", nullptr);
|
CreateDirectoryA("minidumps", nullptr);
|
||||||
const auto* file_name = utils::string::va("minidumps\\iw6-mod_%s_%u.dmp", SHORTVERSION, static_cast<std::uint32_t>(std::time(nullptr)));
|
const auto* file_name = utils::string::va("minidumps\\iw6-mod_%s_%s.dmp", SHORTVERSION, get_current_date());
|
||||||
constexpr auto file_share = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
constexpr auto file_share = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||||
|
|
||||||
const auto file_handle = CreateFileA(file_name, GENERIC_WRITE | GENERIC_READ, file_share, nullptr,
|
const auto file_handle = CreateFileA(file_name, GENERIC_WRITE | GENERIC_READ, file_share, nullptr,
|
||||||
|
Loading…
Reference in New Issue
Block a user