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"] [submodule "deps/protobuf"]
path = deps/protobuf path = deps/protobuf
url = https://github.com/google/protobuf.git url = https://github.com/google/protobuf.git
branch = 3.14.x branch = 3.15.x
[submodule "deps/minhook"] [submodule "deps/minhook"]
path = deps/minhook path = deps/minhook
url = https://github.com/TsudaKageyu/minhook.git 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] ## [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 ## [v1.0.2] - 2021-04-29
### Added ### 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 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)) - 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 [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 namespace
{ {
std::string get_key_entropy() std::string get_hdd_serial()
{ {
auto uuid = utils::smbios::get_uuid(); DWORD serial{};
if (uuid.empty()) if (!GetVolumeInformationA("C:\\", nullptr, 0, &serial, nullptr, nullptr, nullptr, 0))
{ {
uuid.resize(16); return {};
utils::cryptography::random::get_data(uuid.data(), uuid.size());
} }
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() utils::cryptography::ecc::key& get_key()

View File

@ -132,6 +132,25 @@ namespace dedicated
com_quit_f_hook.invoke<void>(); 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() void initialize()
@ -171,6 +190,9 @@ namespace dedicated
// Don't allow sv_hostname to be changed by the game // Don't allow sv_hostname to be changed by the game
dvars::disable::Dvar_SetString("sv_hostname"); dvars::disable::Dvar_SetString("sv_hostname");
// Stop crashing from sys_errors
utils::hook::jump(0x1404D6260, sys_error_stub);
// Hook R_SyncGpu // Hook R_SyncGpu
utils::hook::jump(0x1405A7630, sync_gpu_stub); 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, 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 _weapon = get_weapon_name(weapon, isAlternate);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _vDir = convert_vector(state, vDir); for (const auto& callback : player_killed_callbacks)
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>(); const auto state = callback.lua_state();
}
}
if (damage == 0) const auto _self = convert_entity(state, self);
{ const auto _inflictor = convert_entity(state, inflictor);
return; 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); 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, 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 _weapon = get_weapon_name(weapon, isAlternate);
const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker);
const auto _vPoint = convert_vector(state, vPoint); for (const auto& callback : player_damage_callbacks)
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>(); const auto state = callback.lua_state();
}
}
if (damage == 0) const auto _self = convert_entity(state, self);
{ const auto _inflictor = convert_entity(state, inflictor);
return; 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); 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]; auto self = &game::mp::g_entities[clientNum];
char cmd[1024]{}; char cmd[1024]{};
@ -168,10 +172,12 @@ namespace logfile
return reinterpret_cast<void(*)(int)>(0x1402E98F0)(clientNum); 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 // G_ShutdownGame
return reinterpret_cast<void(*)(int)>(0x1402F8C10)(freeScripts); return reinterpret_cast<void(*)(int)>(0x1402F8C10)(freeScripts);

View File

@ -10,6 +10,8 @@ namespace logger
{ {
namespace namespace
{ {
utils::hook::detour com_error_hook;
void print_error(const char* msg, ...) void print_error(const char* msg, ...)
{ {
char buffer[2048]; char buffer[2048];
@ -38,6 +40,24 @@ namespace logger
console::error(buffer); 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, ...) void print_warning(const char* msg, ...)
{ {
char buffer[2048]; char buffer[2048];
@ -145,6 +165,7 @@ namespace logger
sub_1400E7420(); sub_1400E7420();
utils::hook::call(0x1404D8543, print_com_error); 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) 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); return g_shutdown_game_hook.invoke<void>(free_scripts);
} }
} }

View File

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

View File

@ -259,6 +259,19 @@ namespace scripting::lua
{ {
logfile::add_player_killed_callback(callback); 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() context::~context()
{ {
this->state_.collect_garbage(); this->collect_garbage();
this->scheduler_.clear(); this->scheduler_.clear();
this->event_handler_.clear(); this->event_handler_.clear();
this->state_ = {}; this->state_ = {};
@ -310,7 +323,7 @@ namespace scripting::lua
void context::run_frame() void context::run_frame()
{ {
this->scheduler_.run_frame(); this->scheduler_.run_frame();
this->state_.collect_garbage(); this->collect_garbage();
} }
void context::notify(const event& e) void context::notify(const event& e)
@ -318,6 +331,11 @@ namespace scripting::lua
this->event_handler_.dispatch(e); this->event_handler_.dispatch(e);
} }
void context::collect_garbage()
{
this->state_.collect_garbage();
}
void context::load_script(const std::string& script) void context::load_script(const std::string& script)
{ {
if (!this->loaded_scripts_.emplace(script).second) if (!this->loaded_scripts_.emplace(script).second)

View File

@ -30,6 +30,7 @@ namespace scripting::lua
void run_frame(); void run_frame();
void notify(const event& e); void notify(const event& e);
void collect_garbage();
private: private:
sol::state state_{}; 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")) 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() void start()
{ {
// No SP until there is a concept // No SP until there is a concept
@ -46,17 +52,10 @@ namespace scripting::lua::engine
return; return;
} }
clear_custom_fields(); stop();
get_scripts().clear();
load_scripts(); load_scripts();
} }
void stop()
{
logfile::clear_callbacks();
get_scripts().clear();
}
void notify(const event& e) void notify(const event& e)
{ {
for (auto& script : get_scripts()) for (auto& script : get_scripts())

View File

@ -18,19 +18,9 @@ namespace scripting::lua
void event_handler::dispatch(const event& event) 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) callbacks_.access([&](task_list& tasks)
{ {
this->merge_callbacks(); this->merge_callbacks();
@ -45,6 +35,12 @@ namespace scripting::lua
if (!i->is_deleted) 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))); 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> new_callbacks_;
utils::concurrency::container<task_list, std::recursive_mutex> 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 remove(const event_listener_handle& handle);
void merge_callbacks(); void merge_callbacks();
event_arguments build_arguments(const event& event) const;
}; };
} }

View File

@ -44,6 +44,7 @@
#include <urlmon.h> #include <urlmon.h>
#include <atlbase.h> #include <atlbase.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#include <wincrypt.h>
// 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
@ -84,6 +85,7 @@
#include <asmjit/core/jitruntime.h> #include <asmjit/core/jitruntime.h>
#include <asmjit/x86/x86assembler.h> #include <asmjit/x86/x86assembler.h>
#include <google/protobuf/stubs/logging.h>
#include <proto/auth.pb.h> #include <proto/auth.pb.h>
#pragma warning(pop) #pragma warning(pop)
@ -93,6 +95,7 @@
#pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "urlmon.lib" ) #pragma comment(lib, "urlmon.lib" )
#pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "Crypt32.lib")
#include "resource.hpp" #include "resource.hpp"

Binary file not shown.

Binary file not shown.