From 453557b3e274f54e3cfd42e60512451c31592fa7 Mon Sep 17 00:00:00 2001 From: Edo Date: Wed, 3 May 2023 14:34:14 +0100 Subject: [PATCH 1/3] [CHANGELOG]: A user reported this was also missing (#1001) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c232ce76..488aaa7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -336,6 +336,7 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Changed - `sv_mapRotationCurrent` is not being used anymore (#302) +- `sv_mapRotation` is parsed once on startup (#283) ### Security From 8f02f164a0bfe0c6d06d521d49eae5234f7d4478 Mon Sep 17 00:00:00 2001 From: Edo Date: Wed, 3 May 2023 17:31:24 +0100 Subject: [PATCH 2/3] [GSC]: Add field component: (ping field) (#1002) --- src/Components/Modules/Bans.cpp | 4 +- src/Components/Modules/Bans.hpp | 2 +- src/Components/Modules/Bots.cpp | 8 +- src/Components/Modules/Bots.hpp | 2 +- src/Components/Modules/Chat.cpp | 10 +- src/Components/Modules/Chat.hpp | 8 +- src/Components/Modules/ClientCommand.cpp | 6 +- src/Components/Modules/Events.cpp | 4 +- src/Components/Modules/Events.hpp | 4 +- src/Components/Modules/GSC/Field.cpp | 156 ++++++++++++++++++ src/Components/Modules/GSC/Field.hpp | 48 ++++++ src/Components/Modules/GSC/GSC.cpp | 2 + src/Components/Modules/GSC/Script.cpp | 2 +- src/Components/Modules/GSC/Script.hpp | 2 +- .../Modules/GSC/ScriptExtension.cpp | 136 --------------- .../Modules/GSC/ScriptExtension.hpp | 17 -- src/Components/Modules/PlayerName.cpp | 2 +- src/Components/Modules/PlayerName.hpp | 2 +- src/Components/Modules/Security.cpp | 6 +- src/Components/Modules/Security.hpp | 4 +- src/Components/Modules/Voice.cpp | 12 +- src/Components/Modules/Voice.hpp | 8 +- src/Game/Functions.hpp | 2 +- src/Game/Game.cpp | 2 +- src/Game/Game.hpp | 2 +- src/Game/Script.hpp | 2 +- src/Game/Server.cpp | 4 +- src/Game/Server.hpp | 18 +- src/Game/Structs.hpp | 18 +- 29 files changed, 272 insertions(+), 221 deletions(-) create mode 100644 src/Components/Modules/GSC/Field.cpp create mode 100644 src/Components/Modules/GSC/Field.hpp diff --git a/src/Components/Modules/Bans.cpp b/src/Components/Modules/Bans.cpp index f25e5bc6..ae3be8af 100644 --- a/src/Components/Modules/Bans.cpp +++ b/src/Components/Modules/Bans.cpp @@ -186,12 +186,12 @@ namespace Components } } - void Bans::BanClient(Game::client_t* cl, const std::string& reason) + void Bans::BanClient(Game::client_s* cl, const std::string& reason) { SteamID guid; guid.bits = cl->steamID; - InsertBan({guid, cl->header.netchan.remoteAddress.ip}); + InsertBan({ guid, cl->header.netchan.remoteAddress.ip }); Game::SV_DropClient(cl, reason.data(), true); } diff --git a/src/Components/Modules/Bans.hpp b/src/Components/Modules/Bans.hpp index 322a4a12..8545d94b 100644 --- a/src/Components/Modules/Bans.hpp +++ b/src/Components/Modules/Bans.hpp @@ -9,7 +9,7 @@ namespace Components Bans(); - static void BanClient(Game::client_t* cl, const std::string& reason); + static void BanClient(Game::client_s* cl, const std::string& reason); static void UnbanClient(SteamID id); static void UnbanClient(Game::netIP_t ip); diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 1eb60f70..cad90b55 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -274,7 +274,7 @@ namespace Components }); } - void Bots::BotAiAction(Game::client_t* cl) + void Bots::BotAiAction(Game::client_s* cl) { if (!cl->gentity) { @@ -409,9 +409,9 @@ namespace Components Bots::Bots() { - AssertOffset(Game::client_t, bIsTestClient, 0x41AF0); - AssertOffset(Game::client_t, ping, 0x212C8); - AssertOffset(Game::client_t, gentity, 0x212A0); + AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); + AssertOffset(Game::client_s, ping, 0x212C8); + AssertOffset(Game::client_s, gentity, 0x212A0); // Replace connect string Utils::Hook::Set(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\clanAbbrev\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\""); diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index c97b2d26..81a38bb8 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -25,7 +25,7 @@ namespace Components static void GScr_isTestClient(Game::scr_entref_t entref); static void AddScriptMethods(); - static void BotAiAction(Game::client_t* cl); + static void BotAiAction(Game::client_s* cl); static void SV_BotUserMove_Hk(); static void G_SelectWeaponIndex(int clientNum, int iWeaponIndex); diff --git a/src/Components/Modules/Chat.cpp b/src/Components/Modules/Chat.cpp index 4db13e9c..5b7ecf38 100644 --- a/src/Components/Modules/Chat.cpp +++ b/src/Components/Modules/Chat.cpp @@ -29,7 +29,7 @@ namespace Components return lock; } - const char* Chat::EvaluateSay(char* text, Game::gentity_t* player, int mode) + const char* Chat::EvaluateSay(char* text, Game::gentity_s* player, int mode) { SendChat = true; @@ -274,7 +274,7 @@ namespace Components return result; } - bool Chat::IsMuted(const Game::client_t* cl) + bool Chat::IsMuted(const Game::client_s* cl) { const auto clientNum = cl - Game::svs_clients; const auto xuid = Game::svs_clients[clientNum].steamID; @@ -287,7 +287,7 @@ namespace Components return result; } - void Chat::MuteClient(const Game::client_t* client) + void Chat::MuteClient(const Game::client_s* client) { const auto xuid = client->steamID; MutedList.access([&](muteList& clients) @@ -300,7 +300,7 @@ namespace Components Game::SV_GameSendServerCommand(client - Game::svs_clients, Game::SV_CMD_CAN_IGNORE, Utils::String::VA("%c \"You were muted\"", 0x65)); } - void Chat::UnmuteClient(const Game::client_t* client) + void Chat::UnmuteClient(const Game::client_s* client) { UnmuteInternal(client->steamID); @@ -606,7 +606,7 @@ namespace Components Chat::Chat() { - AssertOffset(Game::client_t, steamID, 0x43F00); + AssertOffset(Game::client_s, steamID, 0x43F00); cg_chatWidth = Dvar::Register("cg_chatWidth", 52, 1, std::numeric_limits::max(), Game::DVAR_ARCHIVE, "The normalized maximum width of a chat message"); sv_disableChat = Dvar::Register("sv_disableChat", false, Game::DVAR_NONE, "Disable chat messages from clients"); diff --git a/src/Components/Modules/Chat.hpp b/src/Components/Modules/Chat.hpp index 34cbffea..5a33d118 100644 --- a/src/Components/Modules/Chat.hpp +++ b/src/Components/Modules/Chat.hpp @@ -9,7 +9,7 @@ namespace Components Chat(); static bool IsMuted(const Game::gentity_s* ent); - static bool IsMuted(const Game::client_t* cl); + static bool IsMuted(const Game::client_s* cl); private: static Dvar::Var cg_chatWidth; @@ -27,7 +27,7 @@ namespace Components static std::unique_lock Lock(); - static const char* EvaluateSay(char* text, Game::gentity_t* player, int mode); + static const char* EvaluateSay(char* text, Game::gentity_s* player, int mode); static void PreSayStub(); static void PostSayStub(); @@ -36,8 +36,8 @@ namespace Components static void CG_AddToTeamChat(const char* text); static void CG_AddToTeamChat_Stub(); - static void MuteClient(const Game::client_t* client); - static void UnmuteClient(const Game::client_t* client); + static void MuteClient(const Game::client_s* client); + static void UnmuteClient(const Game::client_s* client); static void UnmuteInternal(std::uint64_t id, bool everyone = false); static void SaveMutedList(const muteList& list); static void LoadMutedList(); diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index a1747309..ab3765a7 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -298,8 +298,7 @@ namespace Components const auto* name = params->get(1); ent->client->visionDuration[visMode] = duration; - strncpy_s(ent->client->visionName[visMode], - sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE); + strncpy_s(ent->client->visionName[visMode], sizeof(Game::gclient_s::visionName[0]) / sizeof(char), name, _TRUNCATE); Game::SV_GameSendServerCommand(ent->s.number, Game::SV_CMD_RELIABLE, VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); }); @@ -325,8 +324,7 @@ namespace Components const auto* name = params->get(1); ent->client->visionDuration[visMode] = duration; - strncpy_s(ent->client->visionName[visMode], - sizeof(Game::gclient_t::visionName[0]) / sizeof(char), name, _TRUNCATE); + strncpy_s(ent->client->visionName[visMode], sizeof(Game::gclient_s::visionName[0]) / sizeof(char), name, _TRUNCATE); Game::SV_GameSendServerCommand(ent->s.number, Game::SV_CMD_RELIABLE, VA("%c \"%s\" %i", Game::MY_CMDS[visMode], name, duration)); }); diff --git a/src/Components/Modules/Events.cpp b/src/Components/Modules/Events.cpp index 0796f4cf..7d69b3a7 100644 --- a/src/Components/Modules/Events.cpp +++ b/src/Components/Modules/Events.cpp @@ -56,11 +56,11 @@ namespace Components Utils::Hook::Call(0x4AA430)(clientNum); // ClientDisconnect } - void Events::SV_UserinfoChanged_Hk(Game::client_t* cl) + void Events::SV_UserinfoChanged_Hk(Game::client_s* cl) { ClientConnectSignal(cl); - Utils::Hook::Call(0x401950)(cl); // SV_UserinfoChanged + Utils::Hook::Call(0x401950)(cl); // SV_UserinfoChanged } void Events::SteamDisconnect_Hk() diff --git a/src/Components/Modules/Events.hpp b/src/Components/Modules/Events.hpp index 8b672fc1..c8d3e6a9 100644 --- a/src/Components/Modules/Events.hpp +++ b/src/Components/Modules/Events.hpp @@ -6,7 +6,7 @@ namespace Components { public: typedef void(ClientCallback)(int clientNum); - typedef void(ClientConnectCallback)(Game::client_t* cl); + typedef void(ClientConnectCallback)(Game::client_s* cl); typedef void(Callback)(); Events(); @@ -40,7 +40,7 @@ namespace Components static Utils::Signal DvarInitSignal; static void ClientDisconnect_Hk(int clientNum); - static void SV_UserinfoChanged_Hk(Game::client_t* cl); + static void SV_UserinfoChanged_Hk(Game::client_s* cl); static void SteamDisconnect_Hk(); static void Scr_ShutdownSystem_Hk(unsigned char sys); static void CL_InitOnceForAllClients_HK(); diff --git a/src/Components/Modules/GSC/Field.cpp b/src/Components/Modules/GSC/Field.cpp new file mode 100644 index 00000000..63893b19 --- /dev/null +++ b/src/Components/Modules/GSC/Field.cpp @@ -0,0 +1,156 @@ +#include +#include "Field.hpp" + +namespace Components::GSC +{ + std::unordered_map Field::CustomEntityFields; + std::unordered_map Field::CustomClientFields; + + void Field::AddEntityField(const char* name, const ScriptCallbackEnt& setter, const ScriptCallbackEnt& getter) + { + static std::uint16_t fieldOffsetStart = 15; // fields count + assert((fieldOffsetStart & Game::ENTFIELD_MASK) == Game::ENTFIELD_ENTITY); + + CustomEntityFields[fieldOffsetStart] = { name, fieldOffsetStart, setter, getter }; + ++fieldOffsetStart; + } + + void Field::AddClientField(const char* name, const ScriptCallbackClient& setter, const ScriptCallbackClient& getter) + { + static std::uint16_t fieldOffsetStart = 21; // fields count + assert((fieldOffsetStart & Game::ENTFIELD_MASK) == Game::ENTFIELD_ENTITY); + + const auto offset = fieldOffsetStart | Game::ENTFIELD_CLIENT; // This is how client field's offset is calculated + + // Use 'index' in 'array' as map key. It will be used later in Scr_SetObjectFieldStub + CustomClientFields[fieldOffsetStart] = { name, offset, setter, getter }; + ++fieldOffsetStart; + } + + void Field::GScr_AddFieldsForEntityStub() + { + for (const auto& field : CustomEntityFields | std::views::values) + { + Game::Scr_AddClassField(Game::ClassNum::CLASS_NUM_ENTITY, field.name, field.ofs); + } + + Utils::Hook::Call(0x4A7CF0)(); // GScr_AddFieldsForClient + + for (const auto& field : CustomClientFields | std::views::values) + { + Game::Scr_AddClassField(Game::ClassNum::CLASS_NUM_ENTITY, field.name, field.ofs); + } + } + + // Because some functions are inlined we have to hook this function instead of Scr_SetEntityField + int Field::Scr_SetObjectFieldStub(const unsigned int classnum, const int entnum, const int offset) + { + if (classnum == Game::ClassNum::CLASS_NUM_ENTITY) + { + const auto entity_offset = static_cast(offset); + if (const auto itr = CustomEntityFields.find(entity_offset); itr != CustomEntityFields.end()) + { + itr->second.setter(&Game::g_entities[entnum], offset); + return 1; + } + } + + // No custom generic field was found, let the game handle it + return Game::Scr_SetObjectField(classnum, entnum, offset); + } + + // Offset was already converted to array 'index' following binop offset & ~Game::ENTFIELD_MASK + void Field::Scr_SetClientFieldStub(Game::gclient_s* client, const int offset) + { + const auto client_offset = static_cast(offset); + if (const auto itr = CustomClientFields.find(client_offset); itr != CustomClientFields.end()) + { + itr->second.setter(nullptr, client, &itr->second); + return; + } + + // No custom field client was found, let the game handle it + Game::Scr_SetClientField(client, offset); + } + + void Field::Scr_GetEntityFieldStub(const int entnum, int offset) + { + if ((offset & Game::ENTFIELD_MASK) == Game::ENTFIELD_CLIENT) + { + // If we have a ENTFIELD_CLIENT offset we need to check g_entity is actually a fully connected client + if (Game::g_entities[entnum].client != nullptr) + { + const auto client_offset = static_cast(offset & ~Game::ENTFIELD_MASK); + if (const auto itr = CustomClientFields.find(client_offset); itr != CustomClientFields.end()) + { + // Game functions probably don't ever need to use the reference to client_fields_s... + itr->second.getter(&Game::svs_clients[entnum], Game::g_entities[entnum].client, &itr->second); + return; + } + } + } + + // Regular entity offsets can be searched directly in our custom handler + const auto entity_offset = static_cast(offset); + + if (const auto itr = CustomEntityFields.find(entity_offset); itr != CustomEntityFields.end()) + { + itr->second.getter(&Game::g_entities[entnum], offset); + return; + } + + // No custom generic field was found, let the game handle it + Game::Scr_GetEntityField(entnum, offset); + } + + + void Field::AddEntityFields() + { + AddEntityField("entityflags", + [](Game::gentity_s* ent, [[maybe_unused]] int offset) + { + ent->flags = Game::Scr_GetInt(0); + }, + [](Game::gentity_s* ent, [[maybe_unused]] int offset) + { + Game::Scr_AddInt(ent->flags); + } + ); + } + + void Field::AddClientFields() + { + AddClientField("clientflags", + []([[maybe_unused]] Game::client_s* client, Game::gclient_s* pSelf, [[maybe_unused]] const ClientFields* pField) + { + pSelf->flags = Game::Scr_GetInt(0); + }, + []([[maybe_unused]] Game::client_s* client, Game::gclient_s* pSelf, [[maybe_unused]] const ClientFields* pField) + { + Game::Scr_AddInt(pSelf->flags); + } + ); + + AddClientField("ping", + []([[maybe_unused]] Game::client_s* client, [[maybe_unused]] Game::gclient_s* pSelf, [[maybe_unused]] const ClientFields* pField) + { + }, + []([[maybe_unused]] Game::client_s* client, [[maybe_unused]] Game::gclient_s* pSelf, [[maybe_unused]] const ClientFields* pField) + { + Game::Scr_AddInt(client->ping); + } + ); + } + + Field::Field() + { + AddEntityFields(); + AddClientFields(); + + Utils::Hook(0x4EC721, GScr_AddFieldsForEntityStub, HOOK_CALL).install()->quick(); // GScr_AddFieldsForEntity + + Utils::Hook(0x41BED2, Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue + Utils::Hook(0x5FBF01, Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField + Utils::Hook(0x4FF413, Scr_GetEntityFieldStub, HOOK_CALL).install()->quick(); // Scr_GetObjectField + } +} diff --git a/src/Components/Modules/GSC/Field.hpp b/src/Components/Modules/GSC/Field.hpp new file mode 100644 index 00000000..6f835811 --- /dev/null +++ b/src/Components/Modules/GSC/Field.hpp @@ -0,0 +1,48 @@ +#pragma once + +namespace Components::GSC +{ + class Field : public Component + { + public: + Field(); + + private: + struct EntField + { + const char* name; + int ofs; + void(*setter)(Game::gentity_s*, int); + void(*getter)(Game::gentity_s*, int); + }; + + struct ClientFields + { + const char* name; + int ofs; + void(*setter)(Game::client_s*, Game::gclient_s*, const ClientFields*); + void(*getter)(Game::client_s*, Game::gclient_s*, const ClientFields*); + }; + + typedef void(*ScriptCallbackEnt)(Game::gentity_s*, int); + typedef void(*ScriptCallbackClient)(Game::client_s*, Game::gclient_s*, const ClientFields*); + + static std::unordered_map CustomEntityFields; + static std::unordered_map CustomClientFields; + + static void AddEntityField(const char* name, const ScriptCallbackEnt& setter, const ScriptCallbackEnt& getter); + static void AddClientField(const char* name, const ScriptCallbackClient& setter, const ScriptCallbackClient& getter); + + static void GScr_AddFieldsForEntityStub(); + + // Two hooks because it makes our code cleaner (luckily functions were not inlined) + static int Scr_SetObjectFieldStub(unsigned int classnum, int entnum, int offset); + static void Scr_SetClientFieldStub(Game::gclient_s* client, int offset); + + // One hook because functions were inlined + static void Scr_GetEntityFieldStub(int entnum, int offset); + + static void AddEntityFields(); + static void AddClientFields(); + }; +} diff --git a/src/Components/Modules/GSC/GSC.cpp b/src/Components/Modules/GSC/GSC.cpp index 46715f33..3fe78e3a 100644 --- a/src/Components/Modules/GSC/GSC.cpp +++ b/src/Components/Modules/GSC/GSC.cpp @@ -1,5 +1,6 @@ #include +#include "Field.hpp" #include "Int64.hpp" #include "IO.hpp" #include "Script.hpp" @@ -14,6 +15,7 @@ namespace Components::GSC { GSC::GSC() { + Loader::Register(new Field()); Loader::Register(new Int64()); Loader::Register(new IO()); Loader::Register(new Script()); diff --git a/src/Components/Modules/GSC/Script.cpp b/src/Components/Modules/GSC/Script.cpp index cb8ea6bb..242f5436 100644 --- a/src/Components/Modules/GSC/Script.cpp +++ b/src/Components/Modules/GSC/Script.cpp @@ -230,7 +230,7 @@ namespace Components::GSC return Game::Scr_GetNumParam(); } - Game::client_t* Script::GetClient(const Game::gentity_t* ent) + Game::client_s* Script::GetClient(const Game::gentity_s* ent) { assert(ent); diff --git a/src/Components/Modules/GSC/Script.hpp b/src/Components/Modules/GSC/Script.hpp index 96f3566a..6cfe112c 100644 --- a/src/Components/Modules/GSC/Script.hpp +++ b/src/Components/Modules/GSC/Script.hpp @@ -14,7 +14,7 @@ namespace Components::GSC static void AddFuncMultiple(Game::BuiltinFunction func, bool type, scriptNames); static void AddMethMultiple(Game::BuiltinMethod func, bool type, scriptNames); - static Game::client_t* GetClient(const Game::gentity_t* gentity); + static Game::client_s* GetClient(const Game::gentity_s* gentity); // Probably a macro 'originally' but this is fine static Game::gentity_s* Scr_GetPlayerEntity(Game::scr_entref_t entref); diff --git a/src/Components/Modules/GSC/ScriptExtension.cpp b/src/Components/Modules/GSC/ScriptExtension.cpp index 9ce1c5c2..f83bdaae 100644 --- a/src/Components/Modules/GSC/ScriptExtension.cpp +++ b/src/Components/Modules/GSC/ScriptExtension.cpp @@ -4,111 +4,9 @@ namespace Components::GSC { - std::unordered_map ScriptExtension::CustomEntityFields; - std::unordered_map ScriptExtension::CustomClientFields; - std::unordered_map ScriptExtension::ReplacedFunctions; const char* ScriptExtension::ReplacedPos = nullptr; - void ScriptExtension::AddEntityField(const char* name, Game::fieldtype_t type, - const Game::ScriptCallbackEnt& setter, const Game::ScriptCallbackEnt& getter) - { - static std::uint16_t fieldOffsetStart = 15; // fields count - assert((fieldOffsetStart & Game::ENTFIELD_MASK) == Game::ENTFIELD_ENTITY); - - CustomEntityFields[fieldOffsetStart] = {name, fieldOffsetStart, type, setter, getter}; - ++fieldOffsetStart; - } - - void ScriptExtension::AddClientField(const char* name, Game::fieldtype_t type, - const Game::ScriptCallbackClient& setter, const Game::ScriptCallbackClient& getter) - { - static std::uint16_t fieldOffsetStart = 21; // fields count - assert((fieldOffsetStart & Game::ENTFIELD_MASK) == Game::ENTFIELD_ENTITY); - - const auto offset = fieldOffsetStart | Game::ENTFIELD_CLIENT; // This is how client field's offset is calculated - - // Use 'index' in 'array' as map key. It will be used later in Scr_SetObjectFieldStub - CustomClientFields[fieldOffsetStart] = {name, offset, type, setter, getter}; - ++fieldOffsetStart; - } - - void ScriptExtension::GScr_AddFieldsForEntityStub() - { - for (const auto& field : CustomEntityFields | std::views::values) - { - Game::Scr_AddClassField(Game::ClassNum::CLASS_NUM_ENTITY, field.name, field.ofs); - } - - Utils::Hook::Call(0x4A7CF0)(); // GScr_AddFieldsForClient - - for (const auto& field : CustomClientFields | std::views::values) - { - Game::Scr_AddClassField(Game::ClassNum::CLASS_NUM_ENTITY, field.name, field.ofs); - } - } - - // Because some functions are inlined we have to hook this function instead of Scr_SetEntityField - int ScriptExtension::Scr_SetObjectFieldStub(unsigned int classnum, int entnum, int offset) - { - if (classnum == Game::ClassNum::CLASS_NUM_ENTITY) - { - const auto entity_offset = static_cast(offset); - if (const auto itr = CustomEntityFields.find(entity_offset); itr != CustomEntityFields.end()) - { - itr->second.setter(&Game::g_entities[entnum], offset); - return 1; - } - } - - // No custom generic field was found, let the game handle it - return Game::Scr_SetObjectField(classnum, entnum, offset); - } - - // Offset was already converted to array 'index' following binop offset & ~Game::ENTFIELD_MASK - void ScriptExtension::Scr_SetClientFieldStub(Game::gclient_s* client, int offset) - { - const auto client_offset = static_cast(offset); - if (const auto itr = CustomClientFields.find(client_offset); itr != CustomClientFields.end()) - { - itr->second.setter(client, &itr->second); - return; - } - - // No custom field client was found, let the game handle it - Game::Scr_SetClientField(client, offset); - } - - void ScriptExtension::Scr_GetEntityFieldStub(int entnum, int offset) - { - if ((offset & Game::ENTFIELD_MASK) == Game::ENTFIELD_CLIENT) - { - // If we have a ENTFIELD_CLIENT offset we need to check g_entity is actually a fully connected client - if (Game::g_entities[entnum].client != nullptr) - { - const auto client_offset = static_cast(offset & ~Game::ENTFIELD_MASK); - if (const auto itr = CustomClientFields.find(client_offset); itr != CustomClientFields.end()) - { - // Game functions probably don't ever need to use the reference to client_fields_s... - itr->second.getter(Game::g_entities[entnum].client, &itr->second); - return; - } - } - } - - // Regular entity offsets can be searched directly in our custom handler - const auto entity_offset = static_cast(offset); - - if (const auto itr = CustomEntityFields.find(entity_offset); itr != CustomEntityFields.end()) - { - itr->second.getter(&Game::g_entities[entnum], offset); - return; - } - - // No custom generic field was found, let the game handle it - Game::Scr_GetEntityField(entnum, offset); - } - const char* ScriptExtension::GetCodePosForParam(int index) { if (static_cast(index) >= Game::scrVmPub->outparamcount) @@ -281,44 +179,10 @@ namespace Components::GSC }); } - void ScriptExtension::AddEntityFields() - { - AddEntityField("entityflags", Game::F_INT, - [](Game::gentity_s* ent, [[maybe_unused]] int offset) - { - ent->flags = Game::Scr_GetInt(0); - }, - [](Game::gentity_s* ent, [[maybe_unused]] int offset) - { - Game::Scr_AddInt(ent->flags); - }); - } - - void ScriptExtension::AddClientFields() - { - AddClientField("clientflags", Game::F_INT, - [](Game::gclient_s* pSelf, [[maybe_unused]] const Game::client_fields_s* pField) - { - pSelf->flags = Game::Scr_GetInt(0); - }, - [](Game::gclient_s* pSelf, [[maybe_unused]] const Game::client_fields_s* pField) - { - Game::Scr_AddInt(pSelf->flags); - }); - } - ScriptExtension::ScriptExtension() { AddFunctions(); AddMethods(); - AddEntityFields(); - AddClientFields(); - - Utils::Hook(0x4EC721, GScr_AddFieldsForEntityStub, HOOK_CALL).install()->quick(); // GScr_AddFieldsForEntity - - Utils::Hook(0x41BED2, Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue - Utils::Hook(0x5FBF01, Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField - Utils::Hook(0x4FF413, Scr_GetEntityFieldStub, HOOK_CALL).install()->quick(); // Scr_GetObjectField Utils::Hook(0x61E92E, VMExecuteInternalStub, HOOK_JUMP).install()->quick(); Utils::Hook::Nop(0x61E933, 1); diff --git a/src/Components/Modules/GSC/ScriptExtension.hpp b/src/Components/Modules/GSC/ScriptExtension.hpp index abd0a273..18fa1ba3 100644 --- a/src/Components/Modules/GSC/ScriptExtension.hpp +++ b/src/Components/Modules/GSC/ScriptExtension.hpp @@ -7,34 +7,17 @@ namespace Components::GSC public: ScriptExtension(); - static void AddEntityField(const char* name, Game::fieldtype_t type, const Game::ScriptCallbackEnt& setter, const Game::ScriptCallbackEnt& getter); - static void AddClientField(const char* name, Game::fieldtype_t type, const Game::ScriptCallbackClient& setter, const Game::ScriptCallbackClient& getter); - static const char* GetCodePosForParam(int index); private: - static std::unordered_map CustomEntityFields; - static std::unordered_map CustomClientFields; - static std::unordered_map ReplacedFunctions; static const char* ReplacedPos; - static void GScr_AddFieldsForEntityStub(); - - // Two hooks because it makes our code cleaner (luckily functions were not inlined) - static int Scr_SetObjectFieldStub(unsigned int classnum, int entnum, int offset); - static void Scr_SetClientFieldStub(Game::gclient_s* client, int offset); - - // One hook because functions were inlined - static void Scr_GetEntityFieldStub(int entnum, int offset); - static void GetReplacedPos(const char* pos); static void SetReplacedPos(const char* what, const char* with); static void VMExecuteInternalStub(); static void AddFunctions(); static void AddMethods(); - static void AddEntityFields(); - static void AddClientFields(); }; } diff --git a/src/Components/Modules/PlayerName.cpp b/src/Components/Modules/PlayerName.cpp index 826b97d5..aa08f2bf 100644 --- a/src/Components/Modules/PlayerName.cpp +++ b/src/Components/Modules/PlayerName.cpp @@ -104,7 +104,7 @@ namespace Components return true; } - void PlayerName::DropClient(Game::client_t* drop) + void PlayerName::DropClient(Game::client_s* drop) { const auto* reason = "Invalid name detected"; Network::SendCommand(drop->header.netchan.remoteAddress, "error", reason); diff --git a/src/Components/Modules/PlayerName.hpp b/src/Components/Modules/PlayerName.hpp index e88c3e99..03112362 100644 --- a/src/Components/Modules/PlayerName.hpp +++ b/src/Components/Modules/PlayerName.hpp @@ -19,7 +19,7 @@ namespace Components static bool IsBadChar(int c); static bool CopyClientNameCheck(char* dest, const char* source, int size); - static void DropClient(Game::client_t* drop); + static void DropClient(Game::client_s* drop); static void SV_UserinfoChangedStub(); }; } diff --git a/src/Components/Modules/Security.cpp b/src/Components/Modules/Security.cpp index eda2a36b..974849bb 100644 --- a/src/Components/Modules/Security.cpp +++ b/src/Components/Modules/Security.cpp @@ -29,7 +29,7 @@ namespace Components return size; } - int Security::SV_CanReplaceServerCommand_Hk([[maybe_unused]] Game::client_t* client, [[maybe_unused]] const char* cmd) + int Security::SV_CanReplaceServerCommand_Hk([[maybe_unused]] Game::client_s* client, [[maybe_unused]] const char* cmd) { // This is a fix copied from V2. As I don't have time to investigate, let's simply trust them return -1; @@ -121,7 +121,7 @@ namespace Components InterlockedIncrement(&Game::deferredQueue->send); } - void Security::SV_ExecuteClientMessage_Stub(Game::client_t* client, Game::msg_t* msg) + void Security::SV_ExecuteClientMessage_Stub(Game::client_s* client, Game::msg_t* msg) { if ((client->reliableSequence - client->reliableAcknowledge) < 0) { @@ -132,7 +132,7 @@ namespace Components return; } - Utils::Hook::Call(0x414D40)(client, msg); + Utils::Hook::Call(0x414D40)(client, msg); } Security::Security() diff --git a/src/Components/Modules/Security.hpp b/src/Components/Modules/Security.hpp index d70d8537..1dcb5227 100644 --- a/src/Components/Modules/Security.hpp +++ b/src/Components/Modules/Security.hpp @@ -11,7 +11,7 @@ namespace Components static int Msg_ReadBitsCompressCheckCL(const unsigned char* from, unsigned char* to, int size); private: - static int SV_CanReplaceServerCommand_Hk(Game::client_t* client, const char* cmd); + static int SV_CanReplaceServerCommand_Hk(Game::client_s* client, const char* cmd); static long AtolAdjustPlayerLimit(const char* string); @@ -23,6 +23,6 @@ namespace Components static void NET_DeferPacketToClient_Hk(Game::netadr_t* net_from, Game::msg_t* net_message); - static void SV_ExecuteClientMessage_Stub(Game::client_t* client, Game::msg_t* msg); + static void SV_ExecuteClientMessage_Stub(Game::client_s* client, Game::msg_t* msg); }; } diff --git a/src/Components/Modules/Voice.cpp b/src/Components/Modules/Voice.cpp index ea28d5d7..b578e9f3 100644 --- a/src/Components/Modules/Voice.cpp +++ b/src/Components/Modules/Voice.cpp @@ -36,7 +36,7 @@ namespace Components assert(!msg->overflowed); } - void Voice::SV_SendClientVoiceData(Game::client_t* client) + void Voice::SV_SendClientVoiceData(Game::client_s* client) { Game::msg_t msg{}; const auto clientNum = client - Game::svs_clients; @@ -68,10 +68,10 @@ namespace Components } } - void Voice::SV_SendClientMessages_Stub(Game::client_t* client, Game::msg_t* msg, unsigned char* snapshotMsgBuf) + void Voice::SV_SendClientMessages_Stub(Game::client_s* client, Game::msg_t* msg, unsigned char* snapshotMsgBuf) { // SV_EndClientSnapshot - Utils::Hook::Call(0x4F5300)(client, msg, snapshotMsgBuf); + Utils::Hook::Call(0x4F5300)(client, msg, snapshotMsgBuf); SV_SendClientVoiceData(client); } @@ -148,7 +148,7 @@ namespace Components } } - void Voice::SV_UserVoice(Game::client_t* cl, Game::msg_t* msg) + void Voice::SV_UserVoice(Game::client_s* cl, Game::msg_t* msg) { Game::VoicePacket_t voicePacket{}; @@ -179,7 +179,7 @@ namespace Components } } - void Voice::SV_PreGameUserVoice(Game::client_t* cl, Game::msg_t* msg) + void Voice::SV_PreGameUserVoice(Game::client_s* cl, Game::msg_t* msg) { Game::VoicePacket_t voicePacket{}; @@ -390,7 +390,7 @@ namespace Components Events::OnSteamDisconnect(CL_ClearMutedList); Events::OnClientDisconnect(SV_UnmuteClient); - Events::OnClientConnect([](Game::client_t* cl) -> void + Events::OnClientConnect([](Game::client_s* cl) -> void { if (Chat::IsMuted(cl)) { diff --git a/src/Components/Modules/Voice.hpp b/src/Components/Modules/Voice.hpp index bc5a2bc5..fa37de00 100644 --- a/src/Components/Modules/Voice.hpp +++ b/src/Components/Modules/Voice.hpp @@ -26,16 +26,16 @@ namespace Components static const Game::dvar_t* sv_voice; static void SV_WriteVoiceDataToClient(int clientNum, Game::msg_t* msg); - static void SV_SendClientVoiceData(Game::client_t* client); - static void SV_SendClientMessages_Stub(Game::client_t* client, Game::msg_t* msg, unsigned char* snapshotMsgBuf); + static void SV_SendClientVoiceData(Game::client_s* client); + static void SV_SendClientMessages_Stub(Game::client_s* client, Game::msg_t* msg, unsigned char* snapshotMsgBuf); static bool SV_ServerHasClientMuted(int talker); static bool OnSameTeam(const Game::gentity_s* ent1, const Game::gentity_s* ent2); static void SV_QueueVoicePacket(int talkerNum, int clientNum, const Game::VoicePacket_t* voicePacket); static void G_BroadcastVoice(Game::gentity_s* talker, const Game::VoicePacket_t* voicePacket); - static void SV_UserVoice(Game::client_t* cl, Game::msg_t* msg); - static void SV_PreGameUserVoice(Game::client_t* cl, Game::msg_t* msg); + static void SV_UserVoice(Game::client_s* cl, Game::msg_t* msg); + static void SV_PreGameUserVoice(Game::client_s* cl, Game::msg_t* msg); static void SV_VoicePacket(Game::netadr_t from, Game::msg_t* msg); static void CL_ClearMutedList(); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 832d36de..a34bea03 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -419,7 +419,7 @@ namespace Game typedef void(*Steam_JoinLobby_t)(SteamID, char); extern Steam_JoinLobby_t Steam_JoinLobby; - typedef void(*TeleportPlayer_t)(gentity_t* entity, float* pos, float* orientation); + typedef void(*TeleportPlayer_t)(gentity_s* entity, float* pos, float* orientation); extern TeleportPlayer_t TeleportPlayer; typedef void(*UI_AddMenuList_t)(UiContext* dc, MenuList* menuList, int close); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 750c2ccf..7e0ad53b 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -16,7 +16,7 @@ namespace Game G_DebugLineWithDuration_t G_DebugLineWithDuration = G_DebugLineWithDuration_t(0x4C3280); - gentity_t* g_entities = reinterpret_cast(0x18835D8); + gentity_s* g_entities = reinterpret_cast(0x18835D8); const char* origErrorMsg = reinterpret_cast(0x79B124); diff --git a/src/Game/Game.hpp b/src/Game/Game.hpp index 6974a034..b51e2538 100644 --- a/src/Game/Game.hpp +++ b/src/Game/Game.hpp @@ -51,7 +51,7 @@ namespace Game constexpr std::size_t MAX_GENTITIES = 2048; constexpr std::size_t ENTITYNUM_NONE = MAX_GENTITIES - 1; - extern gentity_t* g_entities; + extern gentity_s* g_entities; extern const char* origErrorMsg; diff --git a/src/Game/Script.hpp b/src/Game/Script.hpp index ae3e633e..14ebbbb5 100644 --- a/src/Game/Script.hpp +++ b/src/Game/Script.hpp @@ -125,7 +125,7 @@ namespace Game typedef void(*Scr_FreeThread_t)(unsigned __int16 handle); extern Scr_FreeThread_t Scr_FreeThread; - typedef void(*Scr_Notify_t)(gentity_t* ent, unsigned __int16 stringValue, unsigned int paramcount); + typedef void(*Scr_Notify_t)(gentity_s* ent, unsigned __int16 stringValue, unsigned int paramcount); extern Scr_Notify_t Scr_Notify; typedef void(*Scr_NotifyLevel_t)(unsigned __int16 stringValue, unsigned int paramcount); diff --git a/src/Game/Server.cpp b/src/Game/Server.cpp index 448b5c00..1860e2f7 100644 --- a/src/Game/Server.cpp +++ b/src/Game/Server.cpp @@ -27,7 +27,7 @@ namespace Game int* sv_timeResidual = reinterpret_cast(0x2089E14); int* sv_serverId_value = reinterpret_cast(0x2089DC0); int* svs_clientCount = reinterpret_cast(0x31D938C); - client_t* svs_clients = reinterpret_cast(0x31D9390); + client_s* svs_clients = reinterpret_cast(0x31D9390); unsigned short* sv_sconfigstrings = reinterpret_cast(0x208A632); unsigned short* sv_emptyConfigString = reinterpret_cast(0x208A630); @@ -115,7 +115,7 @@ namespace Game SV_SendServerCommand(&svs_clients[clientNum], SV_CMD_RELIABLE, "%c %i %i", 'M', index, value); } - void SV_BotUserMove(client_t* client) + void SV_BotUserMove(client_s* client) { static DWORD SV_BotUserMove_t = 0x626E50; diff --git a/src/Game/Server.hpp b/src/Game/Server.hpp index b507c417..5d9c8694 100644 --- a/src/Game/Server.hpp +++ b/src/Game/Server.hpp @@ -2,7 +2,7 @@ namespace Game { - typedef gentity_t*(*SV_AddTestClient_t)(); + typedef gentity_s*(*SV_AddTestClient_t)(); extern SV_AddTestClient_t SV_AddTestClient; typedef int(*SV_IsTestClient_t)(int clientNum); @@ -14,7 +14,7 @@ namespace Game typedef void(*SV_GameSendServerCommand_t)(int clientNum, svscmd_type type, const char* text); extern SV_GameSendServerCommand_t SV_GameSendServerCommand; - typedef void(*SV_SendServerCommand_t)(client_t* cl, svscmd_type type, const char* fmt, ...); + typedef void(*SV_SendServerCommand_t)(client_s* cl, svscmd_type type, const char* fmt, ...); extern SV_SendServerCommand_t SV_SendServerCommand; typedef void(*SV_Cmd_TokenizeString_t)(const char* string); @@ -38,19 +38,19 @@ namespace Game typedef bool(*SV_Loaded_t)(); extern SV_Loaded_t SV_Loaded; - typedef void(*SV_ClientThink_t)(client_t* cl, usercmd_s* cmd); + typedef void(*SV_ClientThink_t)(client_s* cl, usercmd_s* cmd); extern SV_ClientThink_t SV_ClientThink; - typedef void(*SV_DropClient_t)(client_t* drop, const char* reason, bool tellThem); + typedef void(*SV_DropClient_t)(client_s* drop, const char* reason, bool tellThem); extern SV_DropClient_t SV_DropClient; - typedef client_t*(*SV_GetPlayerByName_t)(); + typedef client_s*(*SV_GetPlayerByName_t)(); extern SV_GetPlayerByName_t SV_GetPlayerByName; - typedef client_t*(*SV_GetPlayerByNum_t)(); + typedef client_s*(*SV_GetPlayerByNum_t)(); extern SV_GetPlayerByNum_t SV_GetPlayerByNum; - typedef client_t*(*SV_FindClientByAddress_t)(netadr_t from, int qport, int remoteClientIndex); + typedef client_s*(*SV_FindClientByAddress_t)(netadr_t from, int qport, int remoteClientIndex); extern SV_FindClientByAddress_t SV_FindClientByAddress; typedef void(*SV_WaitServer_t)(); @@ -68,7 +68,7 @@ namespace Game extern int* sv_timeResidual; extern int* sv_serverId_value; extern int* svs_clientCount; - extern client_t* svs_clients; + extern client_s* svs_clients; extern unsigned short* sv_sconfigstrings; extern unsigned short* sv_emptyConfigString; @@ -80,5 +80,5 @@ namespace Game extern void SV_DropAllBots(); extern int SV_GetClientStat(int clientNum, int index); extern void SV_SetClientStat(int clientNum, int index, int value); - extern void SV_BotUserMove(client_t* client); + extern void SV_BotUserMove(client_s* client); } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index d252e9ce..1b33367a 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -7226,7 +7226,7 @@ namespace Game float spectateDefaultAngles[3]; }; - typedef struct gclient_s + struct gclient_s { playerState_s ps; clientSession_t sess; @@ -7247,9 +7247,9 @@ namespace Game unsigned __int16 attachShieldTagName; hintType_t hintForcedType; int hintForcedString; - } gclient_t; + }; - static_assert(sizeof(gclient_t) == 13932); + static_assert(sizeof(gclient_s) == 0x366C); struct EntHandle { @@ -7300,11 +7300,11 @@ namespace Game ENT_HANDLER_COUNT }; - typedef struct gentity_s + struct gentity_s { entityState_s s; entityShared_t r; - gclient_t* client; // 344 + gclient_s* client; // 344 void /*Turret*/* turret; void /*Vehicle*/* vehicle; int physObjId; @@ -7342,7 +7342,7 @@ namespace Game gentity_s* nextFree; int birthTime; char pad[100]; - } gentity_t; + }; static_assert(sizeof(gentity_s) == 0x274); @@ -7439,7 +7439,7 @@ namespace Game int baselineSnap; }; - struct client_t + struct client_s { clientHeader_t header; const char* dropReason; // 1624 @@ -7454,7 +7454,7 @@ namespace Game usercmd_s lastUsercmd; // 134772 int lastClientCommand; // 134812 char lastClientCommandString[1024]; // 134816 - gentity_t* gentity; // 135840 + gentity_s* gentity; // 135840 char name[16]; // 135844 int nextReliableTime; // 135860 int lastPacketTime; // 135864 @@ -7493,7 +7493,7 @@ namespace Game clientSnapshot_t frames[32]; }; - static_assert(sizeof(client_t) == 0xA6790); + static_assert(sizeof(client_s) == 0xA6790); enum CompassType { From a46a271dfd77ec3d7c6249564b24f8b718fbee54 Mon Sep 17 00:00:00 2001 From: Edo Date: Wed, 3 May 2023 18:03:46 +0100 Subject: [PATCH 3/3] [Field]: Add address field (#1003) --- CHANGELOG.md | 18 +++++++++++++++++- src/Components/Modules/GSC/Field.cpp | 10 ++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 488aaa7a..aecace85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0.3.0/). +## r4251 - 2023-05-03 + +### Added + +- Add GSC client field `ping` as a read-only field (#1002) +- Add GSC client field `address` as a read-only field (#1003) +- Add to the iw4x-rawfiles common_scripts\utility GSC script `getIP` function. + +### Fixed + +- `getPing` function in `common_scripts\utility` now works. + +### Known issues + +- Sound issue fix is experimental as the bug is not fully understood. + ## r4246 - 2023-05-03 ### Added -- Add to the iw4x-rawfiles common_scripts\utility GSC script `setPing` & `getPing` for backward compatibility. +- Add to the iw4x-rawfiles `common_scripts\utility` GSC script `setPing` & `getPing` functions for backward compatibility. ### Fixed diff --git a/src/Components/Modules/GSC/Field.cpp b/src/Components/Modules/GSC/Field.cpp index 63893b19..b11270e3 100644 --- a/src/Components/Modules/GSC/Field.cpp +++ b/src/Components/Modules/GSC/Field.cpp @@ -140,6 +140,16 @@ namespace Components::GSC Game::Scr_AddInt(client->ping); } ); + + AddClientField("address", + []([[maybe_unused]] Game::client_s* client, [[maybe_unused]] Game::gclient_s* pSelf, [[maybe_unused]] const ClientFields* pField) + { + }, + []([[maybe_unused]] Game::client_s* client, [[maybe_unused]] Game::gclient_s* pSelf, [[maybe_unused]] const ClientFields* pField) + { + Game::Scr_AddString(Game::NET_AdrToString(client->header.netchan.remoteAddress)); + } + ); } Field::Field()