- 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.
This commit is contained in:
Mitch Richters 2021-11-12 18:59:52 +11:00 committed by Christoph Oelckers
parent 08bc31e6e2
commit e491d15ff9
20 changed files with 63 additions and 60 deletions

View file

@ -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();
}

View file

@ -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();

View file

@ -1983,6 +1983,7 @@ void Net_SkipCommand (int cmd, uint8_t **stream)
void Net_ClearFifo(void)
{
I_SetFrameTime();
I_ResetInputTime();
gametime = I_GetTime();
}

View file

@ -1024,7 +1024,6 @@ int RunGame()
playername = userConfig.CommandName;
}
GameTicRate = 30;
InputScalePercentage = 0.14125;
CheckUserMap();
palindexmap[0] = 255;

View file

@ -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")

View file

@ -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)

View file

@ -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
{

View file

@ -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() {}

View file

@ -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;
}
}

View file

@ -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()
{

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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())

View file

@ -179,7 +179,6 @@ void GameInterface::LoadGameTextures()
void GameInterface::app_init()
{
GameTicRate = 40;
InputScalePercentage = 0.070625;
InitCheats();
automapping = 1;

View file

@ -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;

View file

@ -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);