Merge pull request #167 from XLabsProject/release/v1.0.3

Release v1.0.3
This commit is contained in:
Maurice Heumann 2021-05-04 13:32:46 +02:00 committed by GitHub
commit 8ecc8f9e34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 246 additions and 94 deletions

7
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: gitsubmodule
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10

2
.gitmodules vendored
View File

@ -10,7 +10,7 @@
[submodule "deps/protobuf"]
path = deps/protobuf
url = https://github.com/google/protobuf.git
branch = 3.14.x
branch = 3.15.x
[submodule "deps/minhook"]
path = deps/minhook
url = https://github.com/TsudaKageyu/minhook.git

View File

@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [v1.0.3] - 2021-05-04
### Added
- Use patrons for bot names [#128](https://github.com/XLabsProject/s1x-client/issues/128)
- Increase network packet limit [#102](https://github.com/XLabsProject/s1x-client/issues/102)
### Fixed
- Possible duplicate GUID [#166](https://github.com/XLabsProject/s1x-client/issues/166)
### Pull Requests
- Game variable support #161 [#164](https://github.com/XLabsProject/s1x-client/pull/164) ([@fedddddd](https://github.com/fedddddd))
## [v1.0.2] - 2021-04-29
### Added
@ -111,7 +126,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Discord RPC - party size + party size max [#59](https://github.com/XLabsProject/s1x-client/pull/59) ([@mjkzy](https://github.com/mjkzy))
- discord presence - host name address [#64](https://github.com/XLabsProject/s1x-client/pull/64) ([@mjkzy](https://github.com/mjkzy))
[Unreleased]: https://github.com/XLabsProject/s1x-client/compare/v1.0.2...HEAD
[Unreleased]: https://github.com/XLabsProject/s1x-client/compare/v1.0.3...HEAD
[v1.0.3]: https://github.com/XLabsProject/s1x-client/compare/v1.0.2...v1.0.3
[v1.0.2]: https://github.com/XLabsProject/s1x-client/compare/v1.0.1...v1.0.2

2
deps/protobuf vendored

@ -1 +1 @@
Subproject commit 19fb89416f3fdc2d6668f3738f444885575285bc
Subproject commit 436bd7880e458532901c58f4d9d1ea23fa7edd52

View File

@ -17,16 +17,62 @@ namespace auth
{
namespace
{
std::string get_key_entropy()
std::string get_hdd_serial()
{
auto uuid = utils::smbios::get_uuid();
if (uuid.empty())
DWORD serial{};
if (!GetVolumeInformationA("C:\\", nullptr, 0, &serial, nullptr, nullptr, nullptr, 0))
{
uuid.resize(16);
utils::cryptography::random::get_data(uuid.data(), uuid.size());
return {};
}
return uuid;
return utils::string::va("%08X", serial);
}
std::string get_hw_profile_guid()
{
HW_PROFILE_INFO info;
if (!GetCurrentHwProfileA(&info))
{
return {};
}
return std::string{info.szHwProfileGuid, sizeof(info.szHwProfileGuid)};
}
std::string get_protected_data()
{
std::string input = "X-Labs-S1x-Auth";
DATA_BLOB data_in{}, data_out{};
data_in.pbData = reinterpret_cast<uint8_t*>(input.data());
data_in.cbData = static_cast<DWORD>(input.size());
if(CryptProtectData(&data_in, nullptr, nullptr, nullptr, nullptr, CRYPTPROTECT_LOCAL_MACHINE, &data_out) != TRUE)
{
return {};
}
const auto size = std::min(data_out.cbData, 52ul);
std::string result{reinterpret_cast<char*>(data_out.pbData), size};
LocalFree(data_out.pbData);
return result;
}
std::string get_key_entropy()
{
std::string entropy{};
entropy.append(utils::smbios::get_uuid());
entropy.append(get_hw_profile_guid());
entropy.append(get_protected_data());
entropy.append(get_hdd_serial());
if (entropy.empty())
{
entropy.resize(32);
utils::cryptography::random::get_data(entropy.data(), entropy.size());
}
return entropy;
}
utils::cryptography::ecc::key& get_key()

View File

@ -132,6 +132,25 @@ namespace dedicated
com_quit_f_hook.invoke<void>();
}
void sys_error_stub(const char* msg, ...)
{
char buffer[2048];
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
scheduler::once([]()
{
command::execute("map_rotate");
}, scheduler::main, 3s);
game::Com_Error(game::ERR_DROP, "%s", buffer);
}
}
void initialize()
@ -171,6 +190,9 @@ namespace dedicated
// Don't allow sv_hostname to be changed by the game
dvars::disable::Dvar_SetString("sv_hostname");
// Stop crashing from sys_errors
utils::hook::jump(0x1404D6260, sys_error_stub);
// Hook R_SyncGpu
utils::hook::jump(0x1405A7630, sync_gpu_stub);

View File

@ -62,79 +62,83 @@ namespace logfile
}
void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage,
int meansOfDeath, const unsigned int weapon, bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration)
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**>(0x1409B5400)[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 std::string _hitLoc = reinterpret_cast<const char**>(0x1409B5400)[hitLoc];
const auto _mod = convert_mod(meansOfDeath);
const auto _self = convert_entity(state, self);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _weapon = get_weapon_name(weapon, isAlternate);
const auto _vDir = convert_vector(state, vDir);
const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _vDir, _hitLoc, psTimeOffset, deathAnimDuration);
scripting::lua::handle_error(result);
if (result.valid() && result.get_type() == sol::type::number)
for (const auto& callback : player_killed_callbacks)
{
damage = result.get<int>();
}
}
const auto state = callback.lua_state();
if (damage == 0)
{
return;
const auto _self = convert_entity(state, self);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _vDir = convert_vector(state, vDir);
const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _vDir, _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,
int meansOfDeath, const unsigned int weapon, bool isAlternate, const float* vPoint, const float* vDir, const unsigned int hitLoc, int timeOffset)
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**>(0x1409B5400)[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 std::string _hitLoc = reinterpret_cast<const char**>(0x1409B5400)[hitLoc];
const auto _mod = convert_mod(meansOfDeath);
const auto _self = convert_entity(state, self);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _weapon = get_weapon_name(weapon, isAlternate);
const auto _vPoint = convert_vector(state, vPoint);
const auto _vDir = convert_vector(state, vDir);
const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _vPoint, _vDir, _hitLoc);
scripting::lua::handle_error(result);
if (result.valid() && result.get_type() == sol::type::number)
for (const auto& callback : player_damage_callbacks)
{
damage = result.get<int>();
}
}
const auto state = callback.lua_state();
if (damage == 0)
{
return;
const auto _self = convert_entity(state, self);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _vPoint = convert_vector(state, vPoint);
const auto _vDir = convert_vector(state, vDir);
const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _vPoint, _vDir, _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(int clientNum)
void client_command_stub(const int clientNum)
{
auto self = &game::mp::g_entities[clientNum];
char cmd[1024]{};
@ -168,10 +172,12 @@ namespace logfile
return reinterpret_cast<void(*)(int)>(0x1402E98F0)(clientNum);
}
void g_shutdown_game_stub(int freeScripts)
void g_shutdown_game_stub(const int freeScripts)
{
const scripting::entity level{*game::levelEntityId};
scripting::notify(level, "shutdownGame_called", {1});
{
const scripting::entity level{*game::levelEntityId};
scripting::notify(level, "shutdownGame_called", {1});
}
// G_ShutdownGame
return reinterpret_cast<void(*)(int)>(0x1402F8C10)(freeScripts);

View File

@ -10,6 +10,8 @@ namespace logger
{
namespace
{
utils::hook::detour com_error_hook;
void print_error(const char* msg, ...)
{
char buffer[2048];
@ -38,6 +40,24 @@ namespace logger
console::error(buffer);
}
void com_error_stub(const int error, const char* msg, ...)
{
char buffer[2048];
{
va_list ap;
va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap);
va_end(ap);
console::error(buffer);
}
com_error_hook.invoke<void>(error, "%s", buffer);
}
void print_warning(const char* msg, ...)
{
char buffer[2048];
@ -145,6 +165,7 @@ namespace logger
sub_1400E7420();
utils::hook::call(0x1404D8543, print_com_error);
com_error_hook.create(0x1403CE480, com_error_stub);
}
};
}

View File

@ -59,10 +59,7 @@ namespace scripting
void g_shutdown_game_stub(const int free_scripts)
{
if (!game::VirtualLobby_Loaded())
{
lua::engine::stop();
}
lua::engine::stop();
return g_shutdown_game_hook.invoke<void>(free_scripts);
}
}

View File

@ -43,8 +43,8 @@ namespace server_list
std::vector<server_info> servers;
size_t server_list_page = 0;
volatile bool update_server_list = false;
std::chrono::high_resolution_clock::time_point last_scroll{};
size_t get_page_count()
{
@ -220,6 +220,11 @@ namespace server_list
return game::Menu_IsMenuOpenAndVisible(0, "menu_systemlink_join");
}
bool is_scrolling_disabled()
{
return update_server_list || (std::chrono::high_resolution_clock::now() - last_scroll) < 500ms;
}
bool scroll_down()
{
if (!is_server_list_open())
@ -227,8 +232,9 @@ namespace server_list
return false;
}
if (server_list_page + 1 < get_page_count())
if (!is_scrolling_disabled() && server_list_page + 1 < get_page_count())
{
last_scroll = std::chrono::high_resolution_clock::now();
++server_list_page;
trigger_refresh();
}
@ -243,8 +249,9 @@ namespace server_list
return false;
}
if (server_list_page > 0)
if (!is_scrolling_disabled() && server_list_page > 0)
{
last_scroll = std::chrono::high_resolution_clock::now();
--server_list_page;
trigger_refresh();
}

