From 854949a34f08e0fb177ce5d0f7a1d2abc8e434ae Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sat, 4 Jun 2022 10:56:14 +0200 Subject: [PATCH] [Script] Add way to modify player name --- deps/premake/json11.lua | 3 +- src/Components/Loader.cpp | 1 + src/Components/Loader.hpp | 1 + src/Components/Modules/ServerList.cpp | 2 +- src/Components/Modules/ServerList.hpp | 2 +- src/Components/Modules/UserInfo.cpp | 76 +++++++++++++++++++++++++++ src/Components/Modules/UserInfo.hpp | 21 ++++++++ src/Game/Functions.cpp | 2 + src/Game/Functions.hpp | 3 ++ src/Utils/InfoString.cpp | 32 +++++++---- src/Utils/InfoString.hpp | 16 +++--- 11 files changed, 140 insertions(+), 19 deletions(-) create mode 100644 src/Components/Modules/UserInfo.cpp create mode 100644 src/Components/Modules/UserInfo.hpp diff --git a/deps/premake/json11.lua b/deps/premake/json11.lua index 3437ba57..60ea05d7 100644 --- a/deps/premake/json11.lua +++ b/deps/premake/json11.lua @@ -15,6 +15,7 @@ end function json11.project() project "json11" language "C++" + cppdialect "C++11" files { @@ -29,4 +30,4 @@ function json11.project() kind "StaticLib" end -table.insert(dependencies, json11) \ No newline at end of file +table.insert(dependencies, json11) diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index a6712c0d..bcb98bfc 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -109,6 +109,7 @@ namespace Components Loader::Register(new RawMouse()); Loader::Register(new Bullet()); Loader::Register(new Ceg()); + Loader::Register(new UserInfo()); Loader::Pregame = false; } diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index dabec0e8..c5a0ea31 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -140,3 +140,4 @@ namespace Components #include "Modules/RawMouse.hpp" #include "Modules/Bullet.hpp" #include "Modules/Ceg.hpp" +#include "Modules/UserInfo.hpp" diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index 5bffcf9e..edecba4d 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -451,7 +451,7 @@ namespace Components } } - void ServerList::Insert(Network::Address address, Utils::InfoString info) + void ServerList::Insert(const Network::Address& address, const Utils::InfoString& info) { std::lock_guard _(ServerList::RefreshContainer.mutex); diff --git a/src/Components/Modules/ServerList.hpp b/src/Components/Modules/ServerList.hpp index 51f7a062..13d99ef6 100644 --- a/src/Components/Modules/ServerList.hpp +++ b/src/Components/Modules/ServerList.hpp @@ -38,7 +38,7 @@ namespace Components static void RefreshVisibleListInternal(UIScript::Token, bool refresh = false); static void UpdateVisibleList(UIScript::Token); static void InsertRequest(Network::Address address); - static void Insert(Network::Address address, Utils::InfoString info); + static void Insert(const Network::Address& address, const Utils::InfoString& info); static ServerInfo* GetCurrentServer(); diff --git a/src/Components/Modules/UserInfo.cpp b/src/Components/Modules/UserInfo.cpp new file mode 100644 index 00000000..8670c486 --- /dev/null +++ b/src/Components/Modules/UserInfo.cpp @@ -0,0 +1,76 @@ +#include + +namespace Components +{ + std::unordered_map UserInfo::UserInfoOverrides; + + void UserInfo::SV_GetUserInfo_Stub(int index, char* buffer, int bufferSize) + { + Utils::Hook::Call(0x49A160)(index, buffer, bufferSize); + + Utils::InfoString map(buffer); + + if (!UserInfoOverrides.contains(index)) + { + UserInfoOverrides[index] = {}; + } + + for (const auto& [key, val] : UserInfoOverrides[index]) + { + if (val.empty()) + { + map.remove(key); + } + else + { + map.set(key, val); + } + } + + const auto userInfo = map.build(); + strncpy_s(buffer, bufferSize, userInfo.data(), _TRUNCATE); + } + + void UserInfo::ClearClientOverrides(const int client) + { + UserInfoOverrides[client].clear(); + } + + void UserInfo::ClearAllOverrides() + { + UserInfoOverrides.clear(); + } + + void UserInfo::AddScriptMethods() + { + Script::AddMethod("SetName", [](Game::scr_entref_t entref) // gsc: self SetName() + { + const auto* ent = Game::GetPlayerEntity(entref); + const auto* name = Game::Scr_GetString(0); + + UserInfoOverrides[ent->s.number]["name"] = name; + Game::ClientUserinfoChanged(ent->s.number); + }); + + Script::AddMethod("ResetName", [](Game::scr_entref_t entref) // gsc: self ResetName() + { + const auto* ent = Game::GetPlayerEntity(entref); + + UserInfoOverrides[ent->s.number].erase("name"); + Game::ClientUserinfoChanged(ent->s.number); + }); + } + + UserInfo::UserInfo() + { + Utils::Hook(0x445268, SV_GetUserInfo_Stub, HOOK_CALL).install()->quick(); + Utils::Hook(0x478B04, SV_GetUserInfo_Stub, HOOK_CALL).install()->quick(); + + AddScriptMethods(); + + Script::OnVMShutdown([] + { + ClearAllOverrides(); + }); + } +} diff --git a/src/Components/Modules/UserInfo.hpp b/src/Components/Modules/UserInfo.hpp new file mode 100644 index 00000000..cdf3cfd2 --- /dev/null +++ b/src/Components/Modules/UserInfo.hpp @@ -0,0 +1,21 @@ +#pragma once + +namespace Components +{ + class UserInfo : public Component + { + public: + UserInfo(); + + private: + using userInfoMap = std::unordered_map; + static std::unordered_map UserInfoOverrides; + + static void SV_GetUserInfo_Stub(int index, char* buffer, int bufferSize); + + static void ClearClientOverrides(int client); + static void ClearAllOverrides(); + + static void AddScriptMethods(); + }; +} diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 38dc86e1..165ee569 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -431,6 +431,8 @@ namespace Game IN_Init_t IN_Init = IN_Init_t(0x45D620); IN_Shutdown_t IN_Shutdown = IN_Shutdown_t(0x426360); + ClientUserinfoChanged_t ClientUserinfoChanged = ClientUserinfoChanged_t(0x445240); + XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); unsigned int* g_poolSize = reinterpret_cast(0x7995E8); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 672a6cc0..080dad39 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -1029,6 +1029,9 @@ namespace Game typedef void(__cdecl * IN_Shutdown_t)(); extern IN_Shutdown_t IN_Shutdown; + typedef void(__cdecl * ClientUserinfoChanged_t)(int clientNum); + extern ClientUserinfoChanged_t ClientUserinfoChanged; + extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; diff --git a/src/Utils/InfoString.cpp b/src/Utils/InfoString.cpp index 8faa26fa..98a81bc6 100644 --- a/src/Utils/InfoString.cpp +++ b/src/Utils/InfoString.cpp @@ -2,12 +2,22 @@ namespace Utils { + InfoString::InfoString(const std::string& buffer) + { + this->parse(buffer); + } + void InfoString::set(const std::string& key, const std::string& value) { this->keyValuePairs[key] = value; } - std::string InfoString::get(const std::string& key) + void InfoString::remove(const std::string& key) + { + this->keyValuePairs.erase(key); + } + + std::string InfoString::get(const std::string& key) const { const auto value = this->keyValuePairs.find(key); if (value != this->keyValuePairs.end()) @@ -15,7 +25,7 @@ namespace Utils return value->second; } - return ""; + return {}; } void InfoString::parse(std::string buffer) @@ -25,17 +35,17 @@ namespace Utils buffer = buffer.substr(1); } - auto KeyValues = Utils::String::Split(buffer, '\\'); + const auto keyValues = Utils::String::Split(buffer, '\\'); - for (size_t i = 0; !KeyValues.empty() && i < (KeyValues.size() - 1); i += 2) + for (std::size_t i = 0; !keyValues.empty() && i < (keyValues.size() - 1); i += 2) { - const auto& key = KeyValues[i]; - const auto& value = KeyValues[i + 1]; + const auto& key = keyValues[i]; + const auto& value = keyValues[i + 1]; this->keyValuePairs[key] = value; } } - std::string InfoString::build() + std::string InfoString::build() const { std::string infoString; @@ -54,16 +64,18 @@ namespace Utils return infoString; } +#ifdef _DEBUG void InfoString::dump() { for (const auto& [key, value] : this->keyValuePairs) { - OutputDebugStringA(Utils::String::VA("%s: %s\n", key.data(), value.data())); + OutputDebugStringA(String::VA("%s: %s\n", key.data(), value.data())); } } +#endif - json11::Json InfoString::to_json() + json11::Json InfoString::to_json() const { - return this->keyValuePairs; + return {this->keyValuePairs}; } } diff --git a/src/Utils/InfoString.hpp b/src/Utils/InfoString.hpp index f63c6714..11f48599 100644 --- a/src/Utils/InfoString.hpp +++ b/src/Utils/InfoString.hpp @@ -5,19 +5,23 @@ namespace Utils class InfoString { public: - InfoString() {}; - InfoString(const std::string& buffer) : InfoString() { this->parse(buffer); }; + InfoString() = default; + explicit InfoString(const std::string& buffer); void set(const std::string& key, const std::string& value); - std::string get(const std::string& key); - std::string build(); + void remove(const std::string& key); + [[nodiscard]] std::string get(const std::string& key) const; + [[nodiscard]] std::string build() const; + +#ifdef _DEBUG void dump(); +#endif - json11::Json to_json(); + [[nodiscard]] json11::Json to_json() const; private: - std::map keyValuePairs; + std::unordered_map keyValuePairs; void parse(std::string buffer); }; }