Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
16 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "player.h"
  8. #include "usercmd.h"
  9. #include "igamemovement.h"
  10. #include "mathlib/mathlib.h"
  11. #include "client.h"
  12. #include "player_command.h"
  13. #include "movehelper_server.h"
  14. #include "iservervehicle.h"
  15. #include "tier0/vprof.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. extern IGameMovement *g_pGameMovement;
  19. extern CMoveData *g_pMoveData; // This is a global because it is subclassed by each game.
  20. extern ConVar sv_noclipduringpause;
  21. ConVar sv_maxusrcmdprocessticks_warning( "sv_maxusrcmdprocessticks_warning", "-1", FCVAR_RELEASE, "Print a warning when user commands get dropped due to insufficient usrcmd ticks allocated, number of seconds to throttle, negative disabled" );
  22. static ConVar sv_maxusrcmdprocessticks_holdaim( "sv_maxusrcmdprocessticks_holdaim", "1", FCVAR_RELEASE, "Hold client aim for multiple server sim ticks when client-issued usrcmd contains multiple actions (0: off; 1: hold this server tick; 2+: hold multiple ticks)" );
  23. //-----------------------------------------------------------------------------
  24. // Purpose:
  25. //-----------------------------------------------------------------------------
  26. CPlayerMove::CPlayerMove( void )
  27. {
  28. }
  29. //-----------------------------------------------------------------------------
  30. // Purpose: We're about to run this usercmd for the specified player. We can set up groupinfo and masking here, etc.
  31. // This is the time to examine the usercmd for anything extra. This call happens even if think does not.
  32. // Input : *player -
  33. // *cmd -
  34. //-----------------------------------------------------------------------------
  35. void CPlayerMove::StartCommand( CBasePlayer *player, CUserCmd *cmd )
  36. {
  37. VPROF( "CPlayerMove::StartCommand" );
  38. #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID )
  39. CPredictableId::ResetInstanceCounters();
  40. #endif
  41. player->m_pCurrentCommand = cmd;
  42. CBaseEntity::SetPredictionRandomSeed( cmd );
  43. CBaseEntity::SetPredictionPlayer( player );
  44. #if defined (HL2_DLL)
  45. // pull out backchannel data and move this out
  46. int i;
  47. for (i = 0; i < cmd->entitygroundcontact.Count(); i++)
  48. {
  49. int entindex = cmd->entitygroundcontact[i].entindex;
  50. CBaseEntity *pEntity = CBaseEntity::Instance( INDEXENT( entindex) );
  51. if (pEntity)
  52. {
  53. CBaseAnimating *pAnimating = pEntity->GetBaseAnimating();
  54. if (pAnimating)
  55. {
  56. pAnimating->SetIKGroundContactInfo( cmd->entitygroundcontact[i].minheight, cmd->entitygroundcontact[i].maxheight );
  57. }
  58. }
  59. }
  60. #endif
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose: We've finished running a user's command
  64. // Input : *player -
  65. //-----------------------------------------------------------------------------
  66. void CPlayerMove::FinishCommand( CBasePlayer *player )
  67. {
  68. VPROF( "CPlayerMove::FinishCommand" );
  69. player->m_pCurrentCommand = NULL;
  70. CBaseEntity::SetPredictionRandomSeed( NULL );
  71. CBaseEntity::SetPredictionPlayer( NULL );
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Purpose: Checks if the player is standing on a moving entity and adjusts velocity and
  75. // basevelocity appropriately
  76. // Input : *player -
  77. // frametime -
  78. //-----------------------------------------------------------------------------
  79. void CPlayerMove::CheckMovingGround( CBasePlayer *player, double frametime )
  80. {
  81. VPROF( "CPlayerMove::CheckMovingGround()" );
  82. CBaseEntity *groundentity;
  83. if ( player->GetFlags() & FL_ONGROUND )
  84. {
  85. groundentity = player->GetGroundEntity();
  86. if ( groundentity && ( groundentity->GetFlags() & FL_CONVEYOR) )
  87. {
  88. Vector vecNewVelocity;
  89. groundentity->GetGroundVelocityToApply( vecNewVelocity );
  90. if ( player->GetFlags() & FL_BASEVELOCITY )
  91. {
  92. vecNewVelocity += player->GetBaseVelocity();
  93. }
  94. player->SetBaseVelocity( vecNewVelocity );
  95. player->AddFlag( FL_BASEVELOCITY );
  96. }
  97. }
  98. if ( !( player->GetFlags() & FL_BASEVELOCITY ) )
  99. {
  100. // Apply momentum (add in half of the previous frame of velocity first)
  101. player->ApplyAbsVelocityImpulse( (1.0 + ( frametime * 0.5 )) * player->GetBaseVelocity() );
  102. player->SetBaseVelocity( vec3_origin );
  103. }
  104. player->RemoveFlag( FL_BASEVELOCITY );
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose: Prepares for running movement
  108. // Input : *player -
  109. // *ucmd -
  110. // *pHelper -
  111. // *move -
  112. // time -
  113. //-----------------------------------------------------------------------------
  114. void CPlayerMove::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
  115. {
  116. VPROF( "CPlayerMove::SetupMove" );
  117. // Allow sound, etc. to be created by movement code
  118. move->m_bFirstRunOfFunctions = true;
  119. move->m_bGameCodeMovedPlayer = false;
  120. if ( player->GetPreviouslyPredictedOrigin() != player->GetAbsOrigin() )
  121. {
  122. move->m_bGameCodeMovedPlayer = true;
  123. }
  124. // Prepare the usercmd fields
  125. move->m_nImpulseCommand = ucmd->impulse;
  126. move->m_vecViewAngles = ucmd->viewangles;
  127. CBaseEntity *pMoveParent = player->GetMoveParent();
  128. if (!pMoveParent)
  129. {
  130. move->m_vecAbsViewAngles = move->m_vecViewAngles;
  131. }
  132. else
  133. {
  134. matrix3x4_t viewToParent, viewToWorld;
  135. AngleMatrix( move->m_vecViewAngles, viewToParent );
  136. ConcatTransforms( pMoveParent->EntityToWorldTransform(), viewToParent, viewToWorld );
  137. MatrixAngles( viewToWorld, move->m_vecAbsViewAngles );
  138. }
  139. move->m_nButtons = ucmd->buttons;
  140. // Ingore buttons for movement if at controls
  141. if ( player->GetFlags() & FL_ATCONTROLS )
  142. {
  143. move->m_flForwardMove = 0;
  144. move->m_flSideMove = 0;
  145. move->m_flUpMove = 0;
  146. }
  147. else
  148. {
  149. move->m_flForwardMove = ucmd->forwardmove;
  150. move->m_flSideMove = ucmd->sidemove;
  151. move->m_flUpMove = ucmd->upmove;
  152. }
  153. // Prepare remaining fields
  154. move->m_flClientMaxSpeed = player->m_flMaxspeed;
  155. move->m_nOldButtons = player->m_Local.m_nOldButtons;
  156. move->m_vecAngles = player->pl.v_angle;
  157. move->m_vecVelocity = player->GetAbsVelocity();
  158. move->m_nPlayerHandle = player;
  159. move->SetAbsOrigin( player->GetAbsOrigin() );
  160. // Copy constraint information
  161. if ( player->m_hConstraintEntity.Get() )
  162. move->m_vecConstraintCenter = player->m_hConstraintEntity.Get()->GetAbsOrigin();
  163. else
  164. move->m_vecConstraintCenter = player->m_vecConstraintCenter;
  165. move->m_flConstraintRadius = player->m_flConstraintRadius;
  166. move->m_flConstraintWidth = player->m_flConstraintWidth;
  167. move->m_flConstraintSpeedFactor = player->m_flConstraintSpeedFactor;
  168. move->m_bConstraintPastRadius = player->m_bConstraintPastRadius;
  169. // setup trace optimization
  170. g_pGameMovement->SetupMovementBounds( move );
  171. }
  172. //-----------------------------------------------------------------------------
  173. // Purpose: Finishes running movement
  174. // Input : *player -
  175. // *move -
  176. // *ucmd -
  177. // time -
  178. //-----------------------------------------------------------------------------
  179. void CPlayerMove::FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move )
  180. {
  181. VPROF( "CPlayerMove::FinishMove" );
  182. player->m_flMaxspeed = move->m_flClientMaxSpeed;
  183. player->SetAbsOrigin( move->GetAbsOrigin() );
  184. player->SetAbsVelocity( move->m_vecVelocity );
  185. player->SetPreviouslyPredictedOrigin( move->GetAbsOrigin() );
  186. player->m_Local.m_nOldButtons = move->m_nButtons;
  187. // Convert final pitch to body pitch
  188. float pitch = move->m_vecAngles[ PITCH ];
  189. if ( pitch > 180.0f )
  190. {
  191. pitch -= 360.0f;
  192. }
  193. pitch = clamp( pitch, -90, 90 );
  194. move->m_vecAngles[ PITCH ] = pitch;
  195. player->SetBodyPitch( pitch );
  196. // player->SetLocalAngles( move->m_vecAngles );
  197. // The class had better not have changed during the move!!
  198. if ( player->m_hConstraintEntity )
  199. Assert( move->m_vecConstraintCenter == player->m_hConstraintEntity.Get()->GetAbsOrigin() );
  200. else
  201. Assert( move->m_vecConstraintCenter == player->m_vecConstraintCenter );
  202. Assert( move->m_flConstraintRadius == player->m_flConstraintRadius );
  203. Assert( move->m_flConstraintWidth == player->m_flConstraintWidth );
  204. Assert( move->m_flConstraintSpeedFactor == player->m_flConstraintSpeedFactor );
  205. Assert( move->m_bConstraintPastRadius == player->m_bConstraintPastRadius );
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Called before player thinks
  209. // Input : *player -
  210. // thinktime -
  211. //-----------------------------------------------------------------------------
  212. void CPlayerMove::RunPreThink( CBasePlayer *player )
  213. {
  214. VPROF( "CPlayerMove::RunPreThink" );
  215. // Run think functions on the player
  216. VPROF_SCOPE_BEGIN( "player->PhysicsRunThink()" );
  217. if ( !player->PhysicsRunThink() )
  218. return;
  219. VPROF_SCOPE_END();
  220. VPROF_SCOPE_BEGIN( "g_pGameRules->PlayerThink( player )" );
  221. // Called every frame to let game rules do any specific think logic for the player
  222. g_pGameRules->PlayerThink( player );
  223. VPROF_SCOPE_END();
  224. VPROF_SCOPE_BEGIN( "player->PreThink()" );
  225. player->PreThink();
  226. VPROF_SCOPE_END();
  227. }
  228. //-----------------------------------------------------------------------------
  229. // Purpose: Runs the PLAYER's thinking code if time. There is some play in the exact time the think
  230. // function will be called, because it is called before any movement is done
  231. // in a frame. Not used for pushmove objects, because they must be exact.
  232. // Returns false if the entity removed itself.
  233. // Input : *ent -
  234. // frametime -
  235. // clienttimebase -
  236. // Output : void CPlayerMove::RunThink
  237. //-----------------------------------------------------------------------------
  238. void CPlayerMove::RunThink (CBasePlayer *player, double frametime )
  239. {
  240. VPROF( "CPlayerMove::RunThink" );
  241. int thinktick = player->GetNextThinkTick();
  242. if ( thinktick <= 0 || thinktick > player->m_nTickBase )
  243. return;
  244. //gpGlobals->curtime = thinktime;
  245. player->SetNextThink( TICK_NEVER_THINK );
  246. // Think
  247. player->Think();
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose: Called after player movement
  251. // Input : *player -
  252. // thinktime -
  253. // frametime -
  254. //-----------------------------------------------------------------------------
  255. void CPlayerMove::RunPostThink( CBasePlayer *player )
  256. {
  257. VPROF( "CPlayerMove::RunPostThink" );
  258. // Run post-think
  259. player->PostThink();
  260. }
  261. void CommentarySystem_PePlayerRunCommand( CBasePlayer *player, CUserCmd *ucmd );
  262. //-----------------------------------------------------------------------------
  263. // Purpose: Runs movement commands for the player
  264. // Input : *player -
  265. // *ucmd -
  266. // *moveHelper -
  267. // Output : void CPlayerMove::RunCommand
  268. //-----------------------------------------------------------------------------
  269. void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *moveHelper )
  270. {
  271. const float playerCurTime = player->m_nTickBase * TICK_INTERVAL;
  272. const float playerFrameTime = player->m_bGamePaused ? 0 : TICK_INTERVAL;
  273. const float flTimeAllowedForProcessing = player->ConsumeMovementTimeForUserCmdProcessing( playerFrameTime );
  274. if ( !player->IsBot() && !player->IsHLTV() && ( flTimeAllowedForProcessing < playerFrameTime ) )
  275. {
  276. // Make sure that the activity in command is erased because player cheated or dropped too many packets
  277. double dblWarningFrequencyThrottle = sv_maxusrcmdprocessticks_warning.GetFloat();
  278. if ( dblWarningFrequencyThrottle >= 0 )
  279. {
  280. static double s_dblLastWarningTime = 0;
  281. double dblTimeNow = Plat_FloatTime();
  282. if ( !s_dblLastWarningTime || ( dblTimeNow - s_dblLastWarningTime >= dblWarningFrequencyThrottle ) )
  283. {
  284. s_dblLastWarningTime = dblTimeNow;
  285. Warning( "sv_maxusrcmdprocessticks_warning at server tick %u: Ignored client %s usrcmd (%.6f < %.6f)!\n", gpGlobals->tickcount, player->GetPlayerName(), flTimeAllowedForProcessing, playerFrameTime );
  286. }
  287. }
  288. return; // Don't process this command
  289. }
  290. StartCommand( player, ucmd );
  291. // Set globals appropriately
  292. const float serverCurTime = gpGlobals->curtime;
  293. const float serverFrameTime = gpGlobals->frametime;
  294. gpGlobals->curtime = playerCurTime;
  295. gpGlobals->frametime = playerFrameTime;
  296. // Add and subtract buttons we're forcing on the player
  297. ucmd->buttons |= player->m_afButtonForced;
  298. ucmd->buttons &= ~player->m_afButtonDisabled;
  299. if ( player->m_bGamePaused )
  300. {
  301. // If no clipping and cheats enabled and noclipduring game enabled, then leave
  302. // forwardmove and angles stuff in usercmd
  303. if ( player->GetMoveType() == MOVETYPE_NOCLIP &&
  304. sv_cheats->GetBool() &&
  305. sv_noclipduringpause.GetBool() )
  306. {
  307. gpGlobals->frametime = TICK_INTERVAL;
  308. }
  309. }
  310. /*
  311. // TODO: We can check whether the player is sending more commands than elapsed real time
  312. cmdtimeremaining -= ucmd->msec;
  313. if ( cmdtimeremaining < 0 )
  314. {
  315. // return;
  316. }
  317. */
  318. g_pGameMovement->StartTrackPredictionErrors( player );
  319. CommentarySystem_PePlayerRunCommand( player, ucmd );
  320. // Do weapon selection
  321. if ( ucmd->weaponselect != 0 )
  322. {
  323. CBaseCombatWeapon *weapon = dynamic_cast< CBaseCombatWeapon * >( CBaseEntity::Instance( ucmd->weaponselect ) );
  324. if ( weapon )
  325. {
  326. VPROF( "player->SelectItem()" );
  327. player->SelectItem( weapon->GetName(), ucmd->weaponsubtype );
  328. }
  329. }
  330. IServerVehicle *pVehicle = player->GetVehicle();
  331. // Latch in impulse.
  332. if ( ucmd->impulse )
  333. {
  334. // Discard impulse commands unless the vehicle allows them.
  335. // FIXME: UsingStandardWeapons seems like a bad filter for this. The flashlight is an impulse command, for example.
  336. if ( !pVehicle || player->UsingStandardWeaponsInVehicle() )
  337. {
  338. player->m_nImpulse = ucmd->impulse;
  339. }
  340. }
  341. // Update player input button states
  342. VPROF_SCOPE_BEGIN( "player->UpdateButtonState" );
  343. player->UpdateButtonState( ucmd->buttons );
  344. VPROF_SCOPE_END();
  345. CheckMovingGround( player, TICK_INTERVAL );
  346. g_pMoveData->m_vecOldAngles = player->pl.v_angle;
  347. // Copy from command to player unless game .dll has set angle using fixangle
  348. if ( player->pl.fixangle == FIXANGLE_NONE )
  349. {
  350. player->pl.v_angle = ucmd->viewangles;
  351. }
  352. else if( player->pl.fixangle == FIXANGLE_RELATIVE )
  353. {
  354. player->pl.v_angle = ucmd->viewangles + player->pl.anglechange;
  355. }
  356. // TrackIR
  357. player->SetEyeAngleOffset(ucmd->headangles);
  358. player->SetEyeOffset(ucmd->headoffset);
  359. // TrackIR
  360. player->SetAimDirection(ucmd->aimdirection);
  361. // Call standard client pre-think
  362. RunPreThink( player );
  363. // Call Think if one is set
  364. RunThink( player, TICK_INTERVAL );
  365. // Setup input.
  366. SetupMove( player, ucmd, moveHelper, g_pMoveData );
  367. // Let the game do the movement.
  368. if ( !pVehicle )
  369. {
  370. VPROF( "g_pGameMovement->ProcessMovement()" );
  371. Assert( g_pGameMovement );
  372. g_pGameMovement->ProcessMovement( player, g_pMoveData );
  373. }
  374. else
  375. {
  376. VPROF( "pVehicle->ProcessMovement()" );
  377. pVehicle->ProcessMovement( player, g_pMoveData );
  378. }
  379. // Copy output
  380. FinishMove( player, ucmd, g_pMoveData );
  381. // If we have to restore the view angle then do so right now
  382. if ( !player->IsBot() &&
  383. ( gpGlobals->tickcount - player->GetLockViewanglesTickNumber() < sv_maxusrcmdprocessticks_holdaim.GetInt() ) )
  384. {
  385. player->pl.v_angle = player->GetLockViewanglesData();
  386. }
  387. // Restore server time temporarily before processing impacts,
  388. // so timestamps are all in the same time space
  389. gpGlobals->curtime = serverCurTime;
  390. gpGlobals->frametime = serverFrameTime;
  391. // Let server invoke any needed impact functions
  392. VPROF_SCOPE_BEGIN( "moveHelper->ProcessImpacts" );
  393. moveHelper->ProcessImpacts();
  394. VPROF_SCOPE_END();
  395. gpGlobals->curtime = playerCurTime;
  396. gpGlobals->frametime = playerFrameTime;
  397. RunPostThink( player );
  398. g_pGameMovement->FinishTrackPredictionErrors( player );
  399. g_pGameMovement->Reset();
  400. FinishCommand( player );
  401. // Let time pass
  402. if ( gpGlobals->frametime > 0 )
  403. {
  404. player->m_nTickBase++;
  405. }
  406. }