View File

@ -259,6 +259,19 @@ namespace scripting::lua
{
logfile::add_player_killed_callback(callback);
};
game_type["getgamevar"] = [](const sol::this_state s)
{
const auto id = *reinterpret_cast<unsigned int*>(0x14815DEB4);
const auto value = ::game::scr_VarGlob->childVariableValue[id];
::game::VariableValue variable{};
variable.type = value.type;
variable.u.uintValue = value.u.u.uintValue;
return convert(s, variable);
};
}
}
@ -301,7 +314,7 @@ namespace scripting::lua
context::~context()
{
this->state_.collect_garbage();
this->collect_garbage();
this->scheduler_.clear();
this->event_handler_.clear();
this->state_ = {};
@ -310,7 +323,7 @@ namespace scripting::lua
void context::run_frame()
{
this->scheduler_.run_frame();
this->state_.collect_garbage();
this->collect_garbage();
}
void context::notify(const event& e)
@ -318,6 +331,11 @@ namespace scripting::lua
this->event_handler_.dispatch(e);
}
void context::collect_garbage()
{
this->state_.collect_garbage();
}
void context::load_script(const std::string& script)
{
if (!this->loaded_scripts_.emplace(script).second)

View File

@ -30,6 +30,7 @@ namespace scripting::lua
void run_frame();
void notify(const event& e);
void collect_garbage();
private:
sol::state state_{};

View File

@ -32,12 +32,18 @@ namespace scripting::lua::engine
{
if (std::filesystem::is_directory(script) && utils::io::file_exists(script + "/__init__.lua"))
{
get_scripts().push_back(std::make_unique<context>(script));
get_scripts().emplace_back(std::make_unique<context>(script));
}
}
}
}
void stop()
{
logfile::clear_callbacks();
get_scripts().clear();
}
void start()
{
// No SP until there is a concept
@ -46,17 +52,10 @@ namespace scripting::lua::engine
return;
}
clear_custom_fields();
get_scripts().clear();
stop();
load_scripts();
}
void stop()
{
logfile::clear_callbacks();
get_scripts().clear();
}
void notify(const event& e)
{
for (auto& script : get_scripts())

View File

@ -18,19 +18,9 @@ namespace scripting::lua
void event_handler::dispatch(const event& event)
{
std::vector<sol::lua_value> arguments;
bool has_built_arguments = false;
event_arguments arguments{};
for (const auto& argument : event.arguments)
{
arguments.emplace_back(convert(this->state_, argument));
}
this->dispatch_to_specific_listeners(event, arguments);
}
void event_handler::dispatch_to_specific_listeners(const event& event,
const event_arguments& arguments)
{
callbacks_.access([&](task_list& tasks)
{
this->merge_callbacks();
@ -45,6 +35,12 @@ namespace scripting::lua
if (!i->is_deleted)
{
if(!has_built_arguments)
{
has_built_arguments = true;
arguments = this->build_arguments(event);
}
handle_error(i->callback(sol::as_args(arguments)));
}
@ -116,4 +112,16 @@ namespace scripting::lua
});
});
}
event_arguments event_handler::build_arguments(const event& event) const
{
event_arguments arguments;
for (const auto& argument : event.arguments)
{
arguments.emplace_back(convert(this->state_, argument));
}
return arguments;
}
}

View File

@ -46,9 +46,9 @@ namespace scripting::lua
utils::concurrency::container<task_list> new_callbacks_;
utils::concurrency::container<task_list, std::recursive_mutex> callbacks_;
void dispatch_to_specific_listeners(const event& event, const event_arguments& arguments);
void remove(const event_listener_handle& handle);
void merge_callbacks();
event_arguments build_arguments(const event& event) const;
};
}

View File

@ -44,6 +44,7 @@
#include <urlmon.h>
#include <atlbase.h>
#include <iphlpapi.h>
#include <wincrypt.h>
// min and max is required by gdi, therefore NOMINMAX won't work
#ifdef max
@ -84,6 +85,7 @@
#include <asmjit/core/jitruntime.h>
#include <asmjit/x86/x86assembler.h>
#include <google/protobuf/stubs/logging.h>
#include <proto/auth.pb.h>
#pragma warning(pop)
@ -93,6 +95,7 @@
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "urlmon.lib" )
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "Crypt32.lib")
#include "resource.hpp"

Binary file not shown.

Binary file not shown.