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.

274 lines
9.6 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "cbase.h"
  10. #include "c_basetempentity.h"
  11. #include "networkstringtable_clientdll.h"
  12. #include "effect_dispatch_data.h"
  13. #include "c_te_effect_dispatch.h"
  14. #include "tier1/keyvalues.h"
  15. #include "toolframework_client.h"
  16. #include "tier0/vprof.h"
  17. #include "particles_new.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //-----------------------------------------------------------------------------
  21. // CClientEffectRegistration registration
  22. //-----------------------------------------------------------------------------
  23. CClientEffectRegistration *CClientEffectRegistration::s_pHead = NULL;
  24. CClientEffectRegistration::CClientEffectRegistration( const char *pEffectName, ClientEffectCallback fn )
  25. {
  26. AssertMsg1( pEffectName[0] != '\"', "Error: Effect %s. "
  27. "Remove quotes around the effect name in DECLARE_CLIENT_EFFECT.\n", pEffectName );
  28. m_pEffectName = pEffectName;
  29. m_pFunction = fn;
  30. m_pNext = s_pHead;
  31. s_pHead = this;
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Purpose: EffectDispatch TE
  35. //-----------------------------------------------------------------------------
  36. class C_TEEffectDispatch : public C_BaseTempEntity
  37. {
  38. public:
  39. DECLARE_CLASS( C_TEEffectDispatch, C_BaseTempEntity );
  40. DECLARE_CLIENTCLASS();
  41. C_TEEffectDispatch( void );
  42. virtual ~C_TEEffectDispatch( void );
  43. virtual void PostDataUpdate( DataUpdateType_t updateType );
  44. public:
  45. CEffectData m_EffectData;
  46. };
  47. //-----------------------------------------------------------------------------
  48. // Purpose:
  49. //-----------------------------------------------------------------------------
  50. C_TEEffectDispatch::C_TEEffectDispatch( void )
  51. {
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. C_TEEffectDispatch::~C_TEEffectDispatch( void )
  57. {
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Purpose:
  61. //-----------------------------------------------------------------------------
  62. void DispatchEffectToCallback( const char *pEffectName, const CEffectData &m_EffectData )
  63. {
  64. // Built a faster lookup
  65. static CUtlStringMap< CClientEffectRegistration* > map;
  66. static bool bInitializedMap = false;
  67. if ( !bInitializedMap )
  68. {
  69. for ( CClientEffectRegistration *pReg = CClientEffectRegistration::s_pHead; pReg; pReg = pReg->m_pNext )
  70. {
  71. // If the name matches, call it
  72. if ( map.Defined( pReg->m_pEffectName ) )
  73. {
  74. Warning( "Encountered multiple different effects with the same name \"%s\"!\n", pReg->m_pEffectName );
  75. continue;
  76. }
  77. map[ pReg->m_pEffectName ] = pReg;
  78. }
  79. bInitializedMap = true;
  80. }
  81. // Look through all the registered callbacks
  82. UtlSymId_t nSym = map.Find( pEffectName );
  83. if ( nSym == UTL_INVAL_SYMBOL )
  84. {
  85. Warning("DispatchEffect: effect \"%s\" not found on client\n", pEffectName );
  86. return;
  87. }
  88. // NOTE: Here, we want to scope resource access to only be able to use
  89. // those resources specified as being dependencies of this effect
  90. g_pPrecacheSystem->LimitResourceAccess( DISPATCH_EFFECT, pEffectName );
  91. map[nSym]->m_pFunction( m_EffectData );
  92. // NOTE: Here, we no longer need to restrict resource access
  93. g_pPrecacheSystem->EndLimitedResourceAccess( );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Record effects
  97. //-----------------------------------------------------------------------------
  98. static void RecordEffect( const char *pEffectName, const CEffectData &data )
  99. {
  100. if ( !ToolsEnabled() )
  101. return;
  102. if ( clienttools->IsInRecordingMode() && ( (data.m_fFlags & EFFECTDATA_NO_RECORD) == 0 ) )
  103. {
  104. KeyValues *msg = new KeyValues( "TempEntity" );
  105. const char *pSurfacePropName = physprops->GetPropName( data.m_nSurfaceProp );
  106. char pName[1024];
  107. Q_snprintf( pName, sizeof(pName), "TE_DispatchEffect %s %s", pEffectName, pSurfacePropName );
  108. msg->SetInt( "te", TE_DISPATCH_EFFECT );
  109. msg->SetString( "name", pName );
  110. msg->SetFloat( "time", gpGlobals->curtime );
  111. msg->SetFloat( "originx", data.m_vOrigin.x );
  112. msg->SetFloat( "originy", data.m_vOrigin.y );
  113. msg->SetFloat( "originz", data.m_vOrigin.z );
  114. msg->SetFloat( "startx", data.m_vStart.x );
  115. msg->SetFloat( "starty", data.m_vStart.y );
  116. msg->SetFloat( "startz", data.m_vStart.z );
  117. msg->SetFloat( "normalx", data.m_vNormal.x );
  118. msg->SetFloat( "normaly", data.m_vNormal.y );
  119. msg->SetFloat( "normalz", data.m_vNormal.z );
  120. msg->SetFloat( "anglesx", data.m_vAngles.x );
  121. msg->SetFloat( "anglesy", data.m_vAngles.y );
  122. msg->SetFloat( "anglesz", data.m_vAngles.z );
  123. msg->SetInt( "flags", data.m_fFlags );
  124. msg->SetFloat( "scale", data.m_flScale );
  125. msg->SetFloat( "magnitude", data.m_flMagnitude );
  126. msg->SetFloat( "radius", data.m_flRadius );
  127. msg->SetString( "surfaceprop", pSurfacePropName );
  128. msg->SetInt( "color", data.m_nColor );
  129. msg->SetInt( "damagetype", data.m_nDamageType );
  130. msg->SetInt( "hitbox", data.m_nHitBox );
  131. msg->SetString( "effectname", pEffectName );
  132. // FIXME: Need to write the attachment name here
  133. msg->SetInt( "attachmentindex", data.m_nAttachmentIndex );
  134. // NOTE: Ptrs are our way of indicating it's an entindex
  135. msg->SetPtr( "entindex", (void*)(intp)data.entindex() );
  136. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  137. msg->deleteThis();
  138. }
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose:
  142. //-----------------------------------------------------------------------------
  143. void C_TEEffectDispatch::PostDataUpdate( DataUpdateType_t updateType )
  144. {
  145. VPROF( "C_TEEffectDispatch::PostDataUpdate" );
  146. // Find the effect name.
  147. const char *pEffectName = g_StringTableEffectDispatch->GetString( m_EffectData.GetEffectNameIndex() );
  148. if ( pEffectName )
  149. {
  150. DispatchEffectToCallback( pEffectName, m_EffectData );
  151. RecordEffect( pEffectName, m_EffectData );
  152. }
  153. }
  154. IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEEffectDispatch, DT_TEEffectDispatch, CTEEffectDispatch )
  155. RecvPropDataTable( RECVINFO_DT( m_EffectData ), 0, &REFERENCE_RECV_TABLE( DT_EffectData ) )
  156. END_RECV_TABLE()
  157. //-----------------------------------------------------------------------------
  158. // Client version of dispatch effect, for predicted weapons
  159. //-----------------------------------------------------------------------------
  160. void DispatchEffect( IRecipientFilter& filter, float delay, const char *pName, const CEffectData &data )
  161. {
  162. if ( !te->SuppressTE( filter ) )
  163. {
  164. DispatchEffectToCallback( pName, data );
  165. RecordEffect( pName, data );
  166. }
  167. }
  168. void DispatchEffect( const char *pName, const CEffectData &data )
  169. {
  170. CPASFilter filter( data.m_vOrigin );
  171. if ( !te->SuppressTE( filter ) )
  172. {
  173. DispatchEffectToCallback( pName, data );
  174. RecordEffect( pName, data );
  175. }
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Playback
  179. //-----------------------------------------------------------------------------
  180. void DispatchEffect( IRecipientFilter& filter, float delay, KeyValues *pKeyValues )
  181. {
  182. CEffectData data;
  183. data.m_nMaterial = 0;
  184. data.m_vOrigin.x = pKeyValues->GetFloat( "originx" );
  185. data.m_vOrigin.y = pKeyValues->GetFloat( "originy" );
  186. data.m_vOrigin.z = pKeyValues->GetFloat( "originz" );
  187. data.m_vStart.x = pKeyValues->GetFloat( "startx" );
  188. data.m_vStart.y = pKeyValues->GetFloat( "starty" );
  189. data.m_vStart.z = pKeyValues->GetFloat( "startz" );
  190. data.m_vNormal.x = pKeyValues->GetFloat( "normalx" );
  191. data.m_vNormal.y = pKeyValues->GetFloat( "normaly" );
  192. data.m_vNormal.z = pKeyValues->GetFloat( "normalz" );
  193. data.m_vAngles.x = pKeyValues->GetFloat( "anglesx" );
  194. data.m_vAngles.y = pKeyValues->GetFloat( "anglesy" );
  195. data.m_vAngles.z = pKeyValues->GetFloat( "anglesz" );
  196. data.m_fFlags = pKeyValues->GetInt( "flags" );
  197. data.m_flScale = pKeyValues->GetFloat( "scale" );
  198. data.m_flMagnitude = pKeyValues->GetFloat( "magnitude" );
  199. data.m_flRadius = pKeyValues->GetFloat( "radius" );
  200. const char *pSurfaceProp = pKeyValues->GetString( "surfaceprop" );
  201. data.m_nSurfaceProp = physprops->GetSurfaceIndex( pSurfaceProp );
  202. data.m_nDamageType = pKeyValues->GetInt( "damagetype" );
  203. data.m_nHitBox = pKeyValues->GetInt( "hitbox" );
  204. data.m_nColor = pKeyValues->GetInt( "color" );
  205. data.m_nAttachmentIndex = pKeyValues->GetInt( "attachmentindex" );
  206. // NOTE: Ptrs are our way of indicating it's an entindex
  207. ClientEntityHandle_t hWorld = ClientEntityList().EntIndexToHandle( 0 );
  208. data.m_hEntity = ClientEntityHandle_t::UnsafeFromIndex( size_cast< int >( (intp) pKeyValues->GetPtr( "entindex", ( void* )(intp)hWorld.ToInt() ) ) );
  209. const char *pEffectName = pKeyValues->GetString( "effectname" );
  210. DispatchEffect( filter, 0.0f, pEffectName, data );
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose: Displays an error effect in case of missing precache
  214. //-----------------------------------------------------------------------------
  215. void ErrorEffectCallback( const CEffectData &data )
  216. {
  217. CSmartPtr<CNewParticleEffect> pEffect = CNewParticleEffect::Create( NULL, "error" );
  218. if ( pEffect->IsValid() )
  219. {
  220. pEffect->SetSortOrigin( data.m_vOrigin );
  221. pEffect->SetControlPoint( 0, data.m_vOrigin );
  222. pEffect->SetControlPoint( 1, data.m_vStart );
  223. Vector vecForward, vecRight, vecUp;
  224. AngleVectors( data.m_vAngles, &vecForward, &vecRight, &vecUp );
  225. pEffect->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
  226. }
  227. }
  228. DECLARE_CLIENT_EFFECT_BEGIN( Error, ErrorEffectCallback )
  229. PRECACHE( PARTICLE_SYSTEM, "error" )
  230. DECLARE_CLIENT_EFFECT_END()