diff --git a/.gitmodules b/.gitmodules index 07d163da..dd66b2bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,7 +25,7 @@ [submodule "deps/protobuf"] path = deps/protobuf url = https://github.com/google/protobuf.git - branch = 3.11.x + branch = 3.17.x [submodule "deps/udis86"] path = deps/udis86 url = https://github.com/vmt/udis86.git diff --git a/deps/protobuf b/deps/protobuf index df2bce34..5500c72c 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit df2bce345d4bc8cdc3eba2a866e11e79e1fff4df +Subproject commit 5500c72c5b616da9f0125bcfab513987a1226e2b diff --git a/src/Components/Modules/Chat.cpp b/src/Components/Modules/Chat.cpp index 5c849c3b..5e14a433 100644 --- a/src/Components/Modules/Chat.cpp +++ b/src/Components/Modules/Chat.cpp @@ -8,17 +8,35 @@ namespace Components bool Chat::SendChat; + std::mutex Chat::AccessMutex; + std::unordered_set Chat::MuteList; + const char* Chat::EvaluateSay(char* text, Game::gentity_t* player) { - SendChat = true; + Chat::SendChat = true; if (text[1] == '/') { - SendChat = false; + Chat::SendChat = false; text[1] = text[0]; ++text; } + std::unique_lock lock(Chat::AccessMutex); + if (Chat::MuteList.find(Game::svs_clients[player->s.number].steamID) != Chat::MuteList.end()) + { + lock.unlock(); + Chat::SendChat = false; + Game::SV_GameSendServerCommand(player->s.number, 0, + Utils::String::VA("%c \"You are muted\"", 0x65)); + } + + // Test whether the lock is still locked + if (lock.owns_lock()) + { + lock.unlock(); + } + TextRenderer::StripMaterialTextIcons(text, text, strlen(text) + 1); Game::Scr_AddEntity(player); @@ -194,9 +212,113 @@ namespace Components } } + void Chat::MuteClient(const Game::client_t* client) + { + std::unique_lock lock(Chat::AccessMutex); + + if (Chat::MuteList.find(client->steamID) == Chat::MuteList.end()) + { + Chat::MuteList.insert(client->steamID); + lock.unlock(); + + Logger::Print("%s was muted\n", client->name); + Game::SV_GameSendServerCommand(client->gentity->s.number, 0, + Utils::String::VA("%c \"You were muted\"", 0x65)); + return; + } + + lock.unlock(); + Logger::Print("%s is already muted\n", client->name); + Game::SV_GameSendServerCommand(-1, 0, + Utils::String::VA("%c \"%s is already muted\"", 0x65, client->name)); + } + + void Chat::UnmuteClient(const Game::client_t* client) + { + Chat::UnmuteInternal(client->steamID); + + Logger::Print("%s was unmuted\n", client->name); + Game::SV_GameSendServerCommand(client->gentity->s.number, 0, + Utils::String::VA("%c \"You were unmuted\"", 0x65)); + } + + void Chat::UnmuteInternal(const std::uint64_t id, bool everyone) + { + std::unique_lock lock(Chat::AccessMutex); + + if (everyone) + Chat::MuteList.clear(); + else + Chat::MuteList.erase(id); + } + + void Chat::AddChatCommands() + { + Command::AddSV("muteClient", [](Command::Params* params) + { + if (!Dvar::Var("sv_running").get()) + { + Logger::Print("Server is not running.\n"); + return; + } + + const auto* cmd = params->get(0); + if (params->length() < 2) + { + Logger::Print("Usage: %s : prevent the player from using the chat\n", cmd); + return; + } + + const auto* client = Game::SV_GetPlayerByNum(); + if (client != nullptr) + { + Chat::MuteClient(client); + } + }); + + Command::AddSV("unmute", [](Command::Params* params) + { + if (!Dvar::Var("sv_running").get()) + { + Logger::Print("Server is not running.\n"); + return; + } + + const auto* cmd = params->get(0); + if (params->length() < 2) + { + Logger::Print("Usage: %s \n%s all = unmute everyone\n", cmd, cmd); + return; + } + + const auto* client = Game::SV_GetPlayerByNum(); + + if (client != nullptr) + { + Chat::UnmuteClient(client); + return; + } + + if (params->get(1) == "all"s) + { + Logger::Print("All players were unmuted\n"); + Chat::UnmuteInternal(0, true); + } + else + { + const auto steamId = std::strtoull(params->get(1), nullptr, 16); + Chat::UnmuteInternal(steamId); + } + }); + } + Chat::Chat() { - cg_chatWidth = Dvar::Register("cg_chatWidth", 52, 1, INT_MAX, Game::DVAR_FLAG_SAVED, "The normalized maximum width of a chat message"); + Dvar::OnInit([] + { + cg_chatWidth = Dvar::Register("cg_chatWidth", 52, 1, std::numeric_limits::max(), Game::DVAR_FLAG_SAVED, "The normalized maximum width of a chat message"); + Chat::AddChatCommands(); + }); // Intercept chat sending Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick(); @@ -206,4 +328,9 @@ namespace Components // Change logic that does word splitting with new lines for chat messages to support fonticons Utils::Hook(0x592E10, CG_AddToTeamChat_Stub, HOOK_JUMP).install()->quick(); } + + Chat::~Chat() + { + Chat::MuteList.clear(); + } } diff --git a/src/Components/Modules/Chat.hpp b/src/Components/Modules/Chat.hpp index 9cf35e9c..62bc36aa 100644 --- a/src/Components/Modules/Chat.hpp +++ b/src/Components/Modules/Chat.hpp @@ -7,6 +7,7 @@ namespace Components static constexpr auto FONT_ICON_CHAT_WIDTH_CALCULATION_MULTIPLIER = 2.0f; public: Chat(); + ~Chat(); private: static Game::dvar_t** cg_chatHeight; @@ -15,6 +16,9 @@ namespace Components static bool SendChat; + static std::mutex AccessMutex; + static std::unordered_set MuteList; + static const char* EvaluateSay(char* text, Game::gentity_t* player); static void PreSayStub(); @@ -23,5 +27,10 @@ namespace Components static void CheckChatLineEnd(const char*& inputBuffer, char*& lineBuffer, float& len, int chatHeight, float chatWidth, char*& lastSpacePos, char*& lastFontIconPos, int lastColor); 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 UnmuteInternal(const std::uint64_t id, bool everyone = false); + static void AddChatCommands(); }; } diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index dc856792..45e6f1a1 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -273,6 +273,11 @@ namespace Components } } + Game::dvar_t* Dedicated::Dvar_RegisterSVNetworkFps(const char* dvarName, int, int min, int, int, const char* description) + { + return Game::Dvar_RegisterInt(dvarName, 1000, min, 1000, Game::dvar_flag::DVAR_FLAG_NONE, description); + } + Dedicated::Dedicated() { // Map rotation @@ -311,7 +316,7 @@ namespace Components Utils::Hook::Nop(0x4DCEC9, 2); // some check preventing proper game functioning Utils::Hook::Nop(0x507C79, 6); // another similar bsp check - Utils::Hook::Nop(0x414E4D, 6); // unknown check in SV_ExecuteClientMessage (0x20F0890 == 0, related to client->f_40) + Utils::Hook::Nop(0x414E4D, 6); // cl->messageAcknowledge > cl->gamestateMessageNum check in SV_ExecuteClientMessage Utils::Hook::Nop(0x4DCEE9, 5); // some deinit renderer function Utils::Hook::Nop(0x59A896, 5); // warning message on a removed subsystem Utils::Hook::Nop(0x4B4EEF, 5); // same as above @@ -326,14 +331,8 @@ namespace Components // isHost script call return 0 Utils::Hook::Set(0x5DEC04, 0); - // sv_network_fps max 1000, and uncheat - Utils::Hook::Set(0x4D3C67, 0); // ? - Utils::Hook::Set(0x4D3C69, 1000); - // Manually register sv_network_fps - Utils::Hook::Nop(0x4D3C7B, 5); - Utils::Hook::Nop(0x4D3C8E, 5); - *reinterpret_cast(0x62C7C00) = Dvar::Register("sv_network_fps", 1000, 20, 1000, Game::dvar_flag::DVAR_FLAG_NONE, "Number of times per second the server checks for net messages").get(); + Utils::Hook(0x4D3C7B, Dedicated::Dvar_RegisterSVNetworkFps, HOOK_CALL).install()->quick(); // r_loadForRenderer default to 0 Utils::Hook::Set(0x519DDF, 0); diff --git a/src/Components/Modules/Dedicated.hpp b/src/Components/Modules/Dedicated.hpp index 9515870b..78126922 100644 --- a/src/Components/Modules/Dedicated.hpp +++ b/src/Components/Modules/Dedicated.hpp @@ -29,5 +29,7 @@ namespace Components static void TransmitGuids(); static void TimeWrapStub(Game::errorParm_t code, const char* message); + + static Game::dvar_t* Dvar_RegisterSVNetworkFps(const char* dvarName, int value, int min, int max, int flags, const char* description); }; } diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 78b8e6b9..d8c3ac71 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -68,19 +68,22 @@ namespace Components EmptyClipboard(); auto* hMem = GlobalAlloc(GMEM_MOVEABLE, error.size() + 1); - if (hMem != nullptr) + if (hMem == nullptr) { - auto lock = reinterpret_cast(GlobalLock(hMem)); + CloseClipboard(); + return; + } - if (lock != nullptr) - { - std::strcpy(lock, error.data()); // Should be okay since we allocated size + 1 - GlobalUnlock(hMem); - SetClipboardData(1, hMem); - } + auto lock = GlobalLock(hMem); + if (lock != nullptr) + { + std::memcpy(lock, error.data(), error.size() + 1); + GlobalUnlock(hMem); + SetClipboardData(1, hMem); } CloseClipboard(); + GlobalFree(hMem); } LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) @@ -95,19 +98,22 @@ namespace Components std::string errorStr; if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - errorStr = "Termination because of a stack overflow."; + errorStr = "Termination because of a stack overflow.\nCopy exception address to clipboard?"; } else { - errorStr = Utils::String::VA("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); + errorStr = Utils::String::VA("Fatal error (0x%08X) at 0x%08X.\nCopy exception address to clipboard?", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); } //Exception::SuspendProcess(); - Exception::CopyMessageToClipboard(errorStr); - MessageBoxA(nullptr, errorStr.data(), "ERROR", MB_ICONERROR); + // Message should be copied to the keyboard if no button is pressed + if (MessageBoxA(nullptr, errorStr.data(), nullptr, MB_YESNO | MB_ICONERROR) == IDYES) + { + Exception::CopyMessageToClipboard(Utils::String::VA("0x%08X", ExceptionInfo->ExceptionRecord->ExceptionAddress)); + } - if ( Flags::HasFlag("bigminidumps")) + if (Flags::HasFlag("bigminidumps")) { Exception::SetMiniDumpType(true, false); } @@ -199,8 +205,8 @@ namespace Components // Display DEBUG branding, so we know we're on a debug build Scheduler::OnFrame([]() { - Game::Font_s* font = Game::R_RegisterFont("fonts/normalFont", 0); - float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; + auto* font = Game::R_RegisterFont("fonts/normalFont", 0); + Game::vec4_t color = { 1.0f, 1.0f, 1.0f, 1.0f }; // Change the color when attaching a debugger if (IsDebuggerPresent()) @@ -228,12 +234,12 @@ namespace Components Game::UI_UpdateArenas(); std::string command; - for (int i = 0; i < (params->length() >= 2 ? atoi(params->get(1)) : *Game::arenaCount); ++i) + for (auto i = 0; i < (params->length() >= 2 ? atoi(params->get(1)) : *Game::arenaCount); ++i) { - char* mapname = ArenaLength::NewArenas[i % *Game::arenaCount].mapName; + const auto* mapname = ArenaLength::NewArenas[i % *Game::arenaCount].mapName; - if (!(i % 2)) command.append(Utils::String::VA("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect - else command.append(Utils::String::VA("wait 500;", mapname)); // Test direct map switch + if (!(i % 2)) command.append("wait 250;disconnect;wait 750;"); // Test a disconnect + else command.append("wait 500;"); // Test direct map switch command.append(Utils::String::VA("map %s;", mapname)); } diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index e85e61dd..3be8da5b 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -867,7 +867,7 @@ namespace Components } // Check for frozen controls. Flag name should start with PMF_ - if (CG_ShouldUpdateViewAngles(gamePadIndex) && (clientActive.snap.ps.pm_flags & 0x800) == 0) + if (CG_ShouldUpdateViewAngles(gamePadIndex) && (clientActive.snap.ps.pm_flags & Game::PMF_FROZEN) == 0) { Game::AimInput aimInput{}; Game::AimOutput aimOutput{}; @@ -1172,8 +1172,7 @@ namespace Components } else { - Game::Cbuf_AddText(gamePadIndex, keyBinding); - Game::Cbuf_AddText(gamePadIndex, "\n"); + Game::Cbuf_InsertText(gamePadIndex, keyBinding); } } } diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 80baa42f..a37f93c5 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -206,8 +206,16 @@ namespace Components if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end() && (FastFiles::Current() != "mp_shipment_long" || Maps::CurrentMainZone != "mp_shipment")) // Shipment is a special case { - if (type == Game::XAssetType::ASSET_TYPE_CLIPMAP_MP || type == Game::XAssetType::ASSET_TYPE_CLIPMAP_SP || type == Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP || type == Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP || type == Game::XAssetType::ASSET_TYPE_GFXWORLD || type == Game::XAssetType::ASSET_TYPE_MAP_ENTS || type == Game::XAssetType::ASSET_TYPE_COMWORLD || type == Game::XAssetType::ASSET_TYPE_FXWORLD) + switch (type) { + case Game::XAssetType::ASSET_TYPE_CLIPMAP_MP: + case Game::XAssetType::ASSET_TYPE_CLIPMAP_SP: + case Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP: + case Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP: + case Game::XAssetType::ASSET_TYPE_GFXWORLD: + case Game::XAssetType::ASSET_TYPE_MAP_ENTS: + case Game::XAssetType::ASSET_TYPE_COMWORLD: + case Game::XAssetType::ASSET_TYPE_FXWORLD: *restrict = true; return; } @@ -244,15 +252,16 @@ namespace Components Utils::IO::WriteFile(Utils::String::VA("raw/%s.ents", name.data()), asset.mapEnts->entityString, true); } + static std::string mapEntities; FileSystem::File ents(name + ".ents"); if (ents.exists()) { - const auto& mapEntities = ents.getBuffer(); - asset.mapEnts->entityString = const_cast(mapEntities.data()); + mapEntities = ents.getBuffer(); + asset.mapEnts->entityString = mapEntities.data(); asset.mapEnts->numEntityChars = mapEntities.size() + 1; } } - + // This is broken if ((type == Game::XAssetType::ASSET_TYPE_MENU || type == Game::XAssetType::ASSET_TYPE_MENULIST) && Zones::Version() >= 359) { @@ -317,7 +326,7 @@ namespace Components mapname = "mp_shipment_long"; } - _snprintf_s(buffer, size, size, format, mapname); + _snprintf_s(buffer, size, _TRUNCATE, format, mapname); } void Maps::HandleAsSPMap() @@ -332,7 +341,7 @@ namespace Components { std::regex _(expression); } - catch (const std::exception e) + catch (const std::regex_error ex) { MessageBoxA(nullptr, Utils::String::VA("Invalid regular expression: %s", expression.data()), "Warning", MB_ICONEXCLAMATION); return; @@ -438,7 +447,7 @@ namespace Components void Maps::LoadNewMapCommand(char* buffer, size_t size, const char* /*format*/, const char* mapname, const char* gametype) { unsigned int hash = Maps::GetUsermapHash(mapname); - _snprintf_s(buffer, size, size, "loadingnewmap\n%s\n%s\n%d", mapname, gametype, hash); + _snprintf_s(buffer, size, _TRUNCATE, "loadingnewmap\n%s\n%s\n%d", mapname, gametype, hash); } int Maps::TriggerReconnectForMap(Game::msg_t* msg, const char* mapname) diff --git a/src/Components/Modules/Movement.cpp b/src/Components/Modules/Movement.cpp index f71c9699..234b3b77 100644 --- a/src/Components/Modules/Movement.cpp +++ b/src/Components/Modules/Movement.cpp @@ -5,47 +5,29 @@ namespace Components Dvar::Var Movement::PlayerDuckedSpeedScale; Dvar::Var Movement::PlayerLastStandCrawlSpeedScale; Dvar::Var Movement::PlayerProneSpeedScale; + Dvar::Var Movement::PlayerSpectateSpeedScale; + Dvar::Var Movement::CGUfoScaler; + Dvar::Var Movement::CGNoclipScaler; + Dvar::Var Movement::BGBouncesAllAngles; + Dvar::Var Movement::BGRocketJump; + Dvar::Var Movement::BGPlayerEjection; + Dvar::Var Movement::BGPlayerCollision; + Game::dvar_t* Movement::BGBounces; - int Movement::PMGetEffectiveStance(Game::playerState_s* ps) + float Movement::PM_CmdScaleForStance(const Game::pmove_s* pm) { - auto heightTarget = ps->viewHeightTarget; + assert(pm->ps != nullptr); - if (heightTarget == 0x16) - return Game::PM_EFF_STANCE_LASTSTANDCRAWL; - - if (heightTarget == 0x28) - return Game::PM_EFF_STANCE_DUCKED; - - if (heightTarget == 0xB) - return Game::PM_EFF_STANCE_PRONE; - - return Game::PM_EFF_STANCE_DEFAULT; - } - - float Movement::PMCmdScaleForStance(Game::pmove_s* move) - { - auto* playerState = move->ps; + const auto* playerState = pm->ps; float scale; if (playerState->viewHeightLerpTime != 0 && playerState->viewHeightLerpTarget == 0xB) { - scale = move->cmd.serverTime - playerState->viewHeightLerpTime / 400.0f; + scale = pm->cmd.serverTime - playerState->viewHeightLerpTime / 400.0f; if (0.0f <= scale) { - auto flags = 0; - - if (scale < 1.0f) - { - flags |= 1 << 8; - } - - if (scale == 1.0f) - { - flags |= 1 << 14; - } - - if (flags == 0) + if (scale > 1.0f) { scale = 1.0f; return scale * 0.15f + (1.0f - scale) * 0.65f; @@ -61,23 +43,11 @@ namespace Components if ((playerState->viewHeightLerpTime != 0 && playerState->viewHeightLerpTarget == 0x28) && playerState->viewHeightLerpDown == 0) { - scale = 400.0f / move->cmd.serverTime - playerState->viewHeightLerpTime; + scale = 400.0f / pm->cmd.serverTime - playerState->viewHeightLerpTime; if (0.0f <= scale) { - auto flags = 0; - - if (scale < 1.0f) - { - flags |= 1 << 8; - } - - if (scale == 1.0f) - { - flags |= 1 << 14; - } - - if (flags == 0) + if (scale > 1.0f) { scale = 1.0f; } @@ -89,7 +59,7 @@ namespace Components } scale = 1.0f; - auto stance = Movement::PMGetEffectiveStance(playerState); + const auto stance = Game::PM_GetEffectiveStance(playerState); if (stance == Game::PM_EFF_STANCE_PRONE) { @@ -109,14 +79,14 @@ namespace Components return scale; } - __declspec(naked) void Movement::PMCmdScaleForStanceStub() + __declspec(naked) void Movement::PM_CmdScaleForStanceStub() { __asm { pushad push edx - call Movement::PMCmdScaleForStance + call Movement::PM_CmdScaleForStance // pm add esp, 4 popad @@ -124,18 +94,202 @@ namespace Components } } - Game::dvar_t* Movement::Dvar_RegisterLastStandSpeedScale(const char* name, float defaultVal, float min, float max, int, const char* desc) + float Movement::PM_MoveScale(Game::playerState_s* ps, float forwardmove, + float rightmove, float upmove) { - Movement::PlayerLastStandCrawlSpeedScale = Dvar::Register(name, defaultVal, + assert(ps != nullptr); + + auto max = (std::fabsf(forwardmove) < std::fabsf(rightmove)) + ? std::fabsf(rightmove) + : std::fabsf(forwardmove); + + if (std::fabsf(upmove) > max) + { + max = std::fabsf(upmove); + } + + if (max == 0.0f) + { + return 0.0f; + } + + auto total = std::sqrtf(forwardmove * forwardmove + + rightmove * rightmove + upmove * upmove); + auto scale = (ps->speed * max) / (127.0f * total); + + if (ps->pm_flags & Game::PMF_WALKING || ps->leanf != 0.0f) + { + scale *= 0.4f; + } + + if (ps->pm_type == Game::PM_NOCLIP) + { + return scale * Movement::CGNoclipScaler.get(); + } + + if (ps->pm_type == Game::PM_UFO) + { + return scale * Movement::CGUfoScaler.get(); + } + + if (ps->pm_type == Game::PM_SPECTATOR) + { + return scale * Movement::PlayerSpectateSpeedScale.get(); + } + + return scale; + } + + __declspec(naked) void Movement::PM_MoveScaleStub() + { + __asm + { + pushad + + push [esp + 0xC + 0x20] // upmove + push [esp + 0xC + 0x20] // rightmove + push [esp + 0xC + 0x20] // forwardmove + push esi // ps + call Movement::PM_MoveScale + add esp, 0x10 + + popad + ret + } + } + + __declspec(naked) void Movement::PM_StepSlideMoveStub() + { + __asm + { + // Check the value of BGBounces + push ecx + push eax + + mov eax, Movement::BGBounces + mov ecx, dword ptr [eax + 0x10] + test ecx, ecx + + pop eax + pop ecx + + // Do not bounce if BGBounces is 0 + jle noBounce + + // Bounce + push 0x4B1B34 + retn + + noBounce: + // Original game code + cmp dword ptr [esp + 0x24], 0 + push 0x4B1B48 + retn + } + } + + void Movement::PM_ProjectVelocityStub(const float* velIn, const float* normal, float* velOut) + { + const auto lengthSquared2D = velIn[0] * velIn[0] + velIn[1] * velIn[1]; + + if (std::fabsf(normal[2]) < 0.001f || lengthSquared2D == 0.0) + { + velOut[0] = velIn[0]; + velOut[1] = velIn[1]; + velOut[2] = velIn[2]; + return; + } + + auto newZ = velIn[0] * normal[0] + velIn[1] * normal[1]; + newZ = -newZ / normal[2]; + const auto lengthScale = std::sqrtf((velIn[2] * velIn[2] + lengthSquared2D) + / (newZ * newZ + lengthSquared2D)); + + if (Movement::BGBouncesAllAngles.get() + || (lengthScale < 1.f || newZ < 0.f || velIn[2] > 0.f)) + { + velOut[0] = velIn[0] * lengthScale; + velOut[1] = velIn[1] * lengthScale; + velOut[2] = newZ * lengthScale; + } + } + + // Double bounces + void Movement::Jump_ClearState_Hk(Game::playerState_s* ps) + { + if (Movement::BGBounces->current.integer != Movement::DOUBLE) + { + Game::Jump_ClearState(ps); + } + } + + Game::gentity_s* Movement::Weapon_RocketLauncher_Fire_Hk(Game::gentity_s* ent, unsigned int weaponIndex, + float spread, Game::weaponParms* wp, const float* gunVel, Game::lockonFireParms* lockParms, bool a7) + { + auto* result = Game::Weapon_RocketLauncher_Fire(ent, weaponIndex, spread, wp, gunVel, lockParms, a7); + + if (ent->client != nullptr && BGRocketJump.get()) + { + ent->client->ps.velocity[0] += (0 - wp->forward[0]) * 64.0f; + ent->client->ps.velocity[1] += (0 - wp->forward[1]) * 64.0f; + ent->client->ps.velocity[2] += (0 - wp->forward[2]) * 64.0f; + } + + return result; + } + + int Movement::StuckInClient_Hk(Game::gentity_s* self) + { + if (Movement::BGPlayerEjection.get()) + { + return Utils::Hook::Call(0x402D30)(self); // StuckInClient + } + + return 0; + } + + void Movement::CM_TransformedCapsuleTrace_Hk(Game::trace_t* results, const float* start, const float* end, + const Game::Bounds* bounds, const Game::Bounds* capsule, int contents, const float* origin, const float* angles) + { + if (Movement::BGPlayerCollision.get()) + { + Utils::Hook::Call + (0x478300) + (results, start, end, bounds, capsule, contents, origin, angles); // CM_TransformedCapsuleTrace + } + } + + Game::dvar_t* Movement::Dvar_RegisterLastStandSpeedScale(const char* name, float value, + float min, float max, int, const char* desc) + { + Movement::PlayerLastStandCrawlSpeedScale = Dvar::Register(name, value, min, max, Game::DVAR_FLAG_CHEAT | Game::DVAR_FLAG_REPLICATED, desc); return Movement::PlayerLastStandCrawlSpeedScale.get(); } + Game::dvar_t* Movement::Dvar_RegisterSpectateSpeedScale(const char* name, float value, + float min, float max, int, const char* desc) + { + Movement::PlayerSpectateSpeedScale = Dvar::Register(name, value, + min, max, Game::DVAR_FLAG_CHEAT | Game::DVAR_FLAG_REPLICATED, desc); + + return Movement::PlayerSpectateSpeedScale.get(); + } + Movement::Movement() { Dvar::OnInit([] { + static const char* bg_bouncesValues[] = + { + "disabled", + "enabled", + "double", + nullptr + }; + Movement::PlayerDuckedSpeedScale = Dvar::Register("player_duckedSpeedScale", 0.65f, 0.0f, 5.0f, Game::DVAR_FLAG_CHEAT | Game::DVAR_FLAG_REPLICATED, "The scale applied to the player speed when ducking"); @@ -143,19 +297,60 @@ namespace Components Movement::PlayerProneSpeedScale = Dvar::Register("player_proneSpeedScale", 0.15f, 0.0f, 5.0f, Game::DVAR_FLAG_CHEAT | Game::DVAR_FLAG_REPLICATED, "The scale applied to the player speed when crawling"); + + // 3arc naming convention + Movement::CGUfoScaler = Dvar::Register("cg_ufo_scaler", + 6.0f, 0.001f, 1000.0f, Game::DVAR_FLAG_CHEAT | Game::DVAR_FLAG_REPLICATED, + "The speed at which ufo camera moves"); + + Movement::CGNoclipScaler = Dvar::Register("cg_noclip_scaler", + 3.0f, 0.001f, 1000.0f, Game::DVAR_FLAG_CHEAT | Game::DVAR_FLAG_REPLICATED, + "The speed at which noclip camera moves"); + + Movement::BGBounces = Game::Dvar_RegisterEnum("bg_bounces", + bg_bouncesValues, Movement::DISABLED, Game::DVAR_FLAG_REPLICATED, "Bounce glitch settings"); + + Movement::BGBouncesAllAngles = Dvar::Register("bg_bouncesAllAngles", + false, Game::DVAR_FLAG_REPLICATED, "Force bounce from all angles"); + + Movement::BGRocketJump = Dvar::Register("bg_rocketJump", + false, Game::DVAR_FLAG_REPLICATED, "Enable CoD4 rocket jumps"); + + Movement::BGPlayerEjection = Dvar::Register("bg_playerEjection", + true, Game::DVAR_FLAG_REPLICATED, "Push intersecting players away from each other"); + + Movement::BGPlayerCollision = Dvar::Register("bg_playerCollision", + true, Game::DVAR_FLAG_REPLICATED, "Push intersecting players away from each other"); }); // Hook PM_CmdScaleForStance in PM_CmdScale_Walk - Utils::Hook(0x572F34, Movement::PMCmdScaleForStanceStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x572F34, Movement::PM_CmdScaleForStanceStub, HOOK_CALL).install()->quick(); //Hook PM_CmdScaleForStance in PM_GetMaxSpeed - Utils::Hook(0x57395F, Movement::PMCmdScaleForStanceStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x57395F, Movement::PM_CmdScaleForStanceStub, HOOK_CALL).install()->quick(); // Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used. Utils::Hook(0x448B66, Movement::Dvar_RegisterLastStandSpeedScale, HOOK_CALL).install()->quick(); - } - Movement::~Movement() - { + // Hook Dvar_RegisterFloat. Only thing that's changed is that the 0x80 flag is not used. + Utils::Hook(0x448990, Movement::Dvar_RegisterSpectateSpeedScale, HOOK_CALL).install()->quick(); + + // Hook PM_MoveScale so we can add custom speed scale for Ufo and Noclip + Utils::Hook(0x56F845, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x56FABD, Movement::PM_MoveScaleStub, HOOK_CALL).install()->quick(); + + // Bounce logic + Utils::Hook(0x4B1B2D, Movement::PM_StepSlideMoveStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x57383E, Movement::Jump_ClearState_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x4B1B97, Movement::PM_ProjectVelocityStub, HOOK_CALL).install()->quick(); + + // Rocket jump + Utils::Hook(0x4A4F9B, Movement::Weapon_RocketLauncher_Fire_Hk, HOOK_CALL).install()->quick(); // FireWeapon + + // Hook StuckInClient & CM_TransformedCapsuleTrace + // so we can prevent intersecting players from being pushed away from each other + Utils::Hook(0x5D8153, Movement::StuckInClient_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x45A5BF, Movement::CM_TransformedCapsuleTrace_Hk, HOOK_CALL).install()->quick(); // SV_ClipMoveToEntity + Utils::Hook(0x5A0CAD, Movement::CM_TransformedCapsuleTrace_Hk, HOOK_CALL).install()->quick(); // CG_ClipMoveToEntity } } diff --git a/src/Components/Modules/Movement.hpp b/src/Components/Modules/Movement.hpp index 07ad6894..97243ee2 100644 --- a/src/Components/Modules/Movement.hpp +++ b/src/Components/Modules/Movement.hpp @@ -6,17 +6,41 @@ namespace Components { public: Movement(); - ~Movement(); private: + enum BouncesSettings { DISABLED, ENABLED, DOUBLE }; + static Dvar::Var PlayerDuckedSpeedScale; static Dvar::Var PlayerLastStandCrawlSpeedScale; static Dvar::Var PlayerProneSpeedScale; + static Dvar::Var PlayerSpectateSpeedScale; + static Dvar::Var CGUfoScaler; + static Dvar::Var CGNoclipScaler; + static Dvar::Var BGBouncesAllAngles; + static Dvar::Var BGRocketJump; + static Dvar::Var BGPlayerEjection; + static Dvar::Var BGPlayerCollision; + // Can't use Var class inside assembly stubs + static Game::dvar_t* BGBounces; - static int PMGetEffectiveStance(Game::playerState_s* ps); - static float PMCmdScaleForStance(Game::pmove_s* move); - static void PMCmdScaleForStanceStub(); + static float PM_CmdScaleForStance(const Game::pmove_s* move); + static void PM_CmdScaleForStanceStub(); - static Game::dvar_t* Dvar_RegisterLastStandSpeedScale(const char* name, float defaultVal, float min, float max, int flags, const char* desc); + static float PM_MoveScale(Game::playerState_s* ps, float forwardmove, float rightmove, float upmove); + static void PM_MoveScaleStub(); + + // Bounce logic + static void PM_StepSlideMoveStub(); + static void PM_ProjectVelocityStub(const float* velIn, const float* normal, float* velOut); + static void Jump_ClearState_Hk(Game::playerState_s* ps); + + static Game::gentity_s* Weapon_RocketLauncher_Fire_Hk(Game::gentity_s* ent, unsigned int weaponIndex, float spread, Game::weaponParms* wp, const float* gunVel, Game::lockonFireParms* lockParms, bool a7); + + // Player collison + static int StuckInClient_Hk(Game::gentity_s* self); + static void CM_TransformedCapsuleTrace_Hk(Game::trace_t* results, const float* start, const float* end, const Game::Bounds* bounds, const Game::Bounds* capsule, int contents, const float* origin, const float* angles); + + static Game::dvar_t* Dvar_RegisterLastStandSpeedScale(const char* name, float value, float min, float max, int flags, const char* desc); + static Game::dvar_t* Dvar_RegisterSpectateSpeedScale(const char* name, float value, float min, float max, int flags, const char* desc); }; } diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 1b762e38..b0ebd610 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -238,34 +238,6 @@ namespace Components } } - Game::dvar_t* QuickPatch::sv_enableBounces; - __declspec(naked) void QuickPatch::BounceStub() - { - __asm - { - // check the value of sv_enableBounces - push eax; - mov eax, sv_enableBounces; - cmp byte ptr[eax + 16], 1; - pop eax; - - // always bounce if sv_enableBounces is set to 1 - je bounce; - - // original code - cmp dword ptr[esp + 24h], 0; - jnz dontBounce; - - bounce: - push 0x004B1B34; - retn; - - dontBounce: - push 0x004B1B48; - retn; - } - } - Game::dvar_t* QuickPatch::Dvar_RegisterAspectRatioDvar(const char* name, char**, int defaultVal, int flags, const char* description) { static const char* r_aspectRatioEnum[] = @@ -324,61 +296,6 @@ namespace Components } } - Game::dvar_t* QuickPatch::g_playerCollision; - __declspec(naked) void QuickPatch::PlayerCollisionStub() - { - __asm - { - // check the value of g_playerCollision - push eax; - mov eax, g_playerCollision; - cmp byte ptr[eax + 16], 0; - pop eax; - - // dont collide if g_playerCollision is set to 0 - je dontcollide; - - // original code - mov eax, dword ptr[esp + 0xa0]; - push 0x00478376; - retn; - - dontcollide: - mov eax, dword ptr[esp + 0xa0]; - mov ecx, dword ptr[esp + 9ch]; - push eax; - push ecx; - lea edx, [esp + 48h]; - push edx; - mov eax, esi; - push 0x0047838b; - retn; - } - } - - Game::dvar_t* QuickPatch::g_playerEjection; - __declspec(naked) void QuickPatch::PlayerEjectionStub() - { - __asm - { - // check the value of g_playerEjection - push eax; - mov eax, g_playerEjection; - cmp byte ptr[eax + 16], 0; - pop eax; - - // dont eject if g_playerEjection is set to 0 - je donteject; - - push 0x005d8152; - retn; - - donteject: - push 0x005d815b; - retn; - } - } - BOOL QuickPatch::IsDynClassnameStub(char* a1) { auto version = Zones::GetEntitiesZoneVersion(); @@ -433,6 +350,12 @@ namespace Components } } + Game::dvar_t* QuickPatch::Dvar_RegisterUIBuildLocation(const char* dvarName, + float /*x*/, float /*y*/, float min, float max, int /*flags*/, const char* description) + { + return Game::Dvar_RegisterVec2(dvarName, -60.0f, 474.0f, min, max, Game::DVAR_FLAG_READONLY, description); + } + QuickPatch::QuickPatch() { // quit_hard @@ -450,21 +373,9 @@ namespace Components // Hook escape handling on open console to change behaviour to close the console instead of only canceling autocomplete Utils::Hook(0x4F66A3, CL_KeyEvent_ConsoleEscape_Stub, HOOK_JUMP).install()->quick(); - // bounce dvar - sv_enableBounces = Game::Dvar_RegisterBool("sv_enableBounces", false, Game::DVAR_FLAG_REPLICATED, "Enables bouncing on the server"); - Utils::Hook(0x4B1B2D, QuickPatch::BounceStub, HOOK_JUMP).install()->quick(); - // Intermission time dvar Game::Dvar_RegisterFloat("scr_intermissionTime", 10, 0, 120, Game::DVAR_FLAG_REPLICATED | Game::DVAR_FLAG_DEDISAVED, "Time in seconds before match server loads the next map"); - // Player Collision dvar - g_playerCollision = Game::Dvar_RegisterBool("g_playerCollision", true, Game::DVAR_FLAG_REPLICATED, "Flag whether player collision is on or off"); - Utils::Hook(0x47836F, QuickPatch::PlayerCollisionStub, HOOK_JUMP).install()->quick(); - - // Player Ejection dvar - g_playerEjection = Game::Dvar_RegisterBool("g_playerEjection", true, Game::DVAR_FLAG_REPLICATED, "Flag whether player ejection is on or off"); - Utils::Hook(0x5D814A, QuickPatch::PlayerEjectionStub, HOOK_JUMP).install()->quick(); - g_antilag = Game::Dvar_RegisterBool("g_antilag", true, Game::DVAR_FLAG_REPLICATED, "Perform antilag"); Utils::Hook(0x5D6D56, QuickPatch::ClientEventsFireWeaponStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x5D6D6A, QuickPatch::ClientEventsFireWeaponMeleeStub, HOOK_JUMP).install()->quick(); @@ -527,16 +438,11 @@ namespace Components Utils::Hook::Set(0x60BD56, "IW4x (" VERSION ")"); // version string color - static float buildLocColor[] = { 1.0f, 1.0f, 1.0f, 0.8f }; - Utils::Hook::Set(0x43F710, buildLocColor); + static Game::vec4_t buildLocColor = { 1.0f, 1.0f, 1.0f, 0.8f }; + Utils::Hook::Set(0x43F710, buildLocColor); // Shift ui version string to the left (ui_buildlocation) - Utils::Hook::Nop(0x6310A0, 5); // Don't register the initial dvar - Utils::Hook::Nop(0x6310B8, 5); // Don't write the result - Dvar::OnInit([]() - { - *reinterpret_cast(0x62E4B64) = Game::Dvar_RegisterVec2("ui_buildLocation", -60.0f, 474.0f, -10000.0, 10000.0, Game::DVAR_FLAG_READONLY, "Where to draw the build number"); - }); + Utils::Hook(0x6310A0, QuickPatch::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // console title if (ZoneBuilder::IsEnabled()) @@ -763,11 +669,6 @@ namespace Components QuickPatch::UnlockStats(); }); - Command::Add("crash", [](Command::Params*) - { - throw new std::exception(); - }); - Command::Add("dumptechsets", [](Command::Params* param) { if (param->length() != 2) @@ -1000,11 +901,6 @@ namespace Components } } - QuickPatch::~QuickPatch() - { - - } - bool QuickPatch::unitTest() { uint32_t randIntCount = 4'000'000; diff --git a/src/Components/Modules/QuickPatch.hpp b/src/Components/Modules/QuickPatch.hpp index de070be5..32c3ed61 100644 --- a/src/Components/Modules/QuickPatch.hpp +++ b/src/Components/Modules/QuickPatch.hpp @@ -6,7 +6,6 @@ namespace Components { public: QuickPatch(); - ~QuickPatch(); bool unitTest() override; @@ -28,9 +27,6 @@ namespace Components static bool InvalidNameCheck(char* dest, const char* source, int size); static void InvalidNameStub(); - static Game::dvar_t* sv_enableBounces; - static void BounceStub(); - static Dvar::Var r_customAspectRatio; static Game::dvar_t* Dvar_RegisterAspectRatioDvar(const char* name, char** enumValues, int defaultVal, int flags, const char* description); static void SetAspectRatioStub(); @@ -40,13 +36,11 @@ namespace Components static void ClientEventsFireWeaponStub(); static void ClientEventsFireWeaponMeleeStub(); - static Game::dvar_t* g_playerCollision; - static void PlayerCollisionStub(); - static Game::dvar_t* g_playerEjection; - static void PlayerEjectionStub(); static BOOL IsDynClassnameStub(char* a1); static void CL_KeyEvent_OnEscape(); static void CL_KeyEvent_ConsoleEscape_Stub(); + + static Game::dvar_t* Dvar_RegisterUIBuildLocation(const char* dvarName, float x, float y, float min, float max, int flags, const char* description); }; } diff --git a/src/Components/Modules/StartupMessages.cpp b/src/Components/Modules/StartupMessages.cpp index b7be14b3..26e79a26 100644 --- a/src/Components/Modules/StartupMessages.cpp +++ b/src/Components/Modules/StartupMessages.cpp @@ -28,7 +28,7 @@ namespace Components Game::Dvar_SetStringByName("ui_startupMessage", message.data()); Game::Dvar_SetStringByName("ui_startupMessageTitle", Utils::String::VA("Messages (%d/%d)", StartupMessages::TotalMessages - StartupMessages::MessageList.size(), StartupMessages::TotalMessages)); Game::Dvar_SetStringByName("ui_startupNextButtonText", StartupMessages::MessageList.size() ? "Next" : "Close"); - Game::Cbuf_AddText(0, "openmenu startup_messages"); + Game::Cbuf_AddText(0, "openmenu startup_messages\n"); StartupMessages::MessageList.pop_front(); }); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index cf54fd5e..9f57c7a7 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -34,6 +34,7 @@ namespace Game Cbuf_AddServerText_t Cbuf_AddServerText = Cbuf_AddServerText_t(0x4BB9B0); Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20); + Cbuf_InsertText_t Cbuf_InsertText = Cbuf_InsertText_t(0x4940B0); CG_NextWeapon_f_t CG_NextWeapon_f = CG_NextWeapon_f_t(0x449DE0); CG_GetClientNum_t CG_GetClientNum = CG_GetClientNum_t(0x433700); @@ -326,6 +327,8 @@ namespace Game SV_SetConfigstring_t SV_SetConfigstring = SV_SetConfigstring_t(0x4982E0); SV_Loaded_t SV_Loaded = SV_Loaded_t(0x4EE3E0); SV_ClientThink_t SV_ClientThink = SV_ClientThink_t(0x44ADD0); + SV_GetPlayerByName_t SV_GetPlayerByName = SV_GetPlayerByName_t(0x6242B0); + SV_GetPlayerByNum_t SV_GetPlayerByNum = SV_GetPlayerByNum_t(0x624390); Sys_FreeFileList_t Sys_FreeFileList = Sys_FreeFileList_t(0x4D8580); Sys_IsDatabaseReady_t Sys_IsDatabaseReady = Sys_IsDatabaseReady_t(0x4CA4A0); @@ -381,9 +384,12 @@ namespace Game Field_AdjustScroll_t Field_AdjustScroll = Field_AdjustScroll_t(0x488C10); AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee = AimAssist_ApplyAutoMelee_t(0x56A360); + Weapon_RocketLauncher_Fire_t Weapon_RocketLauncher_Fire = Weapon_RocketLauncher_Fire_t(0x424680); + Jump_ClearState_t Jump_ClearState = Jump_ClearState_t(0x04B3890); PM_playerTrace_t PM_playerTrace = PM_playerTrace_t(0x458980); PM_Trace_t PM_Trace = PM_Trace_t(0x441F60); + PM_GetEffectiveStance_t PM_GetEffectiveStance = PM_GetEffectiveStance_t(0x412540); XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); unsigned int* g_poolSize = reinterpret_cast(0x7995E8); @@ -664,7 +670,7 @@ namespace Game { Dvar_SetStringByName("com_errorMessage", message.data()); Dvar_SetStringByName("com_errorTitle", title.data()); - Cbuf_AddText(0, "openmenu error_popmenu_lobby"); + Cbuf_AddText(0, "openmenu error_popmenu_lobby\n"); } } diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index fed9b4d0..f88ca163 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -46,9 +46,12 @@ namespace Game typedef void(__cdecl * Cbuf_AddServerText_t)(); extern Cbuf_AddServerText_t Cbuf_AddServerText; - typedef void(__cdecl * Cbuf_AddText_t)(int localClientNum, const char *text); + typedef void(__cdecl * Cbuf_AddText_t)(int localClientNum, const char* text); extern Cbuf_AddText_t Cbuf_AddText; + typedef void(__cdecl * Cbuf_InsertText_t)(int localClientNum, const char* text); + extern Cbuf_InsertText_t Cbuf_InsertText; + typedef int(__cdecl * CG_GetClientNum_t)(); extern CG_GetClientNum_t CG_GetClientNum; @@ -133,13 +136,13 @@ namespace Game typedef void(__cdecl * Com_EndParseSession_t)(); extern Com_EndParseSession_t Com_EndParseSession; - typedef void(__cdecl * Com_BeginParseSession_t)(const char* why); + typedef void(__cdecl * Com_BeginParseSession_t)(const char* filename); extern Com_BeginParseSession_t Com_BeginParseSession; typedef void(__cdecl * Com_SetSpaceDelimited_t)(int); extern Com_SetSpaceDelimited_t Com_SetSpaceDelimited; - typedef char* (__cdecl * Com_Parse_t)(const char **data_p); + typedef char*(__cdecl * Com_Parse_t)(const char** data_p); extern Com_Parse_t Com_Parse; typedef bool (__cdecl * Com_MatchToken_t)(const char **data_p, const char* token, int size); @@ -783,9 +786,18 @@ namespace Game typedef bool(__cdecl * SV_Loaded_t)(); extern SV_Loaded_t SV_Loaded; - typedef void(__cdecl* SV_ClientThink_t)(client_s*, usercmd_s*); + typedef void(__cdecl * SV_ClientThink_t)(client_s*, usercmd_s*); extern SV_ClientThink_t SV_ClientThink; + typedef client_t*(__cdecl * SV_GetPlayerByName_t)(); + extern SV_GetPlayerByName_t SV_GetPlayerByName; + + typedef client_t*(__cdecl * SV_GetPlayerByNum_t)(); + extern SV_GetPlayerByNum_t SV_GetPlayerByNum; + + typedef int(__cdecl * Sys_Error_t)(int, char *, ...); + extern Sys_Error_t Sys_Error; + typedef void(__cdecl * Sys_FreeFileList_t)(char** list); extern Sys_FreeFileList_t Sys_FreeFileList; @@ -906,6 +918,9 @@ namespace Game typedef void(__cdecl * AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee; + typedef gentity_s*(__cdecl * Weapon_RocketLauncher_Fire_t)(gentity_s* ent, unsigned int weaponIndex, float spread, weaponParms* wp, const float* gunVel, lockonFireParms* lockParms, bool a7); + extern Weapon_RocketLauncher_Fire_t Weapon_RocketLauncher_Fire; + typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps); extern Jump_ClearState_t Jump_ClearState; @@ -915,6 +930,9 @@ namespace Game typedef void(__cdecl * PM_Trace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); extern PM_Trace_t PM_Trace; + typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps); + extern PM_GetEffectiveStance_t PM_GetEffectiveStance; + extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 187cf3f6..84792969 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -865,6 +865,39 @@ namespace Game MaterialShaderArgument *args; }; + /* 9045 */ + struct visionSetVars_t + { + bool glowEnable; + float glowBloomCutoff; + float glowBloomDesaturation; + float glowBloomIntensity0; + float glowBloomIntensity1; + float glowRadius0; + float glowRadius1; + float glowSkyBleedIntensity0; + float glowSkyBleedIntensity1; + bool filmEnable; + float filmBrightness; + float filmContrast; + float filmDesaturation; + float filmDesaturationDark; + bool filmInvert; + float filmLightTint[3]; + float filmMediumTint[3]; + float filmDarkTint[3]; + bool charPrimaryUseTweaks; + float charPrimaryDiffuseScale; + float charPrimarySpecularScale; + }; + + struct visField_t + { + const char* name; + int offset; + int fieldType; + }; + enum OffhandClass { OFFHAND_CLASS_NONE = 0x0, @@ -1101,6 +1134,32 @@ namespace Game hudelem_s archival[31]; }; + enum playerStateFlag + { + PMF_PRONE = 0x1, + PMF_DUCKED = 0x2, + PMF_MANTLE = 0x4, + PMF_LADDER = 0x8, + PMF_SIGHT_AIMING = 0x10, + PMF_BACKWARDS_RUN = 0x20, + PMF_WALKING = 0x40, + PMF_TIME_HARDLANDING = 0x80, + PMF_TIME_KNOCKBACK = 0x100, + PMF_PRONEMOVE_OVERRIDDEN = 0x200, + PMF_RESPAWNED = 0x400, + PMF_FROZEN = 0x800, + PMF_LADDER_FALL = 0x1000, + PMF_JUMPING = 0x2000, + PMF_SPRINTING = 0x4000, + PMF_SHELLSHOCKED = 0x8000, + PMF_MELEE_CHARGE = 0x10000, + PMF_NO_SPRINT = 0x20000, + PMF_NO_JUMP = 0x40000, + PMF_REMOTE_CONTROLLING = 0x80000, + PMF_ANIM_SCRIPTED = 0x100000, + PMF_DIVING = 0x400000 + }; + enum pmtype_t { PM_NORMAL = 0x0, @@ -2024,7 +2083,7 @@ namespace Game struct __declspec(align(4)) MapEnts { const char *name; - char *entityString; + const char *entityString; int numEntityChars; MapTriggers trigger; Stage *stages; @@ -4623,6 +4682,19 @@ namespace Game AddonMapEnts *addonMapEnts; }; + /* 9210 */ + struct weaponParms + { + float forward[3]; + float right[3]; + float up[3]; + float muzzleTrace[3]; + float gunForward[3]; + unsigned int weaponIndex; + const WeaponDef* weapDef; + const WeaponCompleteDef* weapCompleteDef; + }; + struct XAsset { XAssetType type; @@ -5594,6 +5666,14 @@ namespace Game static_assert(sizeof(gentity_s) == 0x274); + struct lockonFireParms + { + bool lockon; + gentity_s* target; + float targetPosOrOffset[3]; + bool topFire; + }; + #pragma pack(push, 1) typedef struct client_s diff --git a/tools/protoc.exe b/tools/protoc.exe index 07452286..87bf60b6 100644 Binary files a/tools/protoc.exe and b/tools/protoc.exe differ