diff --git a/src/game/client/cdll_int.cpp b/src/game/client/cdll_int.cpp index 9936fa2..06641ff 100644 --- a/src/game/client/cdll_int.cpp +++ b/src/game/client/cdll_int.cpp @@ -281,6 +281,7 @@ int CL_DLLEXPORT HUD_VidInit(void) gHUD.VidInit(); g_StudioRenderer.InitOnConnect(); PM_ResetBHopDetection(); + PM_ResetUseSlowDownDetection(); CResults::Get().Stop(); GetClientVoiceMgr()->VidInit(); diff --git a/src/game/client/hud.cpp b/src/game/client/hud.cpp index a510698..b47f8bd 100644 --- a/src/game/client/hud.cpp +++ b/src/game/client/hud.cpp @@ -160,17 +160,11 @@ static Color s_DefaultColorCodeColors[10] = { const Color NoTeamColor::Orange = Color(255, 178, 0, 255); const Color NoTeamColor::White = Color(216, 216, 216, 255); -CON_COMMAND(bhop_reset, "Resets BHop auto-detection if it was detected incorrectly") +CON_COMMAND(pm_reset, "Resets player movement settings if they were detected incorrectly") { - if (gHUD.GetBHopCapState() != EBHopCap::AutoDetect) - { - ConPrintf("BHop auto-detection is disabled, nothing was done.\n"); - } - else - { - PM_ResetBHopDetection(); - ConPrintf("BHop auto-detection reset.\n"); - } + PM_ResetBHopDetection(); + PM_ResetUseSlowDownDetection(); + ConPrintf("Player movement settings reset.\n"); } // inputw32.cpp diff --git a/src/game/client/hud_redraw.cpp b/src/game/client/hud_redraw.cpp index 0bf0206..7430918 100644 --- a/src/game/client/hud_redraw.cpp +++ b/src/game/client/hud_redraw.cpp @@ -41,7 +41,7 @@ extern ConVar zoom_sensitivity_ratio; ConVar hud_colortext("hud_colortext", "1", FCVAR_BHL_ARCHIVE); ConVar hud_takesshots("hud_takesshots", "0", FCVAR_ARCHIVE, "Whether or not to automatically take screenshots at the end of a round"); ConVar default_fov("default_fov", "90", FCVAR_ARCHIVE | FCVAR_BHL_ARCHIVE, "Default horizontal field of view"); -ConVar cl_useslowdown("cl_useslowdown", "1", FCVAR_BHL_ARCHIVE, "Slowdown behavior on +USE. 0 - Old. 1 - New"); +ConVar cl_useslowdown("cl_useslowdown", "2", FCVAR_BHL_ARCHIVE, "Slowdown behavior on +USE. 0 - Old. 1 - New. 2 - Auto-detect."); // Think void CHud::Think(void) diff --git a/src/pm_shared/pm_shared.cpp b/src/pm_shared/pm_shared.cpp index 14d94c9..1247b71 100644 --- a/src/pm_shared/pm_shared.cpp +++ b/src/pm_shared/pm_shared.cpp @@ -173,12 +173,36 @@ EUseSlowDownType PM_GetUseSlowDownType() void PM_SetUseSlowDownType(EUseSlowDownType value) { +#ifdef CLIENT_DLL + if (s_nUseSlowDownType != EUseSlowDownType::AutoDetect && value == EUseSlowDownType::AutoDetect) + PM_ResetUseSlowDownDetection(); +#endif + s_nUseSlowDownType = value; } #ifdef CLIENT_DLL static constexpr float BHOP_DETECT_DELAY = 0.3f; +static constexpr float USE_SLOWDOWN_DETECT_MIN = 0.25f; +static constexpr float USE_SLOWDOWN_DETECT_MAX = 0.4f; + +enum class EUseSlowDownDetectionState +{ + None, + + //! speed < USE_SLOWDOWN_DETECT_MIN * maxSpeed + LowSpeed, + + //! USE_SLOWDOWN_DETECT_MIN * maxSpeed <= speed < USE_SLOWDOWN_DETECT_MAX * maxSpeed + MidSpeed, + + //! speed >= USE_SLOWDOWN_DETECT_MAX * maxSpeed + HighSpeed, + + //! Successfully detected the server mode. + Done, +}; static int s_iOnGround; static int s_iWaterlevel; @@ -186,6 +210,9 @@ static int s_iMoveType; static EBHopCap s_iBHopState = EBHopCap::Enabled; static float s_flBHopCheckTime = 0.0f; +static EUseSlowDownDetectionState s_nUseSlowDownDetectionState = EUseSlowDownDetectionState::None; +static int s_iUseSlowDownCount = 0; + int PM_GetOnGround() { return s_iOnGround; @@ -222,6 +249,12 @@ void PM_ResetBHopDetection() } } +void PM_ResetUseSlowDownDetection() +{ + s_nUseSlowDownDetectionState = EUseSlowDownDetectionState::None; + s_iUseSlowDownCount = 0; +} + #else int PM_GetBHopCapEnabled() @@ -236,6 +269,27 @@ void PM_SetBHopCapEnabled(int state) #endif +static EUseSlowDownType PM_GetActualUseSlowDownType() +{ +#ifdef CLIENT_DLL + if (s_nUseSlowDownType == EUseSlowDownType::AutoDetect) + { + if (s_nUseSlowDownDetectionState == EUseSlowDownDetectionState::Done) + { + // Detected that the server uses Old method + return EUseSlowDownType::Old; + } + else + { + // Not yet detected or the server uses New + return EUseSlowDownType::New; + } + } +#endif + + return s_nUseSlowDownType; +} + void PM_SwapTextures(int i, int j) { char chTemp; @@ -3005,7 +3059,7 @@ void PM_CheckParamters(void) // // JoshA: Moved this to CheckParamters rather than working on the velocity, // as otherwise it affects every integration step incorrectly. - if (s_nUseSlowDownType == EUseSlowDownType::New && (pmove->onground != -1) && (pmove->cmd.buttons & IN_USE)) + if (PM_GetActualUseSlowDownType() == EUseSlowDownType::New && (pmove->onground != -1) && (pmove->cmd.buttons & IN_USE)) { pmove->maxspeed *= 1.0f / 3.0f; } @@ -3185,11 +3239,70 @@ void PM_PlayerMove(qboolean server) } } - // Slow down, I'm pulling it! (a box maybe) but only when I'm standing on ground - if (s_nUseSlowDownType == EUseSlowDownType::Old && (pmove->onground != -1) && (pmove->cmd.buttons & IN_USE)) + if ((pmove->onground != -1) && (pmove->cmd.buttons & IN_USE)) { - VectorScale(pmove->velocity, 0.3, pmove->velocity); + if (PM_GetActualUseSlowDownType() == EUseSlowDownType::Old) + { + // Slow down, I'm pulling it! (a box maybe) but only when I'm standing on ground + VectorScale(pmove->velocity, 0.3, pmove->velocity); + } +#ifdef CLIENT_DLL + else if (s_nUseSlowDownType == EUseSlowDownType::AutoDetect && + s_nUseSlowDownDetectionState != EUseSlowDownDetectionState::Done) + { + if (pmove->cmd.buttons & (IN_FORWARD | IN_FORWARD | IN_MOVELEFT | IN_MOVERIGHT) && + pmove->velocity.Length2DSqr() >= 25.0f) + { + // We're moving in some direction. Try to auto-detect server's +use slowdown type + EUseSlowDownDetectionState oldState = s_nUseSlowDownDetectionState; + EUseSlowDownDetectionState newState = EUseSlowDownDetectionState::None; + float speed = pmove->velocity.Length2D(); + + if (speed >= USE_SLOWDOWN_DETECT_MAX * pmove->maxspeed) + newState = EUseSlowDownDetectionState::HighSpeed; + else if (speed >= USE_SLOWDOWN_DETECT_MIN * pmove->maxspeed) + newState = EUseSlowDownDetectionState::MidSpeed; + else + newState = EUseSlowDownDetectionState::LowSpeed; + + if (oldState == EUseSlowDownDetectionState::HighSpeed && newState == EUseSlowDownDetectionState::LowSpeed) + { + // Sudden slow down. This occurs when the client re-synchronizes with the server. + s_iUseSlowDownCount++; + } + else if (oldState == EUseSlowDownDetectionState::LowSpeed && newState == EUseSlowDownDetectionState::HighSpeed) + { + // Sudden speed up. Something went wrong. + PM_ResetUseSlowDownDetection(); + } + + if (s_iUseSlowDownCount >= 5) + { + // Slow down has happened a few times. Assume the server uses the old method. + PM_ResetUseSlowDownDetection(); + pmove->Con_Printf("Setting +use slowdown to Old to match the server\n"); + s_nUseSlowDownDetectionState = EUseSlowDownDetectionState::Done; + } + else + { + s_nUseSlowDownDetectionState = newState; + } + } + else + { + // Reset auto-detection + PM_ResetUseSlowDownDetection(); + } + } +#endif + } +#ifdef CLIENT_DLL + else if (s_nUseSlowDownDetectionState != EUseSlowDownDetectionState::Done) + { + // Reset auto-detection + PM_ResetUseSlowDownDetection(); } +#endif // Handle movement switch (pmove->movetype) diff --git a/src/pm_shared/pm_shared.h b/src/pm_shared/pm_shared.h index 45e3355..652ddc6 100644 --- a/src/pm_shared/pm_shared.h +++ b/src/pm_shared/pm_shared.h @@ -29,8 +29,18 @@ enum class EUseSlowDownType //! Player slowly slows down if +use is held down. New, +#ifdef CLIENT_DLL + //! Detect automatically. + AutoDetect, +#endif + +#ifdef CLIENT_DLL + _Min = Old, + _Max = AutoDetect, +#else _Min = Old, _Max = New, +#endif }; void PM_Init(struct playermove_s *ppmove); @@ -59,6 +69,7 @@ int PM_GetMoveType(); EBHopCap PM_GetBHopCapState(); void PM_SetBHopCapState(EBHopCap state); void PM_ResetBHopDetection(); +void PM_ResetUseSlowDownDetection(); #else int PM_GetBHopCapEnabled(); void PM_SetBHopCapEnabled(int state);