diff --git a/CHANGELOG.md b/CHANGELOG.md index 725f82b6..4906ef22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ 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/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.7.2] - 2022-05-10 + +### Added + +- Add IsArray GSC function (#248) +- Keybind fields in menus work with controller keys (#255) + +### Changed + +- GSC function `GetSystemTime` now returns the Unix time (#258) + +### Fixed + +- Knife charge is fixed for controller players (#259) +- Fixed internet, local and favorites filters (#260) +- `sv_lanOnly` Dvar now prevents the server from sending heatbeats to master if set to true (#246) + +### Known issue + +- HTTPS is not supported for fast downloads at the moment. +- Sound issue fix is experimental as the bug is not fully understood. +- `reloadmenus` command does not free resources used by custom menus. + ## [0.7.1] - 2022-05-03 ### Added @@ -20,7 +43,9 @@ The format is based on [Keep a Changelog v0.3.0](http://keepachangelog.com/en/0. ### Changed - Test clients' native functionality has been restored by default (#162) +- Renamed GSC method `isBot` to `IsTestClient` (#162) - Custom GSC functions can be called correctly from a game script (#216) +- GSC functions `HttpCancel` and `HttpCancel` require the game to be launched with the command line argument `scriptablehttp` (#162) - Master server list will be used instead of the node system (load server list faster) (#234) ### Fixed diff --git a/premake5.lua b/premake5.lua index 47c2b42f..4a5fbe51 100644 --- a/premake5.lua +++ b/premake5.lua @@ -161,7 +161,7 @@ newaction { local versionHeader = assert(io.open(wks.location .. "/src/version.h", "w")) versionHeader:write("/*\n") versionHeader:write(" * Automatically generated by premake5.\n") - versionHeader:write(" * Do not touch, you fucking moron!\n") + versionHeader:write(" * Do not touch!\n") versionHeader:write(" */\n") versionHeader:write("\n") versionHeader:write("#define GIT_DESCRIBE " .. gitDescribeOutputQuoted .. "\n") @@ -181,7 +181,7 @@ newaction { local versionHeader = assert(io.open(wks.location .. "/src/version.hpp", "w")) versionHeader:write("/*\n") versionHeader:write(" * Automatically generated by premake5.\n") - versionHeader:write(" * Do not touch, you fucking moron!\n") + versionHeader:write(" * Do not touch!\n") versionHeader:write(" *\n") versionHeader:write(" * This file exists for reasons of complying with our coding standards.\n") versionHeader:write(" *\n") diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 7c64416a..912f2487 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -105,6 +105,7 @@ namespace Components Loader::Register(new Elevators()); Loader::Register(new ClientCommand()); Loader::Register(new ScriptExtension()); + Loader::Register(new Branding()); Loader::Register(new RawMouse()); Loader::Register(new Bullet()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 12ffb1ff..9851066a 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -136,5 +136,6 @@ namespace Components #include "Modules/ClientCommand.hpp" #include "Modules/Gamepad.hpp" #include "Modules/ScriptExtension.hpp" +#include "Modules/Branding.hpp" #include "Modules/RawMouse.hpp" #include "Modules/Bullet.hpp" diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index edccc68b..e89c73a2 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -108,8 +108,17 @@ namespace Components } } + void Bots::GScr_isTestClient(Game::scr_entref_t entref) + { + const auto* ent = Game::GetPlayerEntity(entref); + Game::Scr_AddBool(Game::SV_IsTestClient(ent->s.number) != 0); + } + void Bots::AddMethods() { + Script::AddMethod("IsBot", Bots::GScr_isTestClient); // Usage: self IsBot(); + Script::AddMethod("IsTestClient", Bots::GScr_isTestClient); // Usage: self IsTestClient(); + Script::AddMethod("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing() { auto ping = Game::Scr_GetInt(0); @@ -119,7 +128,7 @@ namespace Components const auto* ent = Game::GetPlayerEntity(entref); auto* client = Script::GetClient(ent); - if (!client->bIsTestClient) + if (Game::SV_IsTestClient(ent->s.number) == 0) { Game::Scr_Error("^1SetPing: Can only call on a bot!\n"); return; @@ -128,20 +137,11 @@ namespace Components client->ping = static_cast(ping); }); - Script::AddMethod("IsTestClient", [](Game::scr_entref_t entref) // Usage: IsTestClient(); - { - const auto* gentity = Game::GetPlayerEntity(entref); - const auto* client = Script::GetClient(gentity); - - Game::Scr_AddBool(client->bIsTestClient == 1); - }); - Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: BotStop(); { const auto* ent = Game::GetPlayerEntity(entref); - const auto* client = Script::GetClient(ent); - if (!client->bIsTestClient) + if (Game::SV_IsTestClient(ent->s.number) == 0) { Game::Scr_Error("^1BotStop: Can only call on a bot!\n"); return; @@ -154,17 +154,16 @@ namespace Components Script::AddMethod("BotWeapon", [](Game::scr_entref_t entref) // Usage: BotWeapon(); { - const auto* weapon = Game::Scr_GetString(0); - const auto* ent = Game::GetPlayerEntity(entref); - const auto* client = Script::GetClient(ent); - if (!client->bIsTestClient) + if (Game::SV_IsTestClient(ent->s.number) == 0) { Game::Scr_Error("^1BotWeapon: Can only call on a bot!\n"); return; } + const auto* weapon = Game::Scr_GetString(0); + if (weapon == nullptr || weapon[0] == '\0') { g_botai[entref.entnum].weapon = 1; @@ -178,6 +177,14 @@ namespace Components Script::AddMethod("BotAction", [](Game::scr_entref_t entref) // Usage: BotAction(); { + const auto* ent = Game::GetPlayerEntity(entref); + + if (Game::SV_IsTestClient(ent->s.number) == 0) + { + Game::Scr_Error("^1BotAction: Can only call on a bot!\n"); + return; + } + const auto* action = Game::Scr_GetString(0); if (action == nullptr) @@ -186,15 +193,6 @@ namespace Components return; } - const auto* ent = Game::GetPlayerEntity(entref); - const auto* client = Script::GetClient(ent); - - if (!client->bIsTestClient) - { - Game::Scr_Error("^1BotAction: Can only call on a bot!\n"); - return; - } - if (action[0] != '+' && action[0] != '-') { Game::Scr_ParamError(0, "^1BotAction: Sign for action must be '+' or '-'.\n"); @@ -220,20 +218,16 @@ namespace Components Script::AddMethod("BotMovement", [](Game::scr_entref_t entref) // Usage: BotMovement(, ); { - auto forwardInt = Game::Scr_GetInt(0); - auto rightInt = Game::Scr_GetInt(1); - const auto* ent = Game::GetPlayerEntity(entref); - const auto* client = Script::GetClient(ent); - if (!client->bIsTestClient) + if (Game::SV_IsTestClient(ent->s.number) == 0) { Game::Scr_Error("^1BotMovement: Can only call on a bot!\n"); return; } - forwardInt = std::clamp(forwardInt, std::numeric_limits::min(), std::numeric_limits::max()); - rightInt = std::clamp(rightInt, std::numeric_limits::min(), std::numeric_limits::max()); + const auto forwardInt = std::clamp(Game::Scr_GetInt(0), std::numeric_limits::min(), std::numeric_limits::max()); + const auto rightInt = std::clamp(Game::Scr_GetInt(1), std::numeric_limits::min(), std::numeric_limits::max()); g_botai[entref.entnum].forward = static_cast(forwardInt); g_botai[entref.entnum].right = static_cast(rightInt); @@ -327,6 +321,8 @@ namespace Components Bots::Bots() { + AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); + // 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\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\""); diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index 910bacfa..8bf9045c 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -14,6 +14,7 @@ namespace Components static void Spawn(unsigned int count); + static void GScr_isTestClient(Game::scr_entref_t entref); static void AddMethods(); static void BotAiAction(Game::client_t* cl); diff --git a/src/Components/Modules/Branding.cpp b/src/Components/Modules/Branding.cpp new file mode 100644 index 00000000..3a513af6 --- /dev/null +++ b/src/Components/Modules/Branding.cpp @@ -0,0 +1,122 @@ +#include + +namespace Components +{ + Dvar::Var Branding::CGDrawVersion; + Dvar::Var Branding::CGDrawVersionX; + Dvar::Var Branding::CGDrawVersionY; + Game::dvar_t** Branding::Version = reinterpret_cast(0x1AD7930); + + void Branding::CG_DrawVersion() + { + // Default values + constexpr auto fontScale = 0.25f; + constexpr auto maxChars = std::numeric_limits::max(); + // Default colours + constexpr Game::vec4_t shadowColor = {0.0f, 0.0f, 0.0f, 0.69f}; + constexpr Game::vec4_t color = {0.4f, 0.69f, 1.0f, 0.69f}; + + auto* const placement = Game::ScrPlace_GetUnsafeFullPlacement(); + auto* const font = Game::UI_GetFontHandle(placement, 0, 0.583f); + + const auto width = Game::UI_TextWidth((*Version)->current.string, 0, font, fontScale); + const auto height = Game::UI_TextHeight(font, fontScale); + + Game::UI_DrawText(placement, (*Version)->current.string, maxChars, font, 1.0f - (CGDrawVersionX.get() + static_cast(width)), + 1.0f - (CGDrawVersionY.get() + static_cast(height)), 3, 3, fontScale, shadowColor, 0); + Game::UI_DrawText(placement, (*Version)->current.string, maxChars, font, (0.0f - static_cast(width)) - CGDrawVersionX.get(), + (0.0f - static_cast(height)) - CGDrawVersionY.get(), 3, 3, fontScale, color, 0); + } + + void Branding::CG_DrawVersion_Hk(int localClientNum) + { + Utils::Hook::Call(0x4EFF80)(localClientNum); + + if (Branding::CGDrawVersion.get()) + { + Branding::CG_DrawVersion(); + } + } + + const char* Branding::GetBuildNumber() + { + return SHORTVERSION " latest " __DATE__ " " __TIME__; + } + + const char* Branding::GetVersionString() + { +#ifdef _DEBUG + const auto* buildType = "IW4x_DEV MP"; +#else + const auto* buildType = "IW4x MP"; +#endif + + // IW4x is technically a beta + const auto* result = Utils::String::VA("%s %s build %s %s", + buildType, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast(0x7170A0)); + + return result; + } + + void Branding::Dvar_SetVersionString(const Game::dvar_t* dvar, [[maybe_unused]] const char* value) + { + const auto* result = Branding::GetVersionString(); + Utils::Hook::Call(0x4A9580)(dvar, result); + } + + // Branding this might be a good idea in case this LSP logging ever gets turned on for some reason + void Branding::MSG_WriteVersionStringHeader(Game::msg_t* msg, [[maybe_unused]] const char* string) + { + const auto* result = Branding::GetVersionString(); + Utils::Hook::Call(0x463820)(msg, result); + } + + Game::dvar_t* Branding::Dvar_RegisterUIBuildLocation(const char* dvarName, [[maybe_unused]] float x, + [[maybe_unused]] float y, float min, float max, [[maybe_unused]] int flags, const char* description) + { + return Game::Dvar_RegisterVec2(dvarName, -60.0f, + 474.0f, min, max, Game::dvar_flag::DVAR_READONLY, description); + } + + void Branding::RegisterBrandingDvars() + { +#ifdef _DEBUG + constexpr auto value = true; +#else + constexpr auto value = false; +#endif + Branding::CGDrawVersion = Dvar::Register("cg_drawVersion", value, + Game::dvar_flag::DVAR_NONE, "Draw the game version"); + Branding::CGDrawVersionX = Dvar::Register("cg_drawVersionX", 10.0f, + 0.0f, 512.0f, Game::dvar_flag::DVAR_NONE, "X offset for the version string"); + Branding::CGDrawVersionY = Dvar::Register("cg_drawVersionY", 455.0f, + 0.0f, 512.0f, Game::dvar_flag::DVAR_NONE, "Y offset for the version string"); + } + + Branding::Branding() + { + Dvar::OnInit(Branding::RegisterBrandingDvars); + + // UI version string + Utils::Hook::Set(0x43F73B, "IW4x: " VERSION); + + // Short version dvar + Utils::Hook::Set(0x60BD91, SHORTVERSION); + + Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick(); + + // Version string color + static Game::vec4_t buildLocColor = {1.0f, 1.0f, 1.0f, 0.8f}; + Utils::Hook::Set(0x43F710, buildLocColor); + + // Place ui version string to bottom right corner (ui_buildlocation) + Utils::Hook(0x6310A0, Branding::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); // Dvar_RegisterVec2 + + Utils::Hook(0x60BD81, Branding::Dvar_SetVersionString, HOOK_CALL).install()->quick(); + + Utils::Hook(0x4DA842, Branding::MSG_WriteVersionStringHeader, HOOK_CALL).install()->quick(); + + // Hook CG_DrawFullScreenDebugOverlays so we may render the version when it's appropriate + Utils::Hook(0x5AC975, Branding::CG_DrawVersion_Hk, HOOK_CALL).install()->quick(); + } +} diff --git a/src/Components/Modules/Branding.hpp b/src/Components/Modules/Branding.hpp new file mode 100644 index 00000000..b8424ae4 --- /dev/null +++ b/src/Components/Modules/Branding.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace Components +{ + class Branding : public Component + { + public: + Branding(); + + static const char* GetBuildNumber(); + static const char* GetVersionString(); + + private: + static Dvar::Var CGDrawVersion; + static Dvar::Var CGDrawVersionX; + static Dvar::Var CGDrawVersionY; + static Game::dvar_t** Version; + + static void CG_DrawVersion(); + static void CG_DrawVersion_Hk(int localClientNum); + + // Use IW4x Branding + static void Dvar_SetVersionString(const Game::dvar_t* dvar, const char* value); + static void MSG_WriteVersionStringHeader(Game::msg_t* msg, const char* string); + + static Game::dvar_t* Dvar_RegisterUIBuildLocation(const char* dvarName, float x, float y, float min, float max, int flags, const char* description); + + static void RegisterBrandingDvars(); + }; +} diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index 060fb81f..7d8436da 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -354,7 +354,7 @@ namespace Components } }); - Script::AddFunction("DropAllBots", []() // gsc: DropAllBots(); + Script::AddFunction("DropAllBots", [] // gsc: DropAllBots(); { Game::SV_DropAllBots(); }); diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index 6043607a..582bebb0 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -3,7 +3,9 @@ namespace Components { SteamID Dedicated::PlayerGuids[18][2]; + Dvar::Var Dedicated::SVRandomMapRotation; + Dvar::Var Dedicated::SVLanOnly; bool Dedicated::IsEnabled() { @@ -250,9 +252,15 @@ namespace Components } void Dedicated::Heartbeat() - { - int masterPort = Dvar::Var("masterPort").get(); - const char* masterServerName = Dvar::Var("masterServerName").get(); + { + // Do not send a heartbeat if sv_lanOnly is set to true + if (Dedicated::SVLanOnly.get()) + { + return; + } + + auto masterPort = Dvar::Var("masterPort").get(); + const auto* masterServerName = Dvar::Var("masterServerName").get(); Network::Address master(Utils::String::VA("%s:%u", masterServerName, masterPort)); @@ -290,7 +298,11 @@ namespace Components // Make sure all callbacks are handled Scheduler::OnFrame(Steam::SteamAPI_RunCallbacks); - Dvar::Register("sv_lanOnly", false, Game::dvar_flag::DVAR_NONE, "Don't act as node"); + Dvar::OnInit([] + { + Dedicated::SVLanOnly = Dvar::Register("sv_lanOnly", false, + Game::dvar_flag::DVAR_NONE, "Don't act as node"); + }); Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Dedicated.hpp b/src/Components/Modules/Dedicated.hpp index cfcbc539..80b39795 100644 --- a/src/Components/Modules/Dedicated.hpp +++ b/src/Components/Modules/Dedicated.hpp @@ -8,6 +8,7 @@ namespace Components Dedicated(); static SteamID PlayerGuids[18][2]; + static Dvar::Var SVLanOnly; static bool IsEnabled(); diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index c9d875da..5865d569 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -964,7 +964,7 @@ namespace Components Download::ScriptDownloads.clear(); }); - Script::AddFunction("HttpGet", []() + Script::AddFunction("HttpGet", [] { if (!Flags::HasFlag("scriptablehttp")) return; @@ -985,7 +985,7 @@ namespace Components Game::RemoveRefToObject(object); }); - Script::AddFunction("HttpCancel", []() + Script::AddFunction("HttpCancel", [] { if (!Flags::HasFlag("scriptablehttp")) return; diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index 08dffeb7..6507f1f2 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -16,9 +16,9 @@ namespace Components const auto elevatorSetting = Elevators::BG_Elevators.get(); while (true) { - point[0] = ps->origin[0] + Game::CorrectSolidDeltas[i][0]; - point[1] = ps->origin[1] + Game::CorrectSolidDeltas[i][1]; - point[2] = ps->origin[2] + Game::CorrectSolidDeltas[i][2]; + point[0] = ps->origin[0] + (*Game::CorrectSolidDeltas)[i][0]; + point[1] = ps->origin[1] + (*Game::CorrectSolidDeltas)[i][1]; + point[2] = ps->origin[2] + (*Game::CorrectSolidDeltas)[i][2]; Game::PM_playerTrace(pm, trace, point, point, &pm->bounds, ps->clientNum, pm->tracemask); @@ -40,8 +40,8 @@ namespace Components } } - i += 1; - if (i >= 26) + ++i; + if (i >= 26) // CorrectSolidDeltas count { ps->groundEntityNum = Game::ENTITYNUM_NONE; pml->groundPlane = 0; @@ -62,15 +62,15 @@ namespace Components return 1; } - void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* trace, const float* f3, - const float* f4, const Game::Bounds* bounds, int a6, int a7) + void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* results, const float* start, + const float* end, const Game::Bounds* bounds, int passEntityNum, int contentMask) { - Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7); + Game::PM_Trace(pm, results, start, end, bounds, passEntityNum, contentMask); // Allow the player to stand even when there is no headroom if (Elevators::BG_Elevators.get() == Elevators::EASY) { - trace->allsolid = false; + results->allsolid = false; } } @@ -111,8 +111,7 @@ namespace Components Elevators::ENABLED, Game::DVAR_CODINFO, "Elevators glitch settings"); }); - //Replace PM_CorrectAllSolid - Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); // PM_GroundTrace // Place hooks in PM_CheckDuck. If the elevators dvar is set to easy the // flags for duck/prone will always be removed from the player state diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index 572bfdfd..a58dfefa 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -193,24 +193,6 @@ namespace Components { Exception::SetMiniDumpType(Flags::HasFlag("bigminidumps"), Flags::HasFlag("reallybigminidumps")); -#ifdef DEBUG - // Display DEBUG branding, so we know we're on a debug build - Scheduler::OnFrame([]() - { - 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()) - { - color[0] = 0.6588f; - color[1] = 1.0000f; - color[2] = 0.0000f; - } - - Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED); - }, true); -#endif #if !defined(DEBUG) || defined(FORCE_EXCEPTION_HANDLER) Exception::SetFilterHook.initialize(SetUnhandledExceptionFilter, Exception::SetUnhandledExceptionFilterStub, HOOK_JUMP); Exception::SetFilterHook.install(); diff --git a/src/Components/Modules/Gamepad.cpp b/src/Components/Modules/Gamepad.cpp index ca170379..5a7a98b8 100644 --- a/src/Components/Modules/Gamepad.cpp +++ b/src/Components/Modules/Gamepad.cpp @@ -661,7 +661,8 @@ namespace Components Game::AimAssist_UpdateAdsLerp(input); AimAssist_ApplyTurnRates(input, output); - Game::AimAssist_ApplyAutoMelee(input, output); + // Automelee has already been done by keyboard so don't do it again + AimAssist_ApplyLockOn(input, output); } @@ -886,8 +887,6 @@ namespace Components AimAssist_UpdateGamePadInput(&aimInput, &aimOutput); clientActive.clViewangles[0] = aimOutput.pitch; clientActive.clViewangles[1] = aimOutput.yaw; - cmd->meleeChargeDist = aimOutput.meleeChargeDist; - cmd->meleeChargeYaw = aimOutput.meleeChargeYaw; } } @@ -1033,6 +1032,13 @@ namespace Components void Gamepad::UI_GamepadKeyEvent(const int gamePadIndex, const int key, const bool down) { + // If we are currently capturing a key for menu bind inputs then do not map keys and pass to game + if (*Game::g_waitingForKey) + { + Game::UI_KeyEvent(gamePadIndex, key, down); + return; + } + for (const auto& mapping : controllerMenuKeyMappings) { if (mapping.controllerKey == key) @@ -1711,8 +1717,8 @@ namespace Components { gpad_enabled = Dvar::Register("gpad_enabled", false, Game::DVAR_ARCHIVE, "Game pad enabled"); gpad_debug = Dvar::Register("gpad_debug", false, Game::DVAR_NONE, "Game pad debugging"); - gpad_present = Dvar::Register("gpad_present", false, Game::DVAR_NONE, "Game pad present"); - gpad_in_use = Dvar::Register("gpad_in_use", false, Game::DVAR_NONE, "A game pad is in use"); + gpad_present = Dvar::Register("gpad_present", false, Game::DVAR_READONLY, "Game pad present"); + gpad_in_use = Dvar::Register("gpad_in_use", false, Game::DVAR_READONLY, "A game pad is in use"); gpad_style = Dvar::Register("gpad_style", false, Game::DVAR_ARCHIVE, "Switch between Xbox and PS HUD"); gpad_sticksConfig = Dvar::Register("gpad_sticksConfig", "", Game::DVAR_ARCHIVE, "Game pad stick configuration"); gpad_buttonConfig = Dvar::Register("gpad_buttonConfig", "", Game::DVAR_ARCHIVE, "Game pad button configuration"); @@ -1720,15 +1726,15 @@ namespace Components gpad_menu_scroll_delay_rest = Dvar::Register("gpad_menu_scroll_delay_rest", 210, 0, 1000, Game::DVAR_ARCHIVE, "Menu scroll key-repeat delay, for repeats after the first, in milliseconds"); gpad_rumble = Dvar::Register("gpad_rumble", true, Game::DVAR_ARCHIVE, "Enable game pad rumble"); - gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_NONE, + gpad_stick_pressed_hysteresis = Dvar::Register("gpad_stick_pressed_hysteresis", 0.1f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad stick pressed no-change-zone around gpad_stick_pressed to prevent bouncing"); - gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_NONE, "Game pad stick pressed threshhold"); - gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum stick deadzone"); - gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad minimum stick deadzone"); - gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad button deadzone threshhold"); - gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum pad stick pressed value"); - gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_NONE, "Game pad maximum pad stick pressed value"); - gpad_use_hold_time = Dvar::Register("gpad_use_hold_time", 250, 0, std::numeric_limits::max(), Game::DVAR_NONE, "Time to hold the 'use' button on gamepads to activate use"); + gpad_stick_pressed = Dvar::Register("gpad_stick_pressed", 0.4f, 0.0, 1.0, Game::DVAR_ARCHIVE, "Game pad stick pressed threshhold"); + gpad_stick_deadzone_max = Dvar::Register("gpad_stick_deadzone_max", 0.01f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum stick deadzone"); + gpad_stick_deadzone_min = Dvar::Register("gpad_stick_deadzone_min", 0.2f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad minimum stick deadzone"); + gpad_button_deadzone = Dvar::Register("gpad_button_deadzone", 0.13f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad button deadzone threshhold"); + gpad_button_lstick_deflect_max = Dvar::Register("gpad_button_lstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum pad stick pressed value"); + gpad_button_rstick_deflect_max = Dvar::Register("gpad_button_rstick_deflect_max", 1.0f, 0.0f, 1.0f, Game::DVAR_ARCHIVE, "Game pad maximum pad stick pressed value"); + gpad_use_hold_time = Dvar::Register("gpad_use_hold_time", 250, 0, std::numeric_limits::max(), Game::DVAR_ARCHIVE, "Time to hold the 'use' button on gamepads to activate use"); gpad_lockon_enabled = Dvar::Register("gpad_lockon_enabled", true, Game::DVAR_ARCHIVE, "Game pad lockon aim assist enabled"); gpad_slowdown_enabled = Dvar::Register("gpad_slowdown_enabled", true, Game::DVAR_ARCHIVE, "Game pad slowdown aim assist enabled"); @@ -1777,19 +1783,19 @@ namespace Components return command; } - int Gamepad::Key_GetCommandAssignmentInternal_Hk(const char* cmd, int (*keys)[2]) + int Gamepad::Key_GetCommandAssignmentInternal([[maybe_unused]] int localClientNum, const char* cmd, int (*keys)[2]) { auto keyCount = 0; if (gamePads[0].inUse) { - cmd = GetGamePadCommand(cmd); + const auto gamePadCmd = GetGamePadCommand(cmd); for (auto keyNum = 0; keyNum < Game::K_LAST_KEY; keyNum++) { if (!Key_IsValidGamePadChar(keyNum)) continue; - if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, cmd) == 0) + if (Game::playerKeys[0].keys[keyNum].binding && strcmp(Game::playerKeys[0].keys[keyNum].binding, gamePadCmd) == 0) { (*keys)[keyCount++] = keyNum; @@ -1818,6 +1824,35 @@ namespace Components return keyCount; } + void __declspec(naked) Gamepad::Key_GetCommandAssignmentInternal_Stub() + { + __asm + { + push eax + pushad + + push [esp + 0x20 + 0x4 + 0x8] // keyNums + push [esp + 0x20 + 0x4 + 0x8] // command + push eax // localClientNum + call Key_GetCommandAssignmentInternal + add esp, 0xC + + mov[esp + 0x20], eax + + popad + pop eax + ret + } + } + + void Gamepad::Key_SetBinding_Hk(const int localClientNum, const int keyNum, const char* binding) + { + if(Key_IsValidGamePadChar(keyNum)) + gpad_buttonConfig.set("custom"); + + Game::Key_SetBinding(localClientNum, keyNum, binding); + } + void Gamepad::CL_KeyEvent_Hk(const int localClientNum, const int key, const int down, const unsigned time) { // A keyboard key has been pressed. Mark controller as unused. @@ -1833,13 +1868,18 @@ namespace Components return gamePads[0].inUse; } - int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy) + void Gamepad::OnMouseMove([[maybe_unused]] const int x, [[maybe_unused]] const int y, const int dx, const int dy) { if (dx != 0 || dy != 0) { gamePads[0].inUse = false; gpad_in_use.setRaw(false); } + } + + int Gamepad::CL_MouseEvent_Hk(const int x, const int y, const int dx, const int dy) + { + OnMouseMove(x, y, dx, dy); // Call original function return Utils::Hook::Call(0x4D7C50)(x, y, dx, dy); @@ -1949,7 +1989,12 @@ namespace Components Utils::Hook(0x48E527, UI_RefreshViewport_Hk, HOOK_CALL).install()->quick(); // Only return gamepad keys when gamepad enabled and only non gamepad keys when not - Utils::Hook(0x5A7A23, Key_GetCommandAssignmentInternal_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x5A7890, Key_GetCommandAssignmentInternal_Stub, HOOK_JUMP).install()->quick(); + + // Whenever a key binding for a gamepad key is replaced update the button config + Utils::Hook(0x47D473, Key_SetBinding_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x47D485, Key_SetBinding_Hk, HOOK_CALL).install()->quick(); + Utils::Hook(0x47D49D, Key_SetBinding_Hk, HOOK_CALL).install()->quick(); // Add gamepad inputs to remote control (eg predator) handling Utils::Hook(0x5A6D4E, CL_RemoteControlMove_Stub, HOOK_CALL).install()->quick(); diff --git a/src/Components/Modules/Gamepad.hpp b/src/Components/Modules/Gamepad.hpp index 024d0c6a..2e55c67d 100644 --- a/src/Components/Modules/Gamepad.hpp +++ b/src/Components/Modules/Gamepad.hpp @@ -41,6 +41,8 @@ namespace Components public: Gamepad(); + static void OnMouseMove(int x, int y, int dx, int dy); + private: static Game::ButtonToCodeMap_t buttonList[]; static Game::StickToCodeMap_t analogStickList[4]; @@ -190,7 +192,9 @@ namespace Components static void CG_RegisterDvars_Hk(); static const char* GetGamePadCommand(const char* command); - static int Key_GetCommandAssignmentInternal_Hk(const char* cmd, int(*keys)[2]); + static int Key_GetCommandAssignmentInternal(int localClientNum, const char* cmd, int (*keys)[2]); + static void Key_GetCommandAssignmentInternal_Stub(); + static void Key_SetBinding_Hk(int localClientNum, int keyNum, const char* binding); static bool IsGamePadInUse(); static void CL_KeyEvent_Hk(int localClientNum, int key, int down, unsigned int time); static int CL_MouseEvent_Hk(int x, int y, int dx, int dy); diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 60d1d18b..6f112469 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -114,7 +114,7 @@ namespace Components void Node::StoreNodes(bool force) { - if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get()) return; + if (Dedicated::IsEnabled() && Dedicated::SVLanOnly.get()) return; static Utils::Time::Interval interval; if (!force && !interval.elapsed(1min)) return; @@ -167,13 +167,17 @@ namespace Components void Node::RunFrame() { - if (ServerList::useMasterServer) return; - if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").get()) return; + if (Dedicated::IsEnabled() && Dedicated::SVLanOnly.get()) return; - if (!Dedicated::IsEnabled() && *Game::clcState > 0) + if (!Dedicated::IsEnabled()) { - wasIngame = true; - return; // don't run while ingame because it can still cause lag spikes on lower end PCs + if (ServerList::useMasterServer) return; // don't run node frame if master server is active + + if (*Game::clcState > 0) + { + wasIngame = true; + return; // don't run while ingame because it can still cause lag spikes on lower end PCs + } } if (wasIngame) // our last frame we were ingame and now we aren't so touch all nodes diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 92e09546..c05eac23 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -229,12 +229,6 @@ 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_READONLY, description); - } - QuickPatch::QuickPatch() { // quitHard @@ -304,22 +298,6 @@ namespace Components // fs_basegame Utils::Hook::Set(0x6431D1, BASEGAME); - // UI version string - Utils::Hook::Set(0x43F73B, "IW4x: " VERSION); - - // console version string - Utils::Hook::Set(0x4B12BB, "IW4x " VERSION " (built " __DATE__ " " __TIME__ ")"); - - // version string - Utils::Hook::Set(0x60BD56, "IW4x (" VERSION ")"); - - // version string color - 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(0x6310A0, QuickPatch::Dvar_RegisterUIBuildLocation, HOOK_CALL).install()->quick(); - // console title if (ZoneBuilder::IsEnabled()) { @@ -340,9 +318,6 @@ namespace Components // sv_hostname Utils::Hook::Set(0x4D378B, "IW4Host"); - // shortversion - Utils::Hook::Set(0x60BD91, SHORTVERSION); - // console logo Utils::Hook::Set(0x428A66, BASEGAME "/images/logo.bmp"); diff --git a/src/Components/Modules/QuickPatch.hpp b/src/Components/Modules/QuickPatch.hpp index 62377cfd..b9b03407 100644 --- a/src/Components/Modules/QuickPatch.hpp +++ b/src/Components/Modules/QuickPatch.hpp @@ -27,7 +27,5 @@ namespace Components 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/RawMouse.cpp b/src/Components/Modules/RawMouse.cpp index 3f95a874..51cba280 100644 --- a/src/Components/Modules/RawMouse.cpp +++ b/src/Components/Modules/RawMouse.cpp @@ -97,6 +97,7 @@ namespace Components Game::s_wmv->oldPos = curPos; ScreenToClient(Window::GetWindow(), &curPos); + Gamepad::OnMouseMove(curPos.x, curPos.y, dx, dy); auto recenterMouse = Game::CL_MouseEvent(curPos.x, curPos.y, dx, dy); if (recenterMouse) diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 798a2541..dbe79ccc 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -431,7 +431,7 @@ namespace Components { std::memmove(&Game::scrVmPub->top[-4], &Game::scrVmPub->top[-5], sizeof(Game::VariableValue) * 6); Game::scrVmPub->top += 1; - Game::scrVmPub->top[-6].type = Game::VAR_FLOAT; + Game::scrVmPub->top[-6].type = Game::scrParamType_t::VAR_FLOAT; Game::scrVmPub->top[-6].u.floatValue = 0.0f; ++Game::scrVmPub->outparamcount; @@ -450,7 +450,7 @@ namespace Components const auto value = &Game::scrVmPub->top[-index]; - if (value->type != Game::VAR_FUNCTION) + if (value->type != Game::scrParamType_t::VAR_FUNCTION) { Game::Scr_ParamError(static_cast(index), "^1GetCodePosForParam: Expects a function as parameter!\n"); return ""; @@ -549,7 +549,7 @@ namespace Components void Script::AddFunctions() { - Script::AddFunction("ReplaceFunc", []() // gsc: ReplaceFunc(, ) + Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(, ) { if (Game::Scr_GetNumParam() != 2u) { @@ -564,15 +564,7 @@ namespace Components }); // System time - Script::AddFunction("GetSystemTime", []() // gsc: GetSystemTime() - { - SYSTEMTIME time; - GetSystemTime(&time); - - Game::Scr_AddInt(time.wSecond); - }); - - Script::AddFunction("GetSystemMilliseconds", []() // gsc: GetSystemMilliseconds() + Script::AddFunction("GetSystemMilliseconds", [] // gsc: GetSystemMilliseconds() { SYSTEMTIME time; GetSystemTime(&time); @@ -581,7 +573,7 @@ namespace Components }); // Executes command to the console - Script::AddFunction("Exec", []() // gsc: Exec() + Script::AddFunction("Exec", [] // gsc: Exec() { const auto str = Game::Scr_GetString(0); @@ -595,7 +587,7 @@ namespace Components }); // Allow printing to the console even when developer is 0 - Script::AddFunction("PrintConsole", []() // gsc: PrintConsole() + Script::AddFunction("PrintConsole", [] // gsc: PrintConsole() { for (auto i = 0u; i < Game::Scr_GetNumParam(); i++) { @@ -612,7 +604,7 @@ namespace Components }); // Script Storage Functions - Script::AddFunction("StorageSet", []() // gsc: StorageSet(, ); + Script::AddFunction("StorageSet", [] // gsc: StorageSet(, ); { const auto* key = Game::Scr_GetString(0); const auto* value = Game::Scr_GetString(1); @@ -626,7 +618,7 @@ namespace Components Script::ScriptStorage.insert_or_assign(key, value); }); - Script::AddFunction("StorageRemove", []() // gsc: StorageRemove(); + Script::AddFunction("StorageRemove", [] // gsc: StorageRemove(); { const auto* key = Game::Scr_GetString(0); @@ -645,7 +637,7 @@ namespace Components Script::ScriptStorage.erase(key); }); - Script::AddFunction("StorageGet", []() // gsc: StorageGet(); + Script::AddFunction("StorageGet", [] // gsc: StorageGet(); { const auto* key = Game::Scr_GetString(0); @@ -665,7 +657,7 @@ namespace Components Game::Scr_AddString(data.data()); }); - Script::AddFunction("StorageHas", []() // gsc: StorageHas(); + Script::AddFunction("StorageHas", [] // gsc: StorageHas(); { const auto* key = Game::Scr_GetString(0); @@ -678,7 +670,7 @@ namespace Components Game::Scr_AddBool(static_cast(Script::ScriptStorage.count(key))); // Until C++17 }); - Script::AddFunction("StorageClear", []() // gsc: StorageClear(); + Script::AddFunction("StorageClear", [] // gsc: StorageClear(); { Script::ScriptStorage.clear(); }); @@ -746,7 +738,7 @@ namespace Components }); #ifdef _DEBUG - Script::AddFunction("DebugBox", []() + Script::AddFunction("DebugBox", [] { const auto* message = Game::Scr_GetString(0); diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index 68e80a7a..31b55ae1 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -116,7 +116,7 @@ namespace Components void ScriptExtension::AddFunctions() { // File functions - Script::AddFunction("FileWrite", []() // gsc: FileWrite(, , ) + Script::AddFunction("FileWrite", [] // gsc: FileWrite(, , ) { const auto* path = Game::Scr_GetString(0); auto* text = Game::Scr_GetString(1); @@ -159,7 +159,7 @@ namespace Components } }); - Script::AddFunction("FileRead", []() // gsc: FileRead() + Script::AddFunction("FileRead", [] // gsc: FileRead() { const auto* path = Game::Scr_GetString(0); @@ -187,7 +187,7 @@ namespace Components Game::Scr_AddString(FileSystem::FileReader(path).getBuffer().data()); }); - Script::AddFunction("FileExists", []() // gsc: FileExists() + Script::AddFunction("FileExists", [] // gsc: FileExists() { const auto* path = Game::Scr_GetString(0); @@ -209,7 +209,7 @@ namespace Components Game::Scr_AddInt(FileSystem::FileReader(path).exists()); }); - Script::AddFunction("FileRemove", []() // gsc: FileRemove() + Script::AddFunction("FileRemove", [] // gsc: FileRemove() { const auto* path = Game::Scr_GetString(0); @@ -235,7 +235,7 @@ namespace Components }); // Misc functions - Script::AddFunction("ToUpper", []() // gsc: ToUpper() + Script::AddFunction("ToUpper", [] // gsc: ToUpper() { const auto scriptValue = Game::Scr_GetConstString(0); const auto* string = Game::SL_ConvertToString(scriptValue); @@ -280,7 +280,7 @@ namespace Components }); // Func present on IW5 - Script::AddFunction("StrICmp", []() // gsc: StrICmp(, ) + Script::AddFunction("StrICmp", [] // gsc: StrICmp(, ) { const auto value1 = Game::Scr_GetConstString(0); const auto value2 = Game::Scr_GetConstString(1); @@ -292,7 +292,7 @@ namespace Components }); // Func present on IW5 - Script::AddFunction("IsEndStr", []() // gsc: IsEndStr(, ) + Script::AddFunction("IsEndStr", [] // gsc: IsEndStr(, ) { const auto* s1 = Game::Scr_GetString(0); const auto* s2 = Game::Scr_GetString(1); @@ -305,6 +305,26 @@ namespace Components Game::Scr_AddBool(Utils::String::EndsWith(s1, s2)); }); + + Script::AddFunction("IsArray", [] // gsc: IsArray() + { + const auto type = Game::Scr_GetType(0); + + bool result; + if (type == Game::scrParamType_t::VAR_POINTER) + { + const auto ptr_type = Game::Scr_GetPointerType(0); + assert(ptr_type >= Game::FIRST_OBJECT); + result = (ptr_type == Game::scrParamType_t::VAR_ARRAY); + } + else + { + assert(type < Game::FIRST_OBJECT); + result = false; + } + + Game::Scr_AddBool(result); + }); } void ScriptExtension::AddMethods() diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index d6af313a..5bffcf9e 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -199,6 +199,11 @@ namespace Components } void ServerList::RefreshVisibleList(UIScript::Token) + { + ServerList::RefreshVisibleListInternal(UIScript::Token()); + } + + void ServerList::RefreshVisibleListInternal(UIScript::Token, bool refresh) { Dvar::Var("ui_serverSelected").set(false); @@ -207,6 +212,12 @@ namespace Components auto list = ServerList::GetList(); if (!list) return; + if (refresh) + { + ServerList::Refresh(UIScript::Token()); + return; + } + bool ui_browserShowFull = Dvar::Var("ui_browserShowFull").get(); bool ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get(); int ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get(); @@ -368,7 +379,7 @@ namespace Components auto list = ServerList::GetList(); if (list) list->clear(); - ServerList::RefreshVisibleList(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token()); Game::ShowMessageBox("Server removed from favourites.", "Success"); } @@ -530,7 +541,7 @@ namespace Components if (lList) { lList->push_back(server); - ServerList::RefreshVisibleList(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token()); } } @@ -693,7 +704,7 @@ namespace Components netSource.set(source); - ServerList::RefreshVisibleList(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token(), true); } void ServerList::UpdateGameType() @@ -709,7 +720,7 @@ namespace Components joinGametype.set(gametype); - ServerList::RefreshVisibleList(UIScript::Token()); + ServerList::RefreshVisibleListInternal(UIScript::Token()); } void ServerList::UpdateVisibleInfo() diff --git a/src/Components/Modules/ServerList.hpp b/src/Components/Modules/ServerList.hpp index 22754f7b..51f7a062 100644 --- a/src/Components/Modules/ServerList.hpp +++ b/src/Components/Modules/ServerList.hpp @@ -35,6 +35,7 @@ namespace Components static void Refresh(UIScript::Token); static void RefreshVisibleList(UIScript::Token); + 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); diff --git a/src/Components/Modules/Window.cpp b/src/Components/Modules/Window.cpp index 3661625b..04fa8f22 100644 --- a/src/Components/Modules/Window.cpp +++ b/src/Components/Modules/Window.cpp @@ -100,7 +100,7 @@ namespace Components } } - void Window::DrawCursorStub(void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Game::Material *material) + void Window::DrawCursorStub(Game::ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Game::Material* material) { if (Window::NativeCursor.get()) { diff --git a/src/Components/Modules/Window.hpp b/src/Components/Modules/Window.hpp index 9b0f09c6..9728fd21 100644 --- a/src/Components/Modules/Window.hpp +++ b/src/Components/Modules/Window.hpp @@ -40,7 +40,7 @@ namespace Components static BOOL WINAPI MessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); static int WINAPI ShowCursorHook(BOOL show); - static void DrawCursorStub(void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Game::Material *material); + static void DrawCursorStub(Game::ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Game::Material* material); static void StyleHookStub(); static HWND WINAPI CreateMainWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 5fb7505a..d7d00756 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -171,6 +171,7 @@ namespace Game Key_SetCatcher_t Key_SetCatcher = Key_SetCatcher_t(0x43BD00); Key_RemoveCatcher_t Key_RemoveCatcher = Key_RemoveCatcher_t(0x408260); Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive = Key_IsKeyCatcherActive_t(0x4DA010); + Key_SetBinding_t Key_SetBinding = Key_SetBinding_t(0x494C90); LargeLocalInit_t LargeLocalInit = LargeLocalInit_t(0x4A62A0); @@ -293,6 +294,7 @@ namespace Game Scr_ParamError_t Scr_ParamError = Scr_ParamError_t(0x4FBC70); Scr_GetType_t Scr_GetType = Scr_GetType_t(0x422900); + Scr_GetPointerType_t Scr_GetPointerType = Scr_GetPointerType_t(0x4828E0); Scr_ClearOutParams_t Scr_ClearOutParams = Scr_ClearOutParams_t(0x4386E0); @@ -385,6 +387,7 @@ namespace Game UI_DrawHandlePic_t UI_DrawHandlePic = UI_DrawHandlePic_t(0x4D0EA0); ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement = ScrPlace_GetActivePlacement_t(0x4F8940); UI_TextWidth_t UI_TextWidth = UI_TextWidth_t(0x6315C0); + UI_TextHeight_t UI_TextHeight = UI_TextHeight_t(0x4C8630); UI_DrawText_t UI_DrawText = UI_DrawText_t(0x49C0D0); UI_GetFontHandle_t UI_GetFontHandle = UI_GetFontHandle_t(0x4AEA60); ScrPlace_ApplyRect_t ScrPlace_ApplyRect = ScrPlace_ApplyRect_t(0x454E20); @@ -546,17 +549,21 @@ namespace Game FastCriticalSection* db_hashCritSect = reinterpret_cast(0x16B8A54); - vec3_t* CorrectSolidDeltas = reinterpret_cast(0x739BB8); // Count 26 + ScreenPlacement* scrPlaceFullUnsafe = reinterpret_cast(0x1084460); + + float (*CorrectSolidDeltas)[26][3] = reinterpret_cast(0x739BB8); // Count 26 level_locals_t* level = reinterpret_cast(0x1A831A8); - float(*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT] = reinterpret_cast(0x7C4878); + float (*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT] = reinterpret_cast(0x7C4878); WinMouseVars_t* s_wmv = reinterpret_cast(0x649D640); int* window_center_x = reinterpret_cast(0x649D638); int* window_center_y = reinterpret_cast(0x649D630); + int* g_waitingForKey = reinterpret_cast(0x63A50FC); + void Sys_LockRead(FastCriticalSection* critSect) { InterlockedIncrement(&critSect->readCount); @@ -1121,6 +1128,11 @@ namespace Game return GraphGetValueFromFraction(graph->knotCount, graph->knots, fraction) * graph->scale; } + ScreenPlacement* ScrPlace_GetUnsafeFullPlacement() + { + return scrPlaceFullUnsafe; + } + #pragma optimize("", off) __declspec(naked) float UI_GetScoreboardLeft(void* /*a1*/) { diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 4369bbad..47658d08 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -420,6 +420,9 @@ namespace Game typedef bool(__cdecl * Key_IsKeyCatcherActive_t)(int localClientNum, int catcher); extern Key_IsKeyCatcherActive_t Key_IsKeyCatcherActive; + typedef void(__cdecl * Key_SetBinding_t)(int localClientNum, int keyNum, const char* binding); + extern Key_SetBinding_t Key_SetBinding; + typedef void(__cdecl * LargeLocalInit_t)(); extern LargeLocalInit_t LargeLocalInit; @@ -735,9 +738,12 @@ namespace Game typedef bool(__cdecl * Scr_IsSystemActive_t)(); extern Scr_IsSystemActive_t Scr_IsSystemActive; - typedef int(__cdecl * Scr_GetType_t)(unsigned int); + typedef int(__cdecl * Scr_GetType_t)(unsigned int index); extern Scr_GetType_t Scr_GetType; + typedef int(__cdecl * Scr_GetPointerType_t)(unsigned int index); + extern Scr_GetPointerType_t Scr_GetPointerType; + typedef void(__cdecl * Scr_Error_t)(const char*); extern Scr_Error_t Scr_Error; @@ -885,7 +891,7 @@ namespace Game typedef bool(__cdecl * Sys_IsDatabaseThread_t)(); extern Sys_IsDatabaseThread_t Sys_IsDatabaseThread; - typedef char** (__cdecl * Sys_ListFiles_t)(const char *directory, const char *extension, const char *filter, int *numfiles, int wantsubs); + typedef char**(__cdecl * Sys_ListFiles_t)(const char* directory, const char* extension, const char* filter, int* numfiles, int wantsubs); extern Sys_ListFiles_t Sys_ListFiles; typedef int(__cdecl * Sys_Milliseconds_t)(); @@ -930,28 +936,31 @@ namespace Game typedef void(__cdecl * UI_SortArenas_t)(); extern UI_SortArenas_t UI_SortArenas; - typedef void(__cdecl * UI_DrawHandlePic_t)(/*ScreenPlacement*/void *scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float *color, Material *material); + typedef void(__cdecl * UI_DrawHandlePic_t)(ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Material* material); extern UI_DrawHandlePic_t UI_DrawHandlePic; typedef ScreenPlacement*(__cdecl * ScrPlace_GetActivePlacement_t)(int localClientNum); extern ScrPlace_GetActivePlacement_t ScrPlace_GetActivePlacement; - typedef int(__cdecl * UI_TextWidth_t)(const char *text, int maxChars, Font_s *font, float scale); + typedef int(__cdecl * UI_TextWidth_t)(const char* text, int maxChars, Font_s* font, float scale); extern UI_TextWidth_t UI_TextWidth; + typedef int(__cdecl * UI_TextHeight_t)(Font_s* font, float scale); + extern UI_TextHeight_t UI_TextHeight; + typedef void(__cdecl * UI_DrawText_t)(const ScreenPlacement* scrPlace, const char* text, int maxChars, Font_s* font, float x, float y, int horzAlign, int vertAlign, float scale, const float* color, int style); extern UI_DrawText_t UI_DrawText; typedef Font_s* (__cdecl* UI_GetFontHandle_t)(ScreenPlacement* scrPlace, int fontEnum, float scale); extern UI_GetFontHandle_t UI_GetFontHandle; - typedef void(__cdecl* ScrPlace_ApplyRect_t)(ScreenPlacement* a1, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign); + typedef void(__cdecl* ScrPlace_ApplyRect_t)(const ScreenPlacement* scrPlace, float* x, float* y, float* w, float* h, int horzAlign, int vertAlign); extern ScrPlace_ApplyRect_t ScrPlace_ApplyRect; - typedef const char * (__cdecl * Win_GetLanguage_t)(); + typedef const char*(__cdecl * Win_GetLanguage_t)(); extern Win_GetLanguage_t Win_GetLanguage; - typedef void (__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t *); + typedef void(__cdecl * Vec3UnpackUnitVec_t)(PackedUnitVec, vec3_t*); extern Vec3UnpackUnitVec_t Vec3UnpackUnitVec; typedef float(__cdecl * vectoyaw_t)(vec2_t* vec); @@ -996,10 +1005,10 @@ namespace Game typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps); extern Jump_ClearState_t Jump_ClearState; - typedef void(__cdecl * PM_playerTrace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); + typedef void(__cdecl * PM_playerTrace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask); extern PM_playerTrace_t PM_playerTrace; - typedef void(__cdecl * PM_Trace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); + typedef void(__cdecl * PM_Trace_t)(pmove_s* pm, trace_t* results, const float* start, const float* end, const Bounds* bounds, int passEntityNum, int contentMask); extern PM_Trace_t PM_Trace; typedef EffectiveStance(__cdecl * PM_GetEffectiveStance_t)(const playerState_s* ps); @@ -1142,24 +1151,30 @@ namespace Game constexpr auto MAX_MODELS = 512; extern XModel** cached_models; - extern vec3_t* CorrectSolidDeltas; + extern float (*CorrectSolidDeltas)[26][3]; extern FastCriticalSection* db_hashCritSect; + extern ScreenPlacement* scrPlaceFullUnsafe; + extern level_locals_t* level; - extern float(*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT]; + extern float (*penetrationDepthTable)[PENETRATE_TYPE_COUNT][SURF_TYPE_COUNT]; extern WinMouseVars_t* s_wmv; extern int* window_center_x; extern int* window_center_y; + extern int* g_waitingForKey; + void Sys_LockRead(FastCriticalSection* critSect); void Sys_UnlockRead(FastCriticalSection* critSect); XModel* G_GetModel(int index); + ScreenPlacement* ScrPlace_GetUnsafeFullPlacement(); + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); void Menu_FreeItemMemory(Game::itemDef_s* item); void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index e0eb5dcc..f30a607d 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -234,7 +234,7 @@ namespace Game CS_ACTIVE = 0x5, } clientstate_t; - typedef enum + enum errorParm_t { ERR_FATAL = 0x0, ERR_DROP = 0x1, @@ -244,7 +244,39 @@ namespace Game ERR_SCRIPT_DROP = 0x5, ERR_LOCALIZATION = 0x6, ERR_MAPLOADERRORSUMMARY = 0x7 - } errorParm_t; + }; + + enum conChannel_t + { + CON_CHANNEL_DONT_FILTER, + CON_CHANNEL_ERROR, + CON_CHANNEL_GAMENOTIFY, + CON_CHANNEL_BOLDGAME, + CON_CHANNEL_SUBTITLE, + CON_CHANNEL_OBITUARY, + CON_CHANNEL_LOGFILEONLY, + CON_CHANNEL_CONSOLEONLY, + CON_CHANNEL_GFX, + CON_CHANNEL_SOUND, + CON_CHANNEL_FILES, + CON_CHANNEL_DEVGUI, + CON_CHANNEL_PROFILE, + CON_CHANNEL_UI, + CON_CHANNEL_CLIENT, + CON_CHANNEL_SERVER, + CON_CHANNEL_SYSTEM, + CON_CHANNEL_PLAYERWEAP, + CON_CHANNEL_AI, + CON_CHANNEL_ANIM, + CON_CHANNEL_PHYS, + CON_CHANNEL_FX, + CON_CHANNEL_LEADERBOARDS, + CON_CHANNEL_PARSERSCRIPT, + CON_CHANNEL_SCRIPT, + CON_CHANNEL_NETWORK, + + CON_BUILTIN_CHANNEL_COUNT, + }; enum entityFlag { @@ -5096,7 +5128,7 @@ namespace Game char buf[1]; }; - enum VariableType + enum scrParamType_t { VAR_UNDEFINED = 0x0, VAR_BEGIN_REF = 0x1, @@ -5114,21 +5146,30 @@ namespace Game VAR_BUILTIN_METHOD = 0xB, VAR_STACK = 0xC, VAR_ANIMATION = 0xD, - VAR_PRE_ANIMATION = 0xE, - VAR_THREAD = 0xF, - VAR_NOTIFY_THREAD = 0x10, - VAR_TIME_THREAD = 0x11, - VAR_CHILD_THREAD = 0x12, - VAR_OBJECT = 0x13, - VAR_DEAD_ENTITY = 0x14, - VAR_ENTITY = 0x15, - VAR_ARRAY = 0x16, - VAR_DEAD_THREAD = 0x17, - VAR_COUNT = 0x18, - VAR_FREE = 0x18, - VAR_THREAD_LIST = 0x19, - VAR_ENDON_LIST = 0x1A, - VAR_TOTAL_COUNT = 0x1B, + VAR_DEVELOPER_CODEPOS = 0xE, + VAR_PRE_ANIMATION = 0xF, + VAR_THREAD = 0x10, + VAR_NOTIFY_THREAD = 0x11, + VAR_TIME_THREAD = 0x12, + VAR_CHILD_THREAD = 0x13, + VAR_OBJECT = 0x14, + VAR_DEAD_ENTITY = 0x15, + VAR_ENTITY = 0x16, + VAR_ARRAY = 0x17, + VAR_DEAD_THREAD = 0x18, + VAR_COUNT = 0x19, + VAR_THREAD_LIST = 0x1A, + VAR_ENDON_LIST = 0x1B, + }; + + enum $2441F0C7E439C64E6C27842ECB570A7C + { + FIRST_OBJECT = 0x10, + FIRST_CLEARABLE_OBJECT = 0x14, + LAST_NONENTITY_OBJECT = 0x14, + FIRST_ENTITY_OBJECT = 0x16, + FIRST_NONFIELD_OBJECT = 0x17, + FIRST_DEAD_OBJECT = 0x18, }; union VariableUnion @@ -5147,7 +5188,7 @@ namespace Game struct VariableValue { VariableUnion u; - VariableType type; + scrParamType_t type; }; struct function_stack_t