Merge branch 'master' of https://git.alterware.dev/alterware/s1-mod
This commit is contained in:
commit
ba031d4e5b
@ -122,10 +122,10 @@ This is a client modification for S1!
|
|||||||
- 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\s1-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
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ namespace bots
|
|||||||
|
|
||||||
// SV_BotGetRandomName
|
// SV_BotGetRandomName
|
||||||
const auto* const bot_name = game::SV_BotGetRandomName();
|
const auto* const bot_name = game::SV_BotGetRandomName();
|
||||||
auto* bot_ent = game::SV_AddBot(bot_name);
|
const auto* bot_ent = game::SV_AddBot(bot_name);
|
||||||
if (bot_ent)
|
if (bot_ent)
|
||||||
{
|
{
|
||||||
spawn_bot(bot_ent->s.number);
|
spawn_bot(bot_ent->s.number);
|
||||||
@ -79,22 +79,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;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_bot_names_from_file()
|
void parse_bot_names_from_file()
|
||||||
@ -122,11 +113,30 @@ namespace bots
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void update_bot_names()
|
||||||
{
|
{
|
||||||
bot_names_received = false;
|
bot_names_received = false;
|
||||||
|
|
||||||
game::netadr_s master;
|
game::netadr_s master{};
|
||||||
if (server_list::get_master_server(master))
|
if (server_list::get_master_server(master))
|
||||||
{
|
{
|
||||||
console::info("Getting bots...\n");
|
console::info("Getting bots...\n");
|
||||||
@ -167,7 +177,7 @@ namespace bots
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (should_update_bot_names())
|
if (should_use_remote_bot_names())
|
||||||
{
|
{
|
||||||
scheduler::on_game_initialized([]() -> void
|
scheduler::on_game_initialized([]() -> void
|
||||||
{
|
{
|
||||||
@ -187,6 +197,7 @@ namespace bots
|
|||||||
{
|
{
|
||||||
const std::string received_data{ data };
|
const std::string received_data{ data };
|
||||||
bot_names = utils::string::split(received_data, '\n');
|
bot_names = utils::string::split(received_data, '\n');
|
||||||
|
console::info("Got %zu names from the master server\n", bot_names.size());
|
||||||
bot_names_received = true;
|
bot_names_received = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#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"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
@ -19,8 +21,6 @@ namespace gsc
|
|||||||
std::uint16_t function_id_start = 0x2DF;
|
std::uint16_t function_id_start = 0x2DF;
|
||||||
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 +135,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>(0x1404B6790, mark_pos);
|
utils::hook::invoke<void>(0x1404B6790, mark_pos);
|
||||||
return;
|
return;
|
||||||
@ -263,8 +263,6 @@ namespace gsc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments");
|
|
||||||
|
|
||||||
utils::hook::nop(0x1403FB7F7 + 5, 2);
|
utils::hook::nop(0x1403FB7F7 + 5, 2);
|
||||||
utils::hook::call(0x1403FB7F7, vm_call_builtin_function);
|
utils::hook::call(0x1403FB7F7, 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 scr_error(const char* error);
|
void scr_error(const char* error);
|
||||||
void override_function(const std::string& name, game::BuiltinFunction func);
|
void override_function(const std::string& name, game::BuiltinFunction func);
|
||||||
void add_function(const std::string& name, game::BuiltinFunction function);
|
void add_function(const std::string& name, game::BuiltinFunction function);
|
||||||
|
@ -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/compression.hpp>
|
#include <utils/compression.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();
|
||||||
@ -228,18 +226,6 @@ namespace gsc
|
|||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](const game::XAssetHeader header)
|
|
||||||
{
|
|
||||||
const std::string name = header.rawfile->name;
|
|
||||||
|
|
||||||
if (name.ends_with(".gsc") && name.starts_with("scripts/"))
|
|
||||||
{
|
|
||||||
// Remove .gsc from the file name as it will be re-added by the game later
|
|
||||||
const auto base_name = name.substr(0, name.size() - 4);
|
|
||||||
load_script(base_name);
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
for (const auto& path : filesystem::get_search_paths())
|
for (const auto& path : filesystem::get_search_paths())
|
||||||
{
|
{
|
||||||
load_scripts(path);
|
load_scripts(path);
|
||||||
@ -292,11 +278,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();
|
||||||
|
|
||||||
@ -364,7 +358,8 @@ namespace gsc
|
|||||||
utils::hook::call(SELECT_VALUE(0x1403309E9, 0x1403309E9), scr_begin_load_scripts_stub); // GScr_LoadScripts
|
utils::hook::call(SELECT_VALUE(0x1403309E9, 0x1403309E9), scr_begin_load_scripts_stub); // GScr_LoadScripts
|
||||||
utils::hook::call(SELECT_VALUE(0x14023DA84, 0x140330B9C), scr_end_load_scripts_stub); // GScr_LoadScripts
|
utils::hook::call(SELECT_VALUE(0x14023DA84, 0x140330B9C), 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 = game::Dvar_RegisterInt("developer", 0, 0, 2, game::DVAR_FLAG_NONE, "Enable development options");
|
||||||
|
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,9 +3,10 @@
|
|||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
|
|
||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "network.hpp"
|
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "dvars.hpp"
|
#include "dvars.hpp"
|
||||||
|
#include "network.hpp"
|
||||||
|
#include "party.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
@ -89,14 +90,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(void*, game::netadr_s* from, const int, const int, const char*,
|
void reconnect_migrated_client(void*, 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)
|
||||||
@ -162,7 +167,7 @@ namespace network
|
|||||||
{
|
{
|
||||||
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]);
|
||||||
@ -205,7 +210,7 @@ namespace network
|
|||||||
utils::hook::nop(0x14043FFF8, 6);
|
utils::hook::nop(0x14043FFF8, 6);
|
||||||
|
|
||||||
utils::hook::jump(0x1403DA700, net_compare_address);
|
utils::hook::jump(0x1403DA700, net_compare_address);
|
||||||
utils::hook::jump(0x1403DA750, net_compare_base_address);
|
utils::hook::jump(0x1403DA750, net_compare_address);
|
||||||
|
|
||||||
// don't establish secure conenction
|
// don't establish secure conenction
|
||||||
utils::hook::set<uint8_t>(0x140232BBD, 0xEB);
|
utils::hook::set<uint8_t>(0x140232BBD, 0xEB);
|
||||||
@ -239,8 +244,8 @@ namespace network
|
|||||||
// ignore dw handle in SV_DirectConnect
|
// ignore dw handle in SV_DirectConnect
|
||||||
utils::hook::set<uint8_t>(0x140439BA8, 0xEB);
|
utils::hook::set<uint8_t>(0x140439BA8, 0xEB);
|
||||||
utils::hook::set<uint8_t>(0x140439DA5, 0xEB);
|
utils::hook::set<uint8_t>(0x140439DA5, 0xEB);
|
||||||
utils::hook::call(0x140439B9B, &net_compare_address);
|
utils::hook::call(0x140439B9B, net_compare_address);
|
||||||
utils::hook::call(0x140439D98, &net_compare_address);
|
utils::hook::call(0x140439D98, net_compare_address);
|
||||||
|
|
||||||
// increase cl_maxpackets
|
// increase cl_maxpackets
|
||||||
dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED);
|
dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED);
|
||||||
@ -259,7 +264,7 @@ namespace network
|
|||||||
utils::hook::jump(0x1404D842B, 0x1404D8453);
|
utils::hook::jump(0x1404D842B, 0x1404D8453);
|
||||||
|
|
||||||
// don't try to reconnect client
|
// don't try to reconnect client
|
||||||
utils::hook::call(0x140439D4D, reconnect_migratated_client);
|
utils::hook::call(0x140439D4D, reconnect_migrated_client);
|
||||||
utils::hook::nop(0x140439D28, 4); // this crashes when reconnecting for some reason
|
utils::hook::nop(0x140439D28, 4); // this crashes when reconnecting for some reason
|
||||||
|
|
||||||
// allow server owner to modify net_port before the socket bind
|
// allow server owner to modify net_port before the socket bind
|
||||||
@ -273,13 +278,25 @@ namespace network
|
|||||||
utils::hook::set<int>(0x1403DAD14, max_packet_size);
|
utils::hook::set<int>(0x1403DAD14, max_packet_size);
|
||||||
utils::hook::set<int>(0x1403DAD35, max_packet_size);
|
utils::hook::set<int>(0x1403DAD35, max_packet_size);
|
||||||
|
|
||||||
// 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>(0x14020A723, 0xEB);
|
utils::hook::set<std::uint8_t>(0x14020A723, 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(0x1403DA8A4, memmove_stub); // NET_DeferPacketToClient
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ namespace patches
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sv_kick_client_num_hook.invoke<void>(client_num, reason);
|
return sv_kick_client_num_hook.invoke<void>(client_num, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,14 +94,14 @@ namespace patches
|
|||||||
{
|
{
|
||||||
if (args.size() == 1)
|
if (args.size() == 1)
|
||||||
{
|
{
|
||||||
const auto* const current = game::Dvar_ValueToString(dvar, dvar->current);
|
const std::string current = game::Dvar_ValueToString(dvar, dvar->current);
|
||||||
const auto* const 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);
|
||||||
}
|
}
|
||||||
@ -226,10 +227,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(0x14013EF83, 0x140206DB3), 2);
|
|
||||||
utils::hook::nop(SELECT_VALUE(0x14013CBAC, 0x140204710), 6);
|
|
||||||
|
|
||||||
if (game::environment::is_sp())
|
if (game::environment::is_sp())
|
||||||
{
|
{
|
||||||
patch_sp();
|
patch_sp();
|
||||||
|
@ -16,6 +16,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)
|
||||||
@ -24,14 +25,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_rcon_command(const std::string& password, const std::string& data)
|
void send_rcon_command(const std::string& password, const std::string& data)
|
||||||
@ -79,7 +84,7 @@ namespace rcon
|
|||||||
strncpy_s(clean_name, client->name, _TRUNCATE);
|
strncpy_s(clean_name, client->name, _TRUNCATE);
|
||||||
game::I_CleanStr(clean_name);
|
game::I_CleanStr(clean_name);
|
||||||
|
|
||||||
if (client->header.state >= 1)
|
if (client->header.state > game::CA_DISCONNECTED)
|
||||||
{
|
{
|
||||||
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
|
buffer.append(utils::string::va("%3i %5i %3s %s %32s %16s %21s %5i\n",
|
||||||
i,
|
i,
|
||||||
@ -104,7 +109,7 @@ namespace rcon
|
|||||||
|
|
||||||
if (is_redirecting_)
|
if (is_redirecting_)
|
||||||
{
|
{
|
||||||
network::send(redirect_target_, "print", message);
|
redirect_buffer.append(message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,12 +141,13 @@ namespace rcon
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console::info("%s", build_status_buffer().data());
|
const auto status = build_status_buffer();
|
||||||
|
console::info("%s", status.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!game::environment::is_dedi())
|
if (!game::environment::is_dedi())
|
||||||
{
|
{
|
||||||
command::add("rcon", [&](const command::params& params)
|
command::add("rcon", [](const command::params& params)
|
||||||
{
|
{
|
||||||
static std::string rcon_password{};
|
static std::string rcon_password{};
|
||||||
|
|
||||||
@ -178,9 +184,8 @@ namespace rcon
|
|||||||
|
|
||||||
const auto password = message.substr(0, pos);
|
const auto password = message.substr(0, pos);
|
||||||
const auto command = message.substr(pos + 1);
|
const auto command = message.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 || !strlen(
|
if (command.empty() || !rcon_password || !*rcon_password->current.string)
|
||||||
rcon_password->current.string))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ namespace stats
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
game::dvar_t* cg_unlock_all_items;
|
const game::dvar_t* cg_unlock_all_items;
|
||||||
game::dvar_t* cg_unlock_all_loot;
|
const game::dvar_t* cg_unlock_all_loot;
|
||||||
|
|
||||||
utils::hook::detour is_item_locked_hook1;
|
utils::hook::detour is_item_locked_hook1;
|
||||||
utils::hook::detour is_item_locked_hook2;
|
utils::hook::detour is_item_locked_hook2;
|
||||||
|
@ -12,7 +12,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;
|
||||||
|
@ -40,6 +40,9 @@ namespace dvars
|
|||||||
|
|
||||||
game::dvar_t* sv_cheats = nullptr;
|
game::dvar_t* sv_cheats = nullptr;
|
||||||
|
|
||||||
|
game::dvar_t* com_developer = nullptr;
|
||||||
|
game::dvar_t* com_developer_script = nullptr;
|
||||||
|
|
||||||
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)
|
||||||
@ -73,14 +76,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";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -111,7 +114,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";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -128,10 +131,10 @@ namespace dvars
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -141,7 +144,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);
|
||||||
|
@ -39,6 +39,9 @@ namespace dvars
|
|||||||
|
|
||||||
extern game::dvar_t* sv_cheats;
|
extern game::dvar_t* sv_cheats;
|
||||||
|
|
||||||
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain);
|
extern game::dvar_t* com_developer;
|
||||||
std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain);
|
extern game::dvar_t* com_developer_script;
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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\\s1-mod_%s_%u.dmp", SHORTVERSION, static_cast<std::uint32_t>(std::time(nullptr)));
|
const auto* file_name = utils::string::va("minidumps\\s1-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,
|
||||||
@ -166,7 +181,11 @@ FARPROC load_binary(const launcher::mode mode)
|
|||||||
binary.data()));
|
binary.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef INJECT_HOST_AS_LIB
|
||||||
return loader.load_library(binary);
|
return loader.load_library(binary);
|
||||||
|
#else
|
||||||
|
return loader.load(self, data);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_crash_file()
|
void remove_crash_file()
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#include <wincrypt.h>
|
#include <wincrypt.h>
|
||||||
|
|
||||||
|
#define INJECT_HOST_AS_LIB
|
||||||
|
|
||||||
// min and max is required by gdi, therefore NOMINMAX won't work
|
// min and max is required by gdi, therefore NOMINMAX won't work
|
||||||
#ifdef max
|
#ifdef max
|
||||||
#undef max
|
#undef max
|
||||||
|
Loading…
Reference in New Issue
Block a user