Fixed local player interpolation and added debug_screenshot_bullet_position
This check permits to fix interpolation problems on the local player that valve has been (fucking finally) caring about on counter-strike 2. To recall the original issue, the problem that Valve cared about is that interpolation had some problems with interpolating the local player because the screen would never in the first place match the tick "screen", because interpolation amount could never reach 0.0 or 1.0 Valve solution was to introduce bugs with lag compensating the local player and made the game worse, introducing a new way for cheaters to cheat even more on their games. I'm joking, but you can clearly see the outcome anyway. My solution is to simply set interpolation amount to 0.0 when a tick arrives. So when we shoot, we get the frame we shot with an interpolation amount at 0.0, perfectly aligned to user commands which is ideal for us. It might look a bit more unsmooth with lower fps but with high enough fps, the issue goes away anyway. It's not very noticeable which is very nice for us. No need to lag compensate the local player anymore !
This commit is contained in:
parent
f8c641a9e5
commit
cfa5b12eea
5 changed files with 103 additions and 25 deletions
|
@ -15,6 +15,7 @@
|
|||
#include "r_local.h"
|
||||
#include "gl_lightmap.h"
|
||||
#include "console.h"
|
||||
#include "sv_main.h"
|
||||
#include "traceinit.h"
|
||||
#include "cl_demo.h"
|
||||
#include "cdll_engine_int.h"
|
||||
|
@ -1393,10 +1394,18 @@ void CL_TakeSnapshotAndSwap()
|
|||
if ( bReadPixelsFromFrontBuffer )
|
||||
{
|
||||
Shader_SwapBuffers();
|
||||
}
|
||||
|
||||
if (g_ClientGlobalVariables.client_taking_screenshot
|
||||
|| g_ServerGlobalVariables.client_taking_screenshot)
|
||||
{
|
||||
CL_TakeScreenshot(NULL);
|
||||
g_ClientGlobalVariables.client_taking_screenshot = false;
|
||||
g_ServerGlobalVariables.client_taking_screenshot = false;
|
||||
}
|
||||
|
||||
|
||||
if (cl_takesnapshot)
|
||||
{
|
||||
{
|
||||
// Disable threading for the duration of the screenshots, because we need to get pointers to the (complete)
|
||||
// back buffer right now.
|
||||
bool bEnabled = materials->AllowThreading( false, g_nMaterialSystemThread );
|
||||
|
@ -1505,7 +1514,7 @@ void CL_TakeSnapshotAndSwap()
|
|||
|
||||
// Restore threading if it was previously enabled (if it wasn't this will do nothing).
|
||||
materials->AllowThreading( bEnabled, g_nMaterialSystemThread );
|
||||
}
|
||||
}
|
||||
|
||||
// If recording movie and the console is totally up, then write out this frame to movie file.
|
||||
if ( cl_movieinfo.IsRecording() && !Con_IsVisible() && !scr_drawloading )
|
||||
|
|
102
engine/host.cpp
102
engine/host.cpp
|
@ -3061,8 +3061,7 @@ void _Host_RunFrame (float time)
|
|||
Cbuf_AddText( "quit\n" );
|
||||
}
|
||||
#endif
|
||||
|
||||
int numticks;
|
||||
int numticks;
|
||||
{
|
||||
// Profile scope specific to the top of this function, protect from setjmp() problems
|
||||
VPROF( "_Host_RunFrame_Upto_MarkFrame" );
|
||||
|
@ -3236,7 +3235,7 @@ void _Host_RunFrame (float time)
|
|||
//---------------------------------------------------------
|
||||
// Run prediction, useful when fps is lower than tickrate.
|
||||
//---------------------------------------------------------
|
||||
CL_RunPrediction( PREDICTION_NORMAL );
|
||||
// CL_RunPrediction( PREDICTION_NORMAL );
|
||||
|
||||
_Host_RunFrame_Input( prevremainder, bFinalTick );
|
||||
prevremainder = 0;
|
||||
|
@ -3310,24 +3309,72 @@ void _Host_RunFrame (float time)
|
|||
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "Host_SetClientInSimulation" );
|
||||
|
||||
// This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
|
||||
Host_SetClientInSimulation( false );
|
||||
// Now allow for interpolation on client
|
||||
g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
|
||||
Host_SetClientInSimulation(false);
|
||||
|
||||
#if defined( REPLAY_ENABLED )
|
||||
// Update client-side replay history manager - called here since interpolation_amount is set
|
||||
if ( g_pClientReplayContext && g_pClientReplayContext->IsInitialized() )
|
||||
// TODO_ENHANCED:
|
||||
// Notice_Enhanced:
|
||||
// This check permits to fix interpolation problems on the
|
||||
// local player that valve has been (fucking finally)
|
||||
// caring about on counter-strike 2.
|
||||
//
|
||||
// To recall the original issue, the
|
||||
// problem that Valve cared about is that interpolation
|
||||
// had some problems with interpolating the local
|
||||
// player because the screen would never in the first
|
||||
// place match the tick "screen", because interpolation
|
||||
// amount could never reach 0.0 or 1.0
|
||||
//
|
||||
// Valve solution was to introduce bugs with lag
|
||||
// compensating the local player and made the game worse,
|
||||
// introducing a new way for cheaters to cheat even more
|
||||
// on their games.
|
||||
// I'm joking, but you can clearly see the outcome anyway.
|
||||
//
|
||||
// My solution is to simply set interpolation amount
|
||||
// to 0.0 when a tick arrives.
|
||||
//
|
||||
// So when we shoot, we get the frame we shot with an
|
||||
// interpolation amount at 0.0, perfectly aligned to user
|
||||
// commands which is ideal for us.
|
||||
//
|
||||
// It might look a bit more unsmooth with lower fps
|
||||
// but with high enough fps, the issue goes away anyway.
|
||||
// It's not very noticeable which is very nice for us.
|
||||
// No need to lag compensate the local player anymore !
|
||||
if (numticks == 0)
|
||||
{
|
||||
g_ClientGlobalVariables.interpolation_amount = (cl.m_tickRemainder
|
||||
/ host_state
|
||||
.interval_per_tick);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ClientGlobalVariables.interpolation_amount = 0.0f;
|
||||
#ifdef _DEBUG
|
||||
printf("interpolation amount was %f, corrected to "
|
||||
"fix interpolation issues.\n",
|
||||
cl.m_tickRemainder
|
||||
/ host_state.interval_per_tick);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(REPLAY_ENABLED)
|
||||
// Update client-side replay history manager - called here
|
||||
// since interpolation_amount is set
|
||||
if ( g_pClientReplayContext && g_pClientReplayContext->IsInitialized() )
|
||||
{
|
||||
g_pClientReplayContext->Think();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//-------------------
|
||||
// Run prediction if it hasn't been run yet
|
||||
//-------------------
|
||||
// If we haven't predicted/simulated the player (multiplayer with prediction enabled and
|
||||
// not a listen server with zero frame lag, then go ahead and predict now
|
||||
CL_RunPrediction( PREDICTION_NORMAL );
|
||||
//-------------------
|
||||
// Run prediction if it hasn't been run yet
|
||||
//-------------------
|
||||
// If we haven't predicted/simulated the player
|
||||
// (multiplayer with prediction enabled and
|
||||
// not a listen server with zero frame lag, then go ahead
|
||||
// and predict now
|
||||
CL_RunPrediction( PREDICTION_NORMAL );
|
||||
|
||||
CL_ApplyAddAngle();
|
||||
|
||||
|
@ -3417,9 +3464,24 @@ void _Host_RunFrame (float time)
|
|||
|
||||
// This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
|
||||
Host_SetClientInSimulation( false );
|
||||
// Now allow for interpolation on client
|
||||
g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
|
||||
|
||||
// Please check Notice_Enhanced.
|
||||
if (numticks == 0)
|
||||
{
|
||||
g_ClientGlobalVariables.interpolation_amount = (cl.m_tickRemainder
|
||||
/ host_state
|
||||
.interval_per_tick);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ClientGlobalVariables.interpolation_amount = 0.0f;
|
||||
#ifdef _DEBUG
|
||||
printf("interpolation amount was %f, corrected to "
|
||||
"fix interpolation issues.\n",
|
||||
cl.m_tickRemainder
|
||||
/ host_state.interval_per_tick);
|
||||
#endif
|
||||
}
|
||||
//-------------------
|
||||
// Run prediction if it hasn't been run yet
|
||||
//-------------------
|
||||
|
@ -3443,7 +3505,7 @@ void _Host_RunFrame (float time)
|
|||
g_ClientGlobalVariables.tickcount = host_tickcount;
|
||||
bool bFinalTick = tick==(serverticks-1) ? true : false;
|
||||
// Run prediction before inputs if fps is lower than tickrate
|
||||
CL_RunPrediction( PREDICTION_NORMAL );
|
||||
// CL_RunPrediction( PREDICTION_NORMAL );
|
||||
_Host_RunFrame_Input( prevremainder, bFinalTick );
|
||||
prevremainder = 0;
|
||||
// process any asynchronous network traffic (TCP), set net_time
|
||||
|
@ -3592,7 +3654,7 @@ void _Host_RunFrame (float time)
|
|||
GetTestScriptMgr()->CheckPoint( "frame_end" );
|
||||
} // Profile scope, protect from setjmp() problems
|
||||
|
||||
Host_ShowIPCCallCount();
|
||||
Host_ShowIPCCallCount();
|
||||
}
|
||||
/*
|
||||
==============================
|
||||
|
|
|
@ -922,7 +922,7 @@ void CPrediction::RunCommand( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper
|
|||
// Get button states
|
||||
player->UpdateButtonState( ucmd->buttons );
|
||||
|
||||
// CheckMovingGround( player, gpGlobals->frametime );
|
||||
CheckMovingGround( player, gpGlobals->frametime );
|
||||
|
||||
g_pMoveData->m_vecOldAngles = player->pl.v_angle;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "cbase.h"
|
||||
#include "fx_cs_shared.h"
|
||||
#include "convar.h"
|
||||
#include "weapon_csbase.h"
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
|
@ -284,8 +285,12 @@ void FX_FireBullets(
|
|||
y1[iBullet] = fRadius1 * sinf(fTheta1);
|
||||
}
|
||||
|
||||
static ConVar debug_screenshot_bullet_position("debug_screenshot_bullet_position", "0");
|
||||
for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ )
|
||||
{
|
||||
{
|
||||
if (debug_screenshot_bullet_position.GetBool())
|
||||
gpGlobals->client_taking_screenshot = true;
|
||||
|
||||
pPlayer->FireBullet(
|
||||
vOrigin,
|
||||
vAngles,
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
|
||||
// current saverestore data
|
||||
CSaveRestoreData *pSaveData;
|
||||
bool client_taking_screenshot;
|
||||
|
||||
private:
|
||||
// Set to true in client code.
|
||||
|
@ -99,6 +100,7 @@ inline CGlobalVarsBase::CGlobalVarsBase( bool bIsClient ) :
|
|||
nTimestampNetworkingBase( 100 ),
|
||||
nTimestampRandomizeWindow( 32 )
|
||||
{
|
||||
client_taking_screenshot = false;
|
||||
}
|
||||
|
||||
inline bool CGlobalVarsBase::IsClient() const
|
||||
|
|
Loading…
Reference in a new issue