Skip to content

Commit fbc45f4

Browse files
committed
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 !
1 parent a9657ed commit fbc45f4

File tree

5 files changed

+104
-26
lines changed

5 files changed

+104
-26
lines changed

engine/cl_main.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "r_local.h"
1616
#include "gl_lightmap.h"
1717
#include "console.h"
18+
#include "sv_main.h"
1819
#include "traceinit.h"
1920
#include "cl_demo.h"
2021
#include "cdll_engine_int.h"
@@ -1393,10 +1394,18 @@ void CL_TakeSnapshotAndSwap()
13931394
if ( bReadPixelsFromFrontBuffer )
13941395
{
13951396
Shader_SwapBuffers();
1397+
}
1398+
1399+
if (g_ClientGlobalVariables.client_taking_screenshot
1400+
|| g_ServerGlobalVariables.client_taking_screenshot)
1401+
{
1402+
CL_TakeScreenshot(NULL);
1403+
g_ClientGlobalVariables.client_taking_screenshot = false;
1404+
g_ServerGlobalVariables.client_taking_screenshot = false;
13961405
}
1397-
1406+
13981407
if (cl_takesnapshot)
1399-
{
1408+
{
14001409
// Disable threading for the duration of the screenshots, because we need to get pointers to the (complete)
14011410
// back buffer right now.
14021411
bool bEnabled = materials->AllowThreading( false, g_nMaterialSystemThread );
@@ -1505,7 +1514,7 @@ void CL_TakeSnapshotAndSwap()
15051514

15061515
// Restore threading if it was previously enabled (if it wasn't this will do nothing).
15071516
materials->AllowThreading( bEnabled, g_nMaterialSystemThread );
1508-
}
1517+
}
15091518

15101519
// If recording movie and the console is totally up, then write out this frame to movie file.
15111520
if ( cl_movieinfo.IsRecording() && !Con_IsVisible() && !scr_drawloading )

engine/host.cpp

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,8 +3061,7 @@ void _Host_RunFrame (float time)
30613061
Cbuf_AddText( "quit\n" );
30623062
}
30633063
#endif
3064-
3065-
int numticks;
3064+
int numticks;
30663065
{
30673066
// Profile scope specific to the top of this function, protect from setjmp() problems
30683067
VPROF( "_Host_RunFrame_Upto_MarkFrame" );
@@ -3236,7 +3235,7 @@ void _Host_RunFrame (float time)
32363235
//---------------------------------------------------------
32373236
// Run prediction, useful when fps is lower than tickrate.
32383237
//---------------------------------------------------------
3239-
CL_RunPrediction( PREDICTION_NORMAL );
3238+
// CL_RunPrediction( PREDICTION_NORMAL );
32403239

32413240
_Host_RunFrame_Input( prevremainder, bFinalTick );
32423241
prevremainder = 0;
@@ -3310,24 +3309,72 @@ void _Host_RunFrame (float time)
33103309
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "Host_SetClientInSimulation" );
33113310

33123311
// This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
3313-
Host_SetClientInSimulation( false );
3314-
// Now allow for interpolation on client
3315-
g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
3316-
3317-
#if defined( REPLAY_ENABLED )
3318-
// Update client-side replay history manager - called here since interpolation_amount is set
3319-
if ( g_pClientReplayContext && g_pClientReplayContext->IsInitialized() )
3312+
Host_SetClientInSimulation(false);
3313+
3314+
// TODO_ENHANCED:
3315+
// Notice_Enhanced:
3316+
// This check permits to fix interpolation problems on the
3317+
// local player that valve has been (fucking finally)
3318+
// caring about on counter-strike 2.
3319+
//
3320+
// To recall the original issue, the
3321+
// problem that Valve cared about is that interpolation
3322+
// had some problems with interpolating the local
3323+
// player because the screen would never in the first
3324+
// place match the tick "screen", because interpolation
3325+
// amount could never reach 0.0 or 1.0
3326+
//
3327+
// Valve solution was to introduce bugs with lag
3328+
// compensating the local player and made the game worse,
3329+
// introducing a new way for cheaters to cheat even more
3330+
// on their games.
3331+
// I'm joking, but you can clearly see the outcome anyway.
3332+
//
3333+
// My solution is to simply set interpolation amount
3334+
// to 0.0 when a tick arrives.
3335+
//
3336+
// So when we shoot, we get the frame we shot with an
3337+
// interpolation amount at 0.0, perfectly aligned to user
3338+
// commands which is ideal for us.
3339+
//
3340+
// It might look a bit more unsmooth with lower fps
3341+
// but with high enough fps, the issue goes away anyway.
3342+
// It's not very noticeable which is very nice for us.
3343+
// No need to lag compensate the local player anymore !
3344+
if (numticks == 0)
3345+
{
3346+
g_ClientGlobalVariables.interpolation_amount = (cl.m_tickRemainder
3347+
/ host_state
3348+
.interval_per_tick);
3349+
}
3350+
else
3351+
{
3352+
g_ClientGlobalVariables.interpolation_amount = 0.0f;
3353+
#ifdef _DEBUG
3354+
printf("interpolation amount was %f, corrected to "
3355+
"fix interpolation issues.\n",
3356+
cl.m_tickRemainder
3357+
/ host_state.interval_per_tick);
3358+
#endif
3359+
}
3360+
3361+
#if defined(REPLAY_ENABLED)
3362+
// Update client-side replay history manager - called here
3363+
// since interpolation_amount is set
3364+
if ( g_pClientReplayContext && g_pClientReplayContext->IsInitialized() )
33203365
{
33213366
g_pClientReplayContext->Think();
33223367
}
3323-
#endif
3368+
#endif
33243369

