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.

780 lines
26 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "baseviewmodel_shared.h"
  9. #include "datacache/imdlcache.h"
  10. #include "cs_shareddefs.h"
  11. #if defined( CLIENT_DLL )
  12. #include "iprediction.h"
  13. #include "prediction.h"
  14. #include "inputsystem/iinputsystem.h"
  15. #include "iclientmode.h"
  16. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  17. #include "weapon_basecsgrenade.h"
  18. #endif
  19. #else
  20. #include "vguiscreen.h"
  21. #endif
  22. #if defined( CLIENT_DLL ) && defined( SIXENSE )
  23. #include "sixense/in_sixense.h"
  24. #include "sixense/sixense_convars_extern.h"
  25. #endif
  26. extern ConVar in_forceuser;
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. #define VIEWMODEL_ANIMATION_PARITY_BITS 3
  30. #define SCREEN_OVERLAY_MATERIAL "vgui/screens/vgui_overlay"
  31. #if defined( CLIENT_DLL )
  32. ConVar viewmodel_offset_x( "viewmodel_offset_x", "0.0", FCVAR_ARCHIVE ); // the viewmodel offset from default in X
  33. ConVar viewmodel_offset_y( "viewmodel_offset_y", "0.0", FCVAR_ARCHIVE ); // the viewmodel offset from default in Y
  34. ConVar viewmodel_offset_z( "viewmodel_offset_z", "0.0", FCVAR_ARCHIVE ); // the viewmodel offset from default in Z
  35. #endif
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. //-----------------------------------------------------------------------------
  39. CBaseViewModel::CBaseViewModel()
  40. {
  41. #if defined( CLIENT_DLL )
  42. // NOTE: We do this here because the color is never transmitted for the view model.
  43. m_nOldAnimationParity = 0;
  44. m_EntClientFlags |= ENTCLIENTFLAG_ALWAYS_INTERPOLATE;
  45. RenderWithViewModels( true );
  46. m_flStatTrakGlowMultiplier = 0.0f;
  47. m_flStatTrakGlowMultiplierIdeal = 0.0f;
  48. m_szLastSound[0] = '\0';
  49. m_flLastSoundTime = 0.0f;
  50. m_flCamDriverAppliedTime = 0;
  51. m_flCamDriverWeight = 0;
  52. m_vecCamDriverLastPos.Init();
  53. m_angCamDriverLastAng.Init();
  54. #ifdef IRONSIGHT
  55. m_bScopeStencilMaskModeEnabled = false;
  56. #endif
  57. #endif
  58. SetRenderColor( 255, 255, 255 );
  59. SetRenderAlpha( 255 );
  60. // View model of this weapon
  61. m_sVMName = NULL_STRING;
  62. // Prefix of the animations that should be used by the player carrying this weapon
  63. m_sAnimationPrefix = NULL_STRING;
  64. m_nViewModelIndex = 0;
  65. m_nAnimationParity = 0;
  66. m_bShouldIgnoreOffsetAndAccuracy = false;
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. CBaseViewModel::~CBaseViewModel()
  72. {
  73. }
  74. void CBaseViewModel::UpdateOnRemove( void )
  75. {
  76. BaseClass::UpdateOnRemove();
  77. DestroyControlPanels();
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. //-----------------------------------------------------------------------------
  82. void CBaseViewModel::Precache( void )
  83. {
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CBaseViewModel::Spawn( void )
  89. {
  90. Precache( );
  91. SetSize( Vector( -8, -4, -2), Vector(8, 4, 2) );
  92. SetSolid( SOLID_NONE );
  93. }
  94. #if defined ( CSTRIKE_DLL ) && !defined ( CLIENT_DLL )
  95. #define VGUI_CONTROL_PANELS
  96. #endif
  97. #if defined ( TF_DLL )
  98. #define VGUI_CONTROL_PANELS
  99. #endif
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CBaseViewModel::SetControlPanelsActive( bool bState )
  104. {
  105. #if defined( VGUI_CONTROL_PANELS )
  106. // Activate control panel screens
  107. for ( int i = m_hScreens.Count(); --i >= 0; )
  108. {
  109. if (m_hScreens[i].Get())
  110. {
  111. m_hScreens[i]->SetActive( bState );
  112. }
  113. }
  114. #endif
  115. }
  116. //-----------------------------------------------------------------------------
  117. // This is called by the base object when it's time to spawn the control panels
  118. //-----------------------------------------------------------------------------
  119. void CBaseViewModel::SpawnControlPanels()
  120. {
  121. #if defined( VGUI_CONTROL_PANELS )
  122. char buf[64];
  123. // Destroy existing panels
  124. DestroyControlPanels();
  125. CBaseCombatWeapon *weapon = m_hWeapon.Get();
  126. if ( weapon == NULL )
  127. {
  128. return;
  129. }
  130. MDLCACHE_CRITICAL_SECTION();
  131. // FIXME: Deal with dynamically resizing control panels?
  132. // If we're attached to an entity, spawn control panels on it instead of use
  133. CBaseAnimating *pEntityToSpawnOn = this;
  134. char *pOrgLL = "controlpanel%d_ll";
  135. char *pOrgUR = "controlpanel%d_ur";
  136. char *pAttachmentNameLL = pOrgLL;
  137. char *pAttachmentNameUR = pOrgUR;
  138. /*
  139. if ( IsBuiltOnAttachment() )
  140. {
  141. pEntityToSpawnOn = dynamic_cast<CBaseAnimating*>((CBaseEntity*)m_hBuiltOnEntity.Get());
  142. if ( pEntityToSpawnOn )
  143. {
  144. char sBuildPointLL[64];
  145. char sBuildPointUR[64];
  146. Q_snprintf( sBuildPointLL, sizeof( sBuildPointLL ), "bp%d_controlpanel%%d_ll", m_iBuiltOnPoint );
  147. Q_snprintf( sBuildPointUR, sizeof( sBuildPointUR ), "bp%d_controlpanel%%d_ur", m_iBuiltOnPoint );
  148. pAttachmentNameLL = sBuildPointLL;
  149. pAttachmentNameUR = sBuildPointUR;
  150. }
  151. else
  152. {
  153. pEntityToSpawnOn = this;
  154. }
  155. }
  156. */
  157. Assert( pEntityToSpawnOn );
  158. // Lookup the attachment point...
  159. int nPanel;
  160. for ( nPanel = 0; true; ++nPanel )
  161. {
  162. Q_snprintf( buf, sizeof( buf ), pAttachmentNameLL, nPanel );
  163. int nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
  164. if (nLLAttachmentIndex <= 0)
  165. {
  166. // Try and use my panels then
  167. pEntityToSpawnOn = this;
  168. Q_snprintf( buf, sizeof( buf ), pOrgLL, nPanel );
  169. nLLAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
  170. if (nLLAttachmentIndex <= 0)
  171. return;
  172. }
  173. Q_snprintf( buf, sizeof( buf ), pAttachmentNameUR, nPanel );
  174. int nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
  175. if (nURAttachmentIndex <= 0)
  176. {
  177. // Try and use my panels then
  178. Q_snprintf( buf, sizeof( buf ), pOrgUR, nPanel );
  179. nURAttachmentIndex = pEntityToSpawnOn->LookupAttachment(buf);
  180. if (nURAttachmentIndex <= 0)
  181. return;
  182. }
  183. const char *pScreenName;
  184. weapon->GetControlPanelInfo( nPanel, pScreenName );
  185. if (!pScreenName)
  186. continue;
  187. const char *pScreenClassname;
  188. weapon->GetControlPanelClassName( nPanel, pScreenClassname );
  189. if ( !pScreenClassname )
  190. continue;
  191. // Compute the screen size from the attachment points...
  192. matrix3x4_t panelToWorld;
  193. pEntityToSpawnOn->GetAttachment( nLLAttachmentIndex, panelToWorld );
  194. matrix3x4_t worldToPanel;
  195. MatrixInvert( panelToWorld, worldToPanel );
  196. // Now get the lower right position + transform into panel space
  197. Vector lr, lrlocal;
  198. pEntityToSpawnOn->GetAttachment( nURAttachmentIndex, panelToWorld );
  199. MatrixGetColumn( panelToWorld, 3, lr );
  200. VectorTransform( lr, worldToPanel, lrlocal );
  201. // Not sure why, but the transform for the vgui panel to the world is improperly scaling.
  202. // We add a fudge value here to compensate.
  203. const float SCALE_FUDGE = 1.6f;
  204. float flWidth = fabs( lrlocal.x ) * SCALE_FUDGE;
  205. float flHeight = fabs( lrlocal.y ) * SCALE_FUDGE;
  206. CVGuiScreen *pScreen = CreateVGuiScreen( pScreenClassname, pScreenName, pEntityToSpawnOn, this, nLLAttachmentIndex );
  207. pScreen->ChangeTeam( GetTeamNumber() );
  208. pScreen->SetActualSize( flWidth, flHeight );
  209. pScreen->SetActive( false );
  210. pScreen->MakeVisibleOnlyToTeammates( false );
  211. pScreen->SetAttachedToViewModel( true );
  212. int nScreen = m_hScreens.AddToTail( );
  213. m_hScreens[nScreen].Set( pScreen );
  214. }
  215. #endif
  216. }
  217. void CBaseViewModel::DestroyControlPanels()
  218. {
  219. #if defined( VGUI_CONTROL_PANELS )
  220. // Kill the control panels
  221. int i;
  222. for ( i = m_hScreens.Count(); --i >= 0; )
  223. {
  224. DestroyVGuiScreen( m_hScreens[i].Get() );
  225. }
  226. m_hScreens.RemoveAll();
  227. #endif
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose:
  231. // Input : *pEntity -
  232. //-----------------------------------------------------------------------------
  233. void CBaseViewModel::SetOwner( CBaseEntity *pEntity )
  234. {
  235. m_hOwner = pEntity;
  236. #if !defined( CLIENT_DLL )
  237. // Make sure we're linked into hierarchy
  238. //SetParent( pEntity );
  239. #endif
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose:
  243. // Input : nIndex -
  244. //-----------------------------------------------------------------------------
  245. void CBaseViewModel::SetIndex( int nIndex )
  246. {
  247. m_nViewModelIndex = nIndex;
  248. Assert( m_nViewModelIndex < (1 << VIEWMODEL_INDEX_BITS) );
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose:
  252. //-----------------------------------------------------------------------------
  253. int CBaseViewModel::ViewModelIndex( ) const
  254. {
  255. return m_nViewModelIndex;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose: Pass our visibility on to our child screens
  259. //-----------------------------------------------------------------------------
  260. void CBaseViewModel::AddEffects( int nEffects )
  261. {
  262. if ( nEffects & EF_NODRAW )
  263. {
  264. SetControlPanelsActive( false );
  265. }
  266. BaseClass::AddEffects( nEffects );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Pass our visibility on to our child screens
  270. //-----------------------------------------------------------------------------
  271. void CBaseViewModel::RemoveEffects( int nEffects )
  272. {
  273. if ( nEffects & EF_NODRAW )
  274. {
  275. SetControlPanelsActive( true );
  276. }
  277. BaseClass::RemoveEffects( nEffects );
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. // Input : *modelname -
  282. //-----------------------------------------------------------------------------
  283. void CBaseViewModel::SetWeaponModel( const char *modelname, CBaseCombatWeapon *weapon )
  284. {
  285. m_hWeapon = weapon;
  286. #if defined( CLIENT_DLL )
  287. SetModel( modelname );
  288. #else
  289. string_t str;
  290. if ( modelname != NULL )
  291. {
  292. str = MAKE_STRING( modelname );
  293. }
  294. else
  295. {
  296. str = NULL_STRING;
  297. }
  298. if ( str != m_sVMName )
  299. {
  300. // Msg( "SetWeaponModel %s at %f\n", modelname, gpGlobals->curtime );
  301. m_sVMName = str;
  302. SetModel( STRING( m_sVMName ) );
  303. // Create any vgui control panels associated with the weapon
  304. SpawnControlPanels();
  305. bool showControlPanels = weapon && weapon->ShouldShowControlPanels();
  306. SetControlPanelsActive( showControlPanels );
  307. }
  308. #endif
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose:
  312. // Output : CBaseCombatWeapon
  313. //-----------------------------------------------------------------------------
  314. CBaseCombatWeapon *CBaseViewModel::GetOwningWeapon( void )
  315. {
  316. return m_hWeapon.Get();
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose:
  320. // Input : sequence -
  321. //-----------------------------------------------------------------------------
  322. void CBaseViewModel::SendViewModelMatchingSequence( int sequence )
  323. {
  324. // since all we do is send a sequence number down to the client,
  325. // set this here so other weapons code knows which sequence is playing.
  326. SetSequence( sequence );
  327. m_nAnimationParity = ( m_nAnimationParity + 1 ) & ( (1<<VIEWMODEL_ANIMATION_PARITY_BITS) - 1 );
  328. #if defined( CLIENT_DLL )
  329. m_nOldAnimationParity = m_nAnimationParity;
  330. // Force frame interpolation to start at exactly frame zero
  331. m_flAnimTime = gpGlobals->curtime;
  332. #else
  333. CBaseCombatWeapon *weapon = m_hWeapon.Get();
  334. bool showControlPanels = weapon && weapon->ShouldShowControlPanels();
  335. SetControlPanelsActive( showControlPanels );
  336. #endif
  337. // Restart animation at frame 0
  338. SetCycle( 0 );
  339. ResetSequenceInfo();
  340. }
  341. #if defined( CLIENT_DLL )
  342. #include "ivieweffects.h"
  343. #endif
  344. #ifdef CLIENT_DLL
  345. void CBaseViewModel::PostBuildTransformations( CStudioHdr *pStudioHdr, BoneVector *pos, BoneQuaternion q[] )
  346. {
  347. int nCamDriverBone = LookupBone( "cam_driver" );
  348. if ( nCamDriverBone != -1 )
  349. {
  350. m_flCamDriverAppliedTime = gpGlobals->curtime;
  351. VectorCopy( pos[nCamDriverBone], m_vecCamDriverLastPos );
  352. QuaternionAngles( q[nCamDriverBone], m_angCamDriverLastAng );
  353. if ( ShouldFlipModel() )
  354. {
  355. m_angCamDriverLastAng[YAW] = -m_angCamDriverLastAng[YAW];
  356. m_vecCamDriverLastPos.y = -m_vecCamDriverLastPos.y;
  357. }
  358. }
  359. }
  360. #endif
  361. void CBaseViewModel::CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, const QAngle& eyeAngles )
  362. {
  363. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  364. #ifdef CLIENT_DLL
  365. // apply viewmodel pose param
  366. if ( owner )
  367. {
  368. CBaseCSGrenade* pGrenade = dynamic_cast<CBaseCSGrenade*>( owner->GetActiveWeapon() );
  369. if ( pGrenade )
  370. {
  371. int iPoseParam = LookupPoseParameter( "throwcharge" );
  372. if ( iPoseParam != -1 )
  373. SetPoseParameter( iPoseParam, clamp(pGrenade->ApproachThrownStrength(), 0.0f, 1.0f) );
  374. }
  375. }
  376. #endif
  377. #endif
  378. // UNDONE: Calc this on the server? Disabled for now as it seems unnecessary to have this info on the server
  379. #if defined( CLIENT_DLL )
  380. QAngle vmangoriginal = eyeAngles;
  381. QAngle vmangles = eyeAngles;
  382. Vector vmorigin = eyePosition;
  383. Vector vecRight;
  384. Vector vecUp;
  385. Vector vecForward;
  386. AngleVectors( vmangoriginal, &vecForward, &vecRight, &vecUp );
  387. //Vector vecOffset = Vector( viewmodel_offset_x.GetFloat(), viewmodel_offset_y.GetFloat(), viewmodel_offset_z.GetFloat() );
  388. if ( !m_bShouldIgnoreOffsetAndAccuracy )
  389. {
  390. #ifdef IRONSIGHT
  391. CWeaponCSBase *pIronSightWeapon = (CWeaponCSBase*)owner->GetActiveWeapon();
  392. if ( pIronSightWeapon )
  393. {
  394. CIronSightController* pIronSightController = pIronSightWeapon->GetIronSightController();
  395. if ( pIronSightController && pIronSightController->IsInIronSight() )
  396. {
  397. float flInvIronSightAmount = ( 1.0f - pIronSightController->GetIronSightAmount() );
  398. vecForward *= flInvIronSightAmount;
  399. vecUp *= flInvIronSightAmount;
  400. vecRight *= flInvIronSightAmount;
  401. }
  402. }
  403. #endif
  404. vmorigin += (vecForward * viewmodel_offset_y.GetFloat()) + (vecUp * viewmodel_offset_z.GetFloat()) + (vecRight * viewmodel_offset_x.GetFloat());
  405. }
  406. // TrackIR
  407. if ( IsHeadTrackingEnabled() )
  408. {
  409. vmorigin = owner->EyePosition();
  410. VectorAngles( owner->GetAutoaimVector( AUTOAIM_5DEGREES ), vmangoriginal );
  411. vmangles = vmangoriginal;
  412. }
  413. // TrackIR
  414. CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
  415. //Allow weapon lagging
  416. if ( pWeapon != NULL )
  417. {
  418. if ( !prediction->InPrediction() )
  419. {
  420. // add weapon-specific bob
  421. pWeapon->AddViewmodelBob( this, vmorigin, vmangles );
  422. #if defined ( CSTRIKE_DLL )
  423. CalcViewModelLag( vmorigin, vmangles, vmangoriginal );
  424. #endif
  425. }
  426. }
  427. // Add model-specific bob even if no weapon associated (for head bob for off hand models)
  428. AddViewModelBob( owner, vmorigin, vmangles );
  429. #if !defined ( CSTRIKE_DLL )
  430. // This was causing weapon jitter when rotating in updated CS:S; original Source had this in above InPrediction block 07/14/10
  431. // Add lag
  432. CalcViewModelLag( vmorigin, vmangles, vmangoriginal );
  433. #endif
  434. if ( !prediction->InPrediction() )
  435. {
  436. // Let the viewmodel shake at about 10% of the amplitude of the player's view
  437. ACTIVE_SPLITSCREEN_PLAYER_GUARD_ENT( GetOwner() );
  438. GetViewEffects()->ApplyShake( vmorigin, vmangles, 0.1 );
  439. }
  440. SetLocalOrigin( vmorigin );
  441. SetLocalAngles( vmangles );
  442. #endif //#if defined( CLIENT_DLL )
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose:
  446. //-----------------------------------------------------------------------------
  447. void CBaseViewModel::CalcViewModelLag( Vector& origin, QAngle& angles, QAngle& original_angles )
  448. {
  449. Vector vOriginalOrigin = origin;
  450. QAngle vOriginalAngles = angles;
  451. // Calculate our drift
  452. Vector forward;
  453. AngleVectors( angles, &forward, NULL, NULL );
  454. if ( gpGlobals->frametime != 0.0f )
  455. {
  456. Vector vDifference;
  457. VectorSubtract( forward, m_vecLastFacing, vDifference );
  458. float flSpeed = 5.0f;
  459. // If we start to lag too far behind, we'll increase the "catch up" speed. Solves the problem with fast cl_yawspeed, m_yaw or joysticks
  460. // rotating quickly. The old code would slam lastfacing with origin causing the viewmodel to pop to a new position
  461. float flDiff = vDifference.Length();
  462. if ( flDiff > 1.5f )
  463. {
  464. float flScale = flDiff / 1.5f;
  465. flSpeed *= flScale;
  466. }
  467. // FIXME: Needs to be predictable?
  468. VectorMA( m_vecLastFacing, flSpeed * gpGlobals->frametime, vDifference, m_vecLastFacing );
  469. // Make sure it doesn't grow out of control!!!
  470. VectorNormalize( m_vecLastFacing );
  471. VectorMA( origin, 5.0f, vDifference * -1.0f, origin );
  472. Assert( m_vecLastFacing.IsValid() );
  473. }
  474. #if !defined( PORTAL ) //floor/wall floor/floor portals cause a sudden and large pitch change, causing a pop unless we write a bunch of interpolation code. Easier to just disable this
  475. Vector right, up;
  476. AngleVectors( original_angles, &forward, &right, &up );
  477. float pitch = original_angles[ PITCH ];
  478. if ( pitch > 180.0f )
  479. pitch -= 360.0f;
  480. else if ( pitch < -180.0f )
  481. pitch += 360.0f;
  482. //FIXME: These are the old settings that caused too many exposed polys on some models
  483. VectorMA( origin, -pitch * 0.035f, forward, origin );
  484. VectorMA( origin, -pitch * 0.03f, right, origin );
  485. VectorMA( origin, -pitch * 0.02f, up, origin);
  486. #endif
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Stub to keep networking consistent for DEM files
  490. //-----------------------------------------------------------------------------
  491. #if defined( CLIENT_DLL )
  492. extern void RecvProxy_EffectFlags( const CRecvProxyData *pData, void *pStruct, void *pOut );
  493. void RecvProxy_ViewmodelSequenceNum( const CRecvProxyData *pData, void *pStruct, void *pOut );
  494. void RecvProxy_Viewmodel( const CRecvProxyData *pData, void *pStruct, void *pOut );
  495. #endif
  496. //-----------------------------------------------------------------------------
  497. // Purpose: Resets anim cycle when the server changes the weapon on us
  498. //-----------------------------------------------------------------------------
  499. #if defined( CLIENT_DLL )
  500. static void RecvProxy_Weapon( const CRecvProxyData *pData, void *pStruct, void *pOut )
  501. {
  502. CBaseViewModel *pViewModel = ((CBaseViewModel*)pStruct);
  503. CBaseCombatWeapon *pOldWeapon = pViewModel->GetOwningWeapon();
  504. bool bViewModelWasVisible = pViewModel->IsVisible();
  505. // Chain through to the default recieve proxy ...
  506. RecvProxy_IntToEHandle( pData, pStruct, pOut );
  507. // ... and reset our cycle index if the server is switching weapons on us
  508. CBaseCombatWeapon *pNewWeapon = pViewModel->GetOwningWeapon();
  509. if ( pNewWeapon != pOldWeapon || !bViewModelWasVisible )
  510. {
  511. // Restart animation at frame 0
  512. pViewModel->SetCycle( 0 );
  513. pViewModel->m_flAnimTime = gpGlobals->curtime;
  514. }
  515. }
  516. static void RecvProxy_Owner( const CRecvProxyData *pData, void *pStruct, void *pOut )
  517. {
  518. CBaseViewModel *pViewModel = ( ( CBaseViewModel* )pStruct );
  519. //Msg( "BaseViewModel changed from (%d)%x", ( pViewModel->m_hOwner.GetForModify().GetSerialNumber(), pViewModel->m_hOwner.GetForModify().GetEntryIndex() ) );
  520. // Chain through to the default recieve proxy ...
  521. RecvProxy_IntToEHandle( pData, pStruct, pOut );
  522. //Msg( " to (%d)%x\n", ( pViewModel->m_hOwner.GetForModify().GetSerialNumber(), pViewModel->m_hOwner.GetForModify().GetEntryIndex() ) );
  523. pViewModel->UpdateVisibility(); // visibility of a viewmodel is owner-dependant, and other events like SetDormant() may happen out of order with setting owner, especially when doing full frame update after spectator mode, which happens most often (pretty much exclusively) after HLTV replay ends.
  524. }
  525. #endif
  526. IMPLEMENT_NETWORKCLASS_ALIASED( BaseViewModel, DT_BaseViewModel )
  527. LINK_ENTITY_TO_CLASS_ALIASED( viewmodel, BaseViewModel );
  528. BEGIN_NETWORK_TABLE_NOBASE(CBaseViewModel, DT_BaseViewModel)
  529. #if !defined( CLIENT_DLL )
  530. SendPropModelIndex(SENDINFO(m_nModelIndex)),
  531. SendPropEHandle (SENDINFO(m_hWeapon)),
  532. SendPropInt (SENDINFO(m_nBody), ANIMATION_BODY_BITS ), // increased to 32 bits to support number of bits equal to number of bodygroups
  533. SendPropInt (SENDINFO(m_nSkin), 10),
  534. SendPropInt (SENDINFO(m_nSequence), 8, SPROP_UNSIGNED),
  535. SendPropInt (SENDINFO(m_nViewModelIndex), VIEWMODEL_INDEX_BITS, SPROP_UNSIGNED),
  536. SendPropFloat (SENDINFO(m_flPlaybackRate), 8, SPROP_ROUNDUP, -4.0, 12.0f),
  537. SendPropInt (SENDINFO(m_fEffects), EF_MAX_BITS, SPROP_UNSIGNED),
  538. SendPropInt (SENDINFO(m_nAnimationParity), 3, SPROP_UNSIGNED ),
  539. SendPropEHandle (SENDINFO(m_hOwner)),
  540. SendPropInt( SENDINFO( m_nNewSequenceParity ), EF_PARITY_BITS, SPROP_UNSIGNED ),
  541. SendPropInt( SENDINFO( m_nResetEventsParity ), EF_PARITY_BITS, SPROP_UNSIGNED ),
  542. SendPropInt( SENDINFO( m_nMuzzleFlashParity ), EF_MUZZLEFLASH_BITS, SPROP_UNSIGNED ),
  543. SendPropBool( SENDINFO( m_bShouldIgnoreOffsetAndAccuracy ) ),
  544. #else
  545. RecvPropInt (RECVINFO(m_nModelIndex), 0, RecvProxy_Viewmodel ),
  546. RecvPropEHandle (RECVINFO(m_hWeapon), RecvProxy_Weapon ),
  547. RecvPropInt (RECVINFO(m_nSkin)),
  548. RecvPropInt (RECVINFO(m_nBody)),
  549. RecvPropInt (RECVINFO(m_nSequence), 0, RecvProxy_ViewmodelSequenceNum ),
  550. RecvPropInt (RECVINFO(m_nViewModelIndex)),
  551. RecvPropFloat (RECVINFO(m_flPlaybackRate)),
  552. RecvPropInt (RECVINFO(m_fEffects), 0, RecvProxy_EffectFlags ),
  553. RecvPropInt (RECVINFO(m_nAnimationParity)),
  554. RecvPropEHandle (RECVINFO(m_hOwner), RecvProxy_Owner ),
  555. RecvPropInt( RECVINFO( m_nNewSequenceParity )),
  556. RecvPropInt( RECVINFO( m_nResetEventsParity )),
  557. RecvPropInt( RECVINFO( m_nMuzzleFlashParity )),
  558. RecvPropBool( RECVINFO( m_bShouldIgnoreOffsetAndAccuracy ) ),
  559. #endif
  560. END_NETWORK_TABLE()
  561. #ifdef CLIENT_DLL
  562. BEGIN_PREDICTION_DATA( CBaseViewModel )
  563. // Networked
  564. DEFINE_PRED_FIELD( m_nModelIndex, FIELD_SHORT, FTYPEDESC_INSENDTABLE | FTYPEDESC_MODELINDEX ),
  565. DEFINE_PRED_FIELD( m_nSkin, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  566. DEFINE_PRED_FIELD( m_nBody, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  567. DEFINE_PRED_FIELD( m_nSequence, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  568. DEFINE_PRED_FIELD( m_nViewModelIndex, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  569. DEFINE_PRED_FIELD_TOL( m_flPlaybackRate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.125f ),
  570. DEFINE_PRED_FIELD( m_fEffects, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_OVERRIDE ),
  571. DEFINE_PRED_FIELD( m_nAnimationParity, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  572. DEFINE_PRED_FIELD( m_hWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
  573. DEFINE_PRED_FIELD( m_flAnimTime, FIELD_FLOAT, 0 ),
  574. DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
  575. DEFINE_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT ),
  576. DEFINE_FIELD( m_Activity, FIELD_INTEGER ),
  577. DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_PRIVATE | FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
  578. END_PREDICTION_DATA()
  579. // This needed to be done as a proxy for the surrounding box auto update when animations change.
  580. // This doesn't have to be done for view models as they don't affect the bounding box and it was
  581. // causing some timing problems with our world to view model under the covers swap.
  582. // [msmith] Added back in for CS:GO because without this the m_nSequence number gets reset during prediction causing
  583. // view model animations to freeze up. This issue is probably caused by the fact that prediction doesn't fix up
  584. // m_nSequence, but this fixes it and makes it consistent with CS:S ... which also has the same prediction issues.
  585. void RecvProxy_ViewmodelSequenceNum( const CRecvProxyData *pData, void *pStruct, void *pOut )
  586. {
  587. CBaseViewModel *model = (CBaseViewModel *)pStruct;
  588. if (pData->m_Value.m_Int != model->GetSequence())
  589. {
  590. MDLCACHE_CRITICAL_SECTION();
  591. model->SetSequence(pData->m_Value.m_Int);
  592. model->m_flAnimTime = gpGlobals->curtime;
  593. model->SetCycle(0);
  594. }
  595. }
  596. void RecvProxy_Viewmodel( const CRecvProxyData *pData, void *pStruct, void *pOut )
  597. {
  598. // We assign the model index via the SetModelByIndex function so that the model pointer gets updated as soon as we change the model index.
  599. // This is necessary since this new model may be accessed with frame.
  600. // An example is the SetSequence code in RecvProxy_ViewmodelSequenceNum that checks to make sure the sequence number is in range of those available in
  601. // model.
  602. CBaseViewModel *model = (CBaseViewModel *)pStruct;
  603. if ( model )
  604. {
  605. MDLCACHE_CRITICAL_SECTION();
  606. model->SetModelByIndex( pData->m_Value.m_Int );
  607. }
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Purpose:
  611. //-----------------------------------------------------------------------------
  612. int CBaseViewModel::LookupAttachment( const char *pAttachmentName )
  613. {
  614. if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
  615. return m_hWeapon.Get()->LookupAttachment( pAttachmentName );
  616. return BaseClass::LookupAttachment( pAttachmentName );
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Purpose:
  620. //-----------------------------------------------------------------------------
  621. bool CBaseViewModel::GetAttachment( int number, matrix3x4_t &matrix )
  622. {
  623. if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
  624. return m_hWeapon.Get()->GetAttachment( number, matrix );
  625. return BaseClass::GetAttachment( number, matrix );
  626. }
  627. //-----------------------------------------------------------------------------
  628. // Purpose:
  629. //-----------------------------------------------------------------------------
  630. bool CBaseViewModel::GetAttachment( int number, Vector &origin )
  631. {
  632. if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
  633. return m_hWeapon.Get()->GetAttachment( number, origin );
  634. return BaseClass::GetAttachment( number, origin );
  635. }
  636. //-----------------------------------------------------------------------------
  637. // Purpose:
  638. //-----------------------------------------------------------------------------
  639. bool CBaseViewModel::GetAttachment( int number, Vector &origin, QAngle &angles )
  640. {
  641. if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
  642. return m_hWeapon.Get()->GetAttachment( number, origin, angles );
  643. return BaseClass::GetAttachment( number, origin, angles );
  644. }
  645. //-----------------------------------------------------------------------------
  646. // Purpose:
  647. //-----------------------------------------------------------------------------
  648. bool CBaseViewModel::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
  649. {
  650. if ( m_hWeapon.Get() && m_hWeapon.Get()->WantsToOverrideViewmodelAttachments() )
  651. return m_hWeapon.Get()->GetAttachmentVelocity( number, originVel, angleVel );
  652. return BaseClass::GetAttachmentVelocity( number, originVel, angleVel );
  653. }
  654. #endif