Merge pull request #288 from diamante0018/userinfo
[Script] Add way to modify player name
This commit is contained in:
commit
9eb6bc0cda
3
deps/premake/json11.lua
vendored
3
deps/premake/json11.lua
vendored
@ -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)
|
||||
table.insert(dependencies, json11)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -140,3 +140,4 @@ namespace Components
|
||||
#include "Modules/RawMouse.hpp"
|
||||
#include "Modules/Bullet.hpp"
|
||||
#include "Modules/Ceg.hpp"
|
||||
#include "Modules/UserInfo.hpp"
|
||||
|
@ -311,10 +311,13 @@ namespace Components
|
||||
* Should be called when a client drops from the server
|
||||
* but not "between levels" (Quake-III-Arena)
|
||||
*/
|
||||
void Bots::ClientDisconnect_Hk(int clientNum)
|
||||
void Bots::ClientDisconnect_Hk(const int clientNum)
|
||||
{
|
||||
g_botai[clientNum].active = false;
|
||||
|
||||
// Clear the overrides for UserInfo
|
||||
UserInfo::ClearClientOverrides(clientNum);
|
||||
|
||||
// Call original function
|
||||
Utils::Hook::Call<void(int)>(0x4AA430)(clientNum);
|
||||
}
|
||||
|
@ -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<std::recursive_mutex> _(ServerList::RefreshContainer.mutex);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
76
src/Components/Modules/UserInfo.cpp
Normal file
76
src/Components/Modules/UserInfo.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include <STDInclude.hpp>
|
||||
|
||||
namespace Components
|
||||
{
|
||||
std::unordered_map<int, UserInfo::userInfoMap> UserInfo::UserInfoOverrides;
|
||||
|
||||
void UserInfo::SV_GetUserInfo_Stub(int index, char* buffer, int bufferSize)
|
||||
{
|
||||
Utils::Hook::Call<void(int, char*, int)>(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(<string>)
|
||||
{
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
21
src/Components/Modules/UserInfo.hpp
Normal file
21
src/Components/Modules/UserInfo.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace Components
|
||||
{
|
||||
class UserInfo : public Component
|
||||
{
|
||||
public:
|
||||
UserInfo();
|
||||
|
||||
static void ClearClientOverrides(int client);
|
||||
static void ClearAllOverrides();
|
||||
|
||||
private:
|
||||
using userInfoMap = std::unordered_map<std::string, std::string>;
|
||||
static std::unordered_map<int, userInfoMap> UserInfoOverrides;
|
||||
|
||||
static void SV_GetUserInfo_Stub(int index, char* buffer, int bufferSize);
|
||||
|
||||
static void AddScriptMethods();
|
||||
};
|
||||
}
|
@ -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<XAssetHeader*>(0x7998A8);
|
||||
unsigned int* g_poolSize = reinterpret_cast<unsigned int*>(0x7995E8);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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};
|
||||
}
|
||||
}
|
||||
|
@ -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<std::string, std::string> keyValuePairs;
|
||||
std::unordered_map<std::string, std::string> keyValuePairs;
|
||||
void parse(std::string buffer);
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user