3325-
//-------------------
3326-
// Run prediction if it hasn't been run yet
3327-
//-------------------
3328-
// If we haven't predicted/simulated the player (multiplayer with prediction enabled and
3329-
// not a listen server with zero frame lag, then go ahead and predict now
3330-
CL_RunPrediction( PREDICTION_NORMAL );
3370+
//-------------------
3371+
// Run prediction if it hasn't been run yet
3372+
//-------------------
3373+
// If we haven't predicted/simulated the player
3374+
// (multiplayer with prediction enabled and
3375+
// not a listen server with zero frame lag, then go ahead
3376+
// and predict now
3377+
CL_RunPrediction( PREDICTION_NORMAL );
33313378

33323379
CL_ApplyAddAngle();
33333380

@@ -3417,9 +3464,24 @@ void _Host_RunFrame (float time)
34173464

34183465
// This causes cl.gettime() to return the true clock being used for rendering (tickcount * rate + remainder)
34193466
Host_SetClientInSimulation( false );
3420-
// Now allow for interpolation on client
3421-
g_ClientGlobalVariables.interpolation_amount = ( cl.m_tickRemainder / host_state.interval_per_tick );
34223467

3468+
// Please check Notice_Enhanced.
3469+
if (numticks == 0)
3470+
{
3471+
g_ClientGlobalVariables.interpolation_amount = (cl.m_tickRemainder
3472+
/ host_state
3473+
.interval_per_tick);
3474+
}
3475+
else
3476+
{
3477+
g_ClientGlobalVariables.interpolation_amount = 0.0f;
3478+
#ifdef _DEBUG
3479+
printf("interpolation amount was %f, corrected to "
3480+
"fix interpolation issues.\n",
3481+
cl.m_tickRemainder
3482+
/ host_state.interval_per_tick);
3483+
#endif
3484+
}
34233485
//-------------------
34243486
// Run prediction if it hasn't been run yet
34253487
//-------------------
@@ -3443,7 +3505,7 @@ void _Host_RunFrame (float time)
34433505
g_ClientGlobalVariables.tickcount = host_tickcount;
34443506
bool bFinalTick = tick==(serverticks-1) ? true : false;
34453507
// Run prediction before inputs if fps is lower than tickrate
3446-
CL_RunPrediction( PREDICTION_NORMAL );
3508+
// CL_RunPrediction( PREDICTION_NORMAL );
34473509
_Host_RunFrame_Input( prevremainder, bFinalTick );
34483510
prevremainder = 0;
34493511
// process any asynchronous network traffic (TCP), set net_time
@@ -3592,7 +3654,7 @@ void _Host_RunFrame (float time)
35923654
GetTestScriptMgr()->CheckPoint( "frame_end" );
35933655
} // Profile scope, protect from setjmp() problems
35943656

3595-
Host_ShowIPCCallCount();
3657+
Host_ShowIPCCallCount();
35963658
}
35973659
/*
35983660
==============================

game/client/prediction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,7 +922,7 @@ void CPrediction::RunCommand( C_BasePlayer *player, CUserCmd *ucmd, IMoveHelper
922922
// Get button states
923923
player->UpdateButtonState( ucmd->buttons );
924924

925-
// CheckMovingGround( player, gpGlobals->frametime );
925+
CheckMovingGround( player, gpGlobals->frametime );
926926

927927
g_pMoveData->m_vecOldAngles = player->pl.v_angle;
928928

game/shared/cstrike/fx_cs_shared.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "cbase.h"
88
#include "fx_cs_shared.h"
9+
#include "convar.h"
910
#include "weapon_csbase.h"
1011

1112
#ifndef CLIENT_DLL
@@ -284,8 +285,12 @@ void FX_FireBullets(
284285
y1[iBullet] = fRadius1 * sinf(fTheta1);
285286
}
286287

288+
static ConVar debug_screenshot_bullet_position("debug_screenshot_bullet_position", "0");
287289
for ( int iBullet=0; iBullet < pWeaponInfo->m_iBullets; iBullet++ )
288-
{
290+
{
291+
if (debug_screenshot_bullet_position.GetBool())
292+
gpGlobals->client_taking_screenshot = true;
293+
289294
pPlayer->FireBullet(
290295
vOrigin,
291296
vAngles,

public/globalvars_base.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class CGlobalVarsBase
7474

7575
// current saverestore data
7676
CSaveRestoreData *pSaveData;
77+
bool client_taking_screenshot;
7778

7879
private:
7980
// Set to true in client code.
@@ -99,6 +100,7 @@ inline CGlobalVarsBase::CGlobalVarsBase( bool bIsClient ) :
99100
nTimestampNetworkingBase( 100 ),
100101
nTimestampRandomizeWindow( 32 )
101102
{
103+
client_taking_screenshot = false;
102104
}
103105

104106
inline bool CGlobalVarsBase::IsClient() const

0 commit comments

Comments
 (0)