From e491d15ff9dee7985467f1fad160712a65623d12 Mon Sep 17 00:00:00 2001 From: Mitch Richters Date: Fri, 12 Nov 2021 18:59:52 +1100 Subject: [PATCH] - Move `InputScale()` out of inputstate.cpp and into `i_time.cpp` as `I_GetInputFrac()` to make it available to GZDoom for potential future requirements. * As part of this, feed the output of `I_GetInputFrac()` to `gi->GetInput()` instead of having each game's virtual override calling it locally. --- source/common/utility/i_time.cpp | 37 +++++++++++++++++++++++++++++ source/common/utility/i_time.h | 6 +++++ source/core/d_net.cpp | 1 + source/core/gamecontrol.cpp | 1 - source/core/gamecvars.cpp | 1 - source/core/gamecvars.h | 1 - source/core/gameinput.cpp | 8 +++---- source/core/gamestruct.h | 2 +- source/core/inputstate.cpp | 28 ---------------------- source/core/inputstate.h | 2 -- source/core/mainloop.cpp | 4 ++-- source/games/blood/src/blood.h | 2 +- source/games/blood/src/controls.cpp | 3 +-- source/games/duke/src/duke3d.h | 2 +- source/games/duke/src/input.cpp | 6 ++--- source/games/exhumed/src/exhumed.h | 2 +- source/games/exhumed/src/input.cpp | 11 ++++----- source/games/sw/src/game.cpp | 1 - source/games/sw/src/game.h | 2 +- source/games/sw/src/input.cpp | 3 +-- 20 files changed, 63 insertions(+), 60 deletions(-) diff --git a/source/common/utility/i_time.cpp b/source/common/utility/i_time.cpp index cc8f5f1de..93b3dac89 100644 --- a/source/common/utility/i_time.cpp +++ b/source/common/utility/i_time.cpp @@ -46,6 +46,7 @@ static uint64_t FirstFrameStartTime; static uint64_t CurrentFrameStartTime; static uint64_t FreezeTime; +static double lastinputtime; int GameTicRate = 35; // make sure it is not 0, even if the client doesn't set it. double TimeScale = 1.0; @@ -195,3 +196,39 @@ void I_ResetFrameTime() I_SetFrameTime(); FirstFrameStartTime += (CurrentFrameStartTime - ft); } + +double I_GetInputFrac(bool const synchronised, double const ticrate) +{ + if (!synchronised) + { + const double max = 1000. / ticrate; + const double now = I_msTimeF(); + const double elapsedInputTicks = std::min(now - lastinputtime, max); + lastinputtime = now; + + if (elapsedInputTicks < max) + { + // Calculate an amplification to apply to the result before returning, + // factoring in the game's ticrate and the value of the result. + // This rectifies a deviation of 100+ ms or more depending on the length + // of the operation to be within 1-2 ms of synchronised input + // from 60 fps to at least 1000 fps at ticrates of 30 and 40 Hz. + const double result = elapsedInputTicks * ticrate / 1000.; + return result * (1. + 0.35 * (1. - ticrate / 50.) * (1. - result)); + } + else + { + return 1; + } + } + else + { + return 1; + } +} + +void I_ResetInputTime() +{ + // Reset lastinputtime to current time. + lastinputtime = I_msTimeF(); +} diff --git a/source/common/utility/i_time.h b/source/common/utility/i_time.h index 27ebdae2a..dc0619c37 100644 --- a/source/common/utility/i_time.h +++ b/source/common/utility/i_time.h @@ -38,3 +38,9 @@ uint64_t I_nsTime(); // Reset the timer after a lengthy operation void I_ResetFrameTime(); + +// Return a decimal fraction to scale input operations at framerate +double I_GetInputFrac(bool const synchronised, double const ticrate = GameTicRate); + +// Reset the last input check to after a lengthy operation +void I_ResetInputTime(); diff --git a/source/core/d_net.cpp b/source/core/d_net.cpp index af8e3bc94..33cc07970 100644 --- a/source/core/d_net.cpp +++ b/source/core/d_net.cpp @@ -1983,6 +1983,7 @@ void Net_SkipCommand (int cmd, uint8_t **stream) void Net_ClearFifo(void) { I_SetFrameTime(); + I_ResetInputTime(); gametime = I_GetTime(); } diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index f5d62542e..94137dac7 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -1024,7 +1024,6 @@ int RunGame() playername = userConfig.CommandName; } GameTicRate = 30; - InputScalePercentage = 0.14125; CheckUserMap(); palindexmap[0] = 255; diff --git a/source/core/gamecvars.cpp b/source/core/gamecvars.cpp index ca382e33b..6aed8da83 100644 --- a/source/core/gamecvars.cpp +++ b/source/core/gamecvars.cpp @@ -89,7 +89,6 @@ CVARD(Bool, cl_bloodqavinterp, true, CVAR_ARCHIVE, "enable/disable Blood's QAV i CVARD(Bool, cl_bloodweapinterp, false, CVAR_ARCHIVE, "enable/disable Blood's weapon interpolation. Depends on 'cl_bloodqavinterp'") CVARD(Bool, cl_bloodoldweapbalance, false, CVAR_ARCHIVE, "enable/disable legacy 1.0 weapon handling for Blood") CVARD(Bool, cl_loadingscreens, true, CVAR_ARCHIVE, "enable/disable loading screens for games") -CVARD(Bool, cl_preciseinputscaling, true, CVAR_ARCHIVE, "enable/disable precise scaling of unsynchronised input fraction") CUSTOM_CVARD(Int, cl_autoaim, 1, CVAR_ARCHIVE|CVAR_USERINFO, "enable/disable weapon autoaim") diff --git a/source/core/gamecvars.h b/source/core/gamecvars.h index 6a3533602..2bf23359f 100644 --- a/source/core/gamecvars.h +++ b/source/core/gamecvars.h @@ -34,7 +34,6 @@ EXTERN_CVAR(Bool, cl_bloodqavinterp) EXTERN_CVAR(Bool, cl_bloodweapinterp) EXTERN_CVAR(Bool, cl_bloodoldweapbalance) EXTERN_CVAR(Bool, cl_loadingscreens) -EXTERN_CVAR(Bool, cl_preciseinputscaling) EXTERN_CVAR(Bool, demorec_seeds_cvar) EXTERN_CVAR(Bool, demoplay_diffs) diff --git a/source/core/gameinput.cpp b/source/core/gameinput.cpp index 2a0ba5189..8310db3a7 100644 --- a/source/core/gameinput.cpp +++ b/source/core/gameinput.cpp @@ -188,16 +188,14 @@ void processMovement(InputPacket* const currInput, InputPacket* const inputBuffe if (turnleft || turnright) { - double const turnamount = hidspeed * turnscale; - double const preambleturn = turnamount * (double(PREAMBLEBASE) / double(NORMALTURNBASE)); - updateTurnHeldAmt(scaleAdjust); + float const turnamount = float(scaleAdjust * hidspeed * turnscale * (isTurboTurnTime() ? 1. : double(PREAMBLEBASE) / double(NORMALTURNBASE))); if (turnleft) - currInput->avel -= float(scaleAdjust * (isTurboTurnTime() ? turnamount : preambleturn)); + currInput->avel -= turnamount; if (turnright) - currInput->avel += float(scaleAdjust * (isTurboTurnTime() ? turnamount : preambleturn)); + currInput->avel += turnamount; } else { diff --git a/source/core/gamestruct.h b/source/core/gamestruct.h index c1212b088..851fcf4ab 100644 --- a/source/core/gamestruct.h +++ b/source/core/gamestruct.h @@ -89,7 +89,7 @@ struct GameInterface virtual FString GetCoordString() { return "'stat coord' not implemented"; } virtual void ExitFromMenu() { throw CExitEvent(0); } virtual ReservedSpace GetReservedScreenSpace(int viewsize) { return { 0, 0 }; } - virtual void GetInput(InputPacket* packet, ControlInfo* const hidInput) {} + virtual void GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet = nullptr) {} virtual void UpdateSounds() {} virtual void ErrorCleanup() {} virtual void Startup() {} diff --git a/source/core/inputstate.cpp b/source/core/inputstate.cpp index c0b55dec5..73ee6dbe7 100644 --- a/source/core/inputstate.cpp +++ b/source/core/inputstate.cpp @@ -48,10 +48,8 @@ static int WeaponToSend = 0; ESyncBits ActionsToSend = 0; static int dpad_lock = 0; -double InputScalePercentage = 0; bool sendPause; bool crouch_toggle; -static double lastCheck; CVAR(Float, m_pitch, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) // Mouse speeds CVAR(Float, m_yaw, 1.f, CVAR_GLOBALCONFIG | CVAR_ARCHIVE) @@ -122,7 +120,6 @@ void InputState::ClearAllInput() AnyKeyStatus = false; WeaponToSend = 0; dpad_lock = 0; - lastCheck = 0; if (gamestate != GS_LEVEL) { @@ -471,30 +468,5 @@ void ApplyGlobalInput(InputPacket& input, ControlInfo* hidInput, bool const crou if (buttonMap.ButtonDown(gamefunc_Look_Right)) input.actions |= SB_LOOK_RIGHT; - -} - -double InputScale() -{ - if (!SyncInput()) - { - const double max = 1000. / GameTicRate; - const double now = I_msTimeF(); - const double elapsedInputTicks = lastCheck > 0 ? min(now - lastCheck, max) : 1.; - lastCheck = now; - if (elapsedInputTicks == max) return 1; - - // Calculate a scale increase of the percentage InputScalePercentage is set as to correct an - // inherent drift in this function that progressively causes the actions that depend - // on this fractional scale to increase by over 100 ms as the framerate increases. - // This isn't pretty, but it's accurate to within 1-2 ms from 60 fps to at least 1000 fps. - const double result = elapsedInputTicks * GameTicRate / 1000.; - const double scaler = cl_preciseinputscaling ? 1. + InputScalePercentage * (1. - result) : 1.; - return result * scaler; - } - else - { - return 1; - } } diff --git a/source/core/inputstate.h b/source/core/inputstate.h index 3fc113158..a9dd388ba 100644 --- a/source/core/inputstate.h +++ b/source/core/inputstate.h @@ -104,9 +104,7 @@ enum GameFunction_t void SetupGameButtons(); void ApplyGlobalInput(InputPacket& input, ControlInfo* const hidInput, bool const crouchable = true, bool const disableToggle = false); extern ESyncBits ActionsToSend; -double InputScale(); extern bool gamesetinput; -extern double InputScalePercentage; inline bool SyncInput() { diff --git a/source/core/mainloop.cpp b/source/core/mainloop.cpp index 1ee2585cc..05b94a5b6 100644 --- a/source/core/mainloop.cpp +++ b/source/core/mainloop.cpp @@ -133,7 +133,7 @@ void G_BuildTiccmd(ticcmd_t* cmd) cmd->ucmd = {}; I_GetEvent(); auto input = CONTROL_GetInput(); - gi->GetInput(&cmd->ucmd, &input); + gi->GetInput(&input, I_GetInputFrac(SyncInput()), &cmd->ucmd); cmd->consistency = consistency[myconnectindex][(maketic / ticdup) % BACKUPTICS]; } @@ -576,7 +576,7 @@ void TryRunTics (void) { I_GetEvent(); auto input = CONTROL_GetInput(); - gi->GetInput(nullptr, &input); + gi->GetInput(&input, I_GetInputFrac(SyncInput())); } return; } diff --git a/source/games/blood/src/blood.h b/source/games/blood/src/blood.h index 33d012bb6..f4fdc083c 100644 --- a/source/games/blood/src/blood.h +++ b/source/games/blood/src/blood.h @@ -124,7 +124,7 @@ struct GameInterface : public ::GameInterface FString GetCoordString() override; ReservedSpace GetReservedScreenSpace(int viewsize) override; void UpdateSounds() override; - void GetInput(InputPacket* packet, ControlInfo* const hidInput) override; + void GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet = nullptr) override; void Ticker() override; void DrawBackground() override; void Startup() override; diff --git a/source/games/blood/src/controls.cpp b/source/games/blood/src/controls.cpp index 41b5f27ee..92e6d96a9 100644 --- a/source/games/blood/src/controls.cpp +++ b/source/games/blood/src/controls.cpp @@ -37,7 +37,7 @@ static InputPacket gInput; void UpdatePlayerSpriteAngle(PLAYER* pPlayer); void doslopetilting(PLAYER* pPlayer, double const scaleAdjust); -void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput) +void GameInterface::GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet) { if (paused || M_Active()) { @@ -46,7 +46,6 @@ void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput) } PLAYER* pPlayer = &gPlayer[myconnectindex]; - double const scaleAdjust = InputScale(); InputPacket input {}; ApplyGlobalInput(gInput, hidInput); diff --git a/source/games/duke/src/duke3d.h b/source/games/duke/src/duke3d.h index 2e1860644..37b356667 100644 --- a/source/games/duke/src/duke3d.h +++ b/source/games/duke/src/duke3d.h @@ -43,7 +43,7 @@ struct GameInterface : public ::GameInterface void ExitFromMenu() override; ReservedSpace GetReservedScreenSpace(int viewsize) override; void DrawPlayerSprite(const DVector2& origin, bool onteam) override; - void GetInput(InputPacket* packet, ControlInfo* const hidInput) override; + void GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet = nullptr) override; void UpdateSounds() override; void Startup() override; void DrawBackground() override; diff --git a/source/games/duke/src/input.cpp b/source/games/duke/src/input.cpp index d4c535ca6..b677256f7 100644 --- a/source/games/duke/src/input.cpp +++ b/source/games/duke/src/input.cpp @@ -800,7 +800,7 @@ static void FinalizeInput(player_struct *p, InputPacket& input) // //--------------------------------------------------------------------------- -void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput) +void GameInterface::GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet) { if (paused || gamestate != GS_LEVEL) { @@ -809,13 +809,11 @@ void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput) } auto const p = &ps[myconnectindex]; - bool const rrraVehicle = isRRRA() && (p->OnMotorcycle || p->OnBoat); - double const scaleAdjust = InputScale(); InputPacket input{}; processInputBits(p, hidInput); - if (rrraVehicle) + if (isRRRA() && (p->OnMotorcycle || p->OnBoat)) { processVehicleInput(p, hidInput, input, scaleAdjust); } diff --git a/source/games/exhumed/src/exhumed.h b/source/games/exhumed/src/exhumed.h index d8b36a3dd..9927124a7 100644 --- a/source/games/exhumed/src/exhumed.h +++ b/source/games/exhumed/src/exhumed.h @@ -231,7 +231,7 @@ struct GameInterface : public ::GameInterface void Ticker() override; void DrawBackground() override; void Render() override; - void GetInput(InputPacket* packet, ControlInfo* const hidInput) override; + void GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet = nullptr) override; void Startup() override; const char* GenericCheat(int player, int cheat) override; void NewGame(MapRecord *map, int skill, bool) override; diff --git a/source/games/exhumed/src/input.cpp b/source/games/exhumed/src/input.cpp index 95f96f998..30a980ad8 100644 --- a/source/games/exhumed/src/input.cpp +++ b/source/games/exhumed/src/input.cpp @@ -34,7 +34,7 @@ void ClearSpaceBar(short nPlayer) } -void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput) +void GameInterface::GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* packet) { if (paused || M_Active()) { @@ -50,17 +50,16 @@ void GameInterface::GetInput(InputPacket* packet, ControlInfo* const hidInput) } Player* pPlayer = &PlayerList[nLocalPlayer]; - double const scaleAdjust = InputScale(); InputPacket input {}; - if (PlayerList[nLocalPlayer].nHealth == 0) + if (PlayerList[nLocalPlayer].nHealth != 0) { - lPlayerYVel = 0; - lPlayerXVel = 0; + processMovement(&input, &localInput, hidInput, scaleAdjust); } else { - processMovement(&input, &localInput, hidInput, scaleAdjust); + lPlayerYVel = 0; + lPlayerXVel = 0; } if (!SyncInput()) diff --git a/source/games/sw/src/game.cpp b/source/games/sw/src/game.cpp index 61c49927b..c787f0bde 100644 --- a/source/games/sw/src/game.cpp +++ b/source/games/sw/src/game.cpp @@ -179,7 +179,6 @@ void GameInterface::LoadGameTextures() void GameInterface::app_init() { GameTicRate = 40; - InputScalePercentage = 0.070625; InitCheats(); automapping = 1; diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h index 784713c96..ee587a58d 100644 --- a/source/games/sw/src/game.h +++ b/source/games/sw/src/game.h @@ -2191,7 +2191,7 @@ struct GameInterface : public ::GameInterface ReservedSpace GetReservedScreenSpace(int viewsize) override; void UpdateSounds() override; void ErrorCleanup() override; - void GetInput(InputPacket* input, ControlInfo* const hidInput) override; + void GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket* input = nullptr) override; void DrawBackground(void) override; void Ticker(void) override; void Render() override; diff --git a/source/games/sw/src/input.cpp b/source/games/sw/src/input.cpp index 802d5af7f..229b4831b 100644 --- a/source/games/sw/src/input.cpp +++ b/source/games/sw/src/input.cpp @@ -160,7 +160,7 @@ static void processWeapon(PLAYERp const pp) } } -void GameInterface::GetInput(InputPacket *packet, ControlInfo* const hidInput) +void GameInterface::GetInput(ControlInfo* const hidInput, double const scaleAdjust, InputPacket *packet) { PLAYERp pp = &Player[myconnectindex]; @@ -170,7 +170,6 @@ void GameInterface::GetInput(InputPacket *packet, ControlInfo* const hidInput) return; } - double const scaleAdjust = InputScale(); InputPacket input {}; ApplyGlobalInput(loc, hidInput);