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.

527 lines
18 KiB

  1. //========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Point entity used to create templates out of other entities or groups of entities
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "entityinput.h"
  8. #include "entityoutput.h"
  9. #include "TemplateEntities.h"
  10. #include "point_template.h"
  11. #include "saverestore_utlvector.h"
  12. #include "mapentities.h"
  13. #include "tier0/icommandline.h"
  14. #include "mapentities_shared.h"
  15. #include "spawn_helper_nut.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. #define SF_POINTTEMPLATE_DONTREMOVETEMPLATEENTITIES 0x0001
  19. // Level designers can suppress the uniquification of the spawned entity
  20. // names with a spawnflag, provided they guarantee that only one instance
  21. // of the entities will ever be spawned at a time.
  22. #define SF_POINTTEMPLATE_PRESERVE_NAMES 0x0002
  23. LINK_ENTITY_TO_CLASS(point_template, CPointTemplate);
  24. BEGIN_SIMPLE_DATADESC( template_t )
  25. DEFINE_FIELD( iTemplateIndex, FIELD_INTEGER ),
  26. DEFINE_FIELD( matEntityToTemplate, FIELD_VMATRIX ),
  27. END_DATADESC()
  28. BEGIN_DATADESC( CPointTemplate )
  29. // Keys
  30. // Silence, Classcheck!
  31. // DEFINE_ARRAY( m_iszTemplateEntityNames, FIELD_STRING, MAX_NUM_TEMPLATES ),
  32. DEFINE_KEYFIELD( m_iszTemplateEntityNames[0], FIELD_STRING, "Template01"),
  33. DEFINE_KEYFIELD( m_iszTemplateEntityNames[1], FIELD_STRING, "Template02"),
  34. DEFINE_KEYFIELD( m_iszTemplateEntityNames[2], FIELD_STRING, "Template03"),
  35. DEFINE_KEYFIELD( m_iszTemplateEntityNames[3], FIELD_STRING, "Template04"),
  36. DEFINE_KEYFIELD( m_iszTemplateEntityNames[4], FIELD_STRING, "Template05"),
  37. DEFINE_KEYFIELD( m_iszTemplateEntityNames[5], FIELD_STRING, "Template06"),
  38. DEFINE_KEYFIELD( m_iszTemplateEntityNames[6], FIELD_STRING, "Template07"),
  39. DEFINE_KEYFIELD( m_iszTemplateEntityNames[7], FIELD_STRING, "Template08"),
  40. DEFINE_KEYFIELD( m_iszTemplateEntityNames[8], FIELD_STRING, "Template09"),
  41. DEFINE_KEYFIELD( m_iszTemplateEntityNames[9], FIELD_STRING, "Template10"),
  42. DEFINE_KEYFIELD( m_iszTemplateEntityNames[10], FIELD_STRING, "Template11"),
  43. DEFINE_KEYFIELD( m_iszTemplateEntityNames[11], FIELD_STRING, "Template12"),
  44. DEFINE_KEYFIELD( m_iszTemplateEntityNames[12], FIELD_STRING, "Template13"),
  45. DEFINE_KEYFIELD( m_iszTemplateEntityNames[13], FIELD_STRING, "Template14"),
  46. DEFINE_KEYFIELD( m_iszTemplateEntityNames[14], FIELD_STRING, "Template15"),
  47. DEFINE_KEYFIELD( m_iszTemplateEntityNames[15], FIELD_STRING, "Template16"),
  48. DEFINE_UTLVECTOR( m_hTemplateEntities, FIELD_CLASSPTR ),
  49. DEFINE_UTLVECTOR( m_hTemplates, FIELD_EMBEDDED ),
  50. // Inputs
  51. DEFINE_INPUTFUNC( FIELD_VOID, "ForceSpawn", InputForceSpawn ),
  52. // Outputs
  53. DEFINE_OUTPUT( m_pOutputOnSpawned, "OnEntitySpawned" ),
  54. END_DATADESC()
  55. //-----------------------------------------------------------------------------
  56. // Purpose: A simple system to help precache point_template entities ... ywb
  57. //-----------------------------------------------------------------------------
  58. class CPointTemplatePrecacher : public CAutoGameSystem
  59. {
  60. public:
  61. CPointTemplatePrecacher( char const *name ) : CAutoGameSystem( name )
  62. {
  63. }
  64. void AddToPrecache( CPointTemplate *ent )
  65. {
  66. m_Ents.AddToTail( ent );
  67. }
  68. virtual void LevelInitPreEntity()
  69. {
  70. m_Ents.RemoveAll();
  71. }
  72. virtual void Shutdown()
  73. {
  74. m_Ents.RemoveAll();
  75. }
  76. void Precache()
  77. {
  78. int c = m_Ents.Count();
  79. for ( int i = 0 ; i < c; ++i )
  80. {
  81. CPointTemplate *ent = m_Ents[ i ].Get();
  82. if ( ent )
  83. {
  84. ent->PerformPrecache();
  85. }
  86. }
  87. m_Ents.RemoveAll();
  88. }
  89. private:
  90. CUtlVector< CHandle< CPointTemplate > > m_Ents;
  91. };
  92. CPointTemplatePrecacher g_PointTemplatePrecacher( "CPointTemplatePrecacher" );
  93. //-----------------------------------------------------------------------------
  94. // Purpose:
  95. //-----------------------------------------------------------------------------
  96. void PrecachePointTemplates()
  97. {
  98. g_PointTemplatePrecacher.Precache();
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CPointTemplate::Spawn( void )
  104. {
  105. Precache();
  106. ScriptInstallPreSpawnHook();
  107. }
  108. void CPointTemplate::Precache()
  109. {
  110. // We can't call precache right when we instance the template, we need to defer it until after all map entities have
  111. // been loaded, so add this template to a list which is cleared after map entity parsing is completed.
  112. g_PointTemplatePrecacher.AddToPrecache( this );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose: Level designers can suppress the uniquification of the spawned entity
  116. // names with a spawnflag, provided they guarantee that only one instance
  117. // of the entities will ever be spawned at a time.
  118. //-----------------------------------------------------------------------------
  119. bool CPointTemplate::AllowNameFixup()
  120. {
  121. return !HasSpawnFlags( SF_POINTTEMPLATE_PRESERVE_NAMES );
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: Called at the start of template initialization for this point_template.
  125. // Find all the entities referenced by this point_template, which will
  126. // then be turned into templates by the map-parsing code.
  127. //-----------------------------------------------------------------------------
  128. void CPointTemplate::StartBuildingTemplates( void )
  129. {
  130. // Build our list of template entities
  131. for ( int i = 0; i < MAX_NUM_TEMPLATES; i++ )
  132. {
  133. if ( m_iszTemplateEntityNames[i] != NULL_STRING )
  134. {
  135. CBaseEntity *pEntity = NULL;
  136. int iOldNum = m_hTemplateEntities.Count();
  137. // Add all the entities with the matching targetname
  138. while ( (pEntity = gEntList.FindEntityByName( pEntity, STRING(m_iszTemplateEntityNames[i]) )) != NULL )
  139. {
  140. m_hTemplateEntities.AddToTail( pEntity );
  141. }
  142. // Useful mapmaker warning
  143. if ( iOldNum == m_hTemplateEntities.Count() )
  144. {
  145. Warning( "Couldn't find any entities named %s, which point_template %s is specifying.\n", STRING(m_iszTemplateEntityNames[i]), STRING(GetEntityName()) );
  146. }
  147. }
  148. }
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose: Called at the end of template initialization for this point_template.
  152. // All of our referenced entities have now been destroyed.
  153. //-----------------------------------------------------------------------------
  154. void CPointTemplate::FinishBuildingTemplates( void )
  155. {
  156. // Our template entities are now gone, deleted by the server post turning them into templates.
  157. m_hTemplateEntities.Purge();
  158. // Now tell the template system to hook up all the Entity I/O connections within our set of templates.
  159. Templates_ReconnectIOForGroup( this );
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. //-----------------------------------------------------------------------------
  164. void CPointTemplate::AddTemplate( CBaseEntity *pEntity, const char *pszMapData, int nLen )
  165. {
  166. // Add it to the template list
  167. int iIndex = Templates_Add( pEntity, pszMapData, nLen );
  168. if ( iIndex == -1 )
  169. {
  170. Warning( "point_template %s failed to add template.\n", STRING(GetEntityName()) );
  171. return;
  172. }
  173. template_t newTemplate;
  174. newTemplate.iTemplateIndex = iIndex;
  175. // Store the entity's origin & angles in a matrix in the template's local space
  176. VMatrix matTemplateToWorld, matWorldToTemplate, matEntityToWorld, matEntityToTemplate;
  177. matTemplateToWorld.SetupMatrixOrgAngles( GetAbsOrigin(), GetAbsAngles() );
  178. matTemplateToWorld.InverseTR( matWorldToTemplate );
  179. matEntityToWorld.SetupMatrixOrgAngles( pEntity->GetAbsOrigin(), pEntity->GetAbsAngles() );
  180. MatrixMultiply( matWorldToTemplate, matEntityToWorld, matEntityToTemplate );
  181. newTemplate.matEntityToTemplate = matEntityToTemplate;
  182. m_hTemplates.AddToTail( newTemplate );
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose:
  186. //-----------------------------------------------------------------------------
  187. bool CPointTemplate::ShouldRemoveTemplateEntities( void )
  188. {
  189. return ( !(m_spawnflags & SF_POINTTEMPLATE_DONTREMOVETEMPLATEENTITIES) );
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Purpose:
  193. //-----------------------------------------------------------------------------
  194. int CPointTemplate::GetNumTemplates( void )
  195. {
  196. return m_hTemplates.Count();
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose:
  200. //-----------------------------------------------------------------------------
  201. int CPointTemplate::GetTemplateIndexForTemplate( int iTemplate )
  202. {
  203. Assert( iTemplate < m_hTemplates.Count() );
  204. return m_hTemplates[iTemplate].iTemplateIndex;
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Purpose:
  208. //-----------------------------------------------------------------------------
  209. int CPointTemplate::GetNumTemplateEntities( void )
  210. {
  211. return m_hTemplateEntities.Count();
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. CBaseEntity *CPointTemplate::GetTemplateEntity( int iTemplateNumber )
  217. {
  218. Assert( iTemplateNumber < m_hTemplateEntities.Count() );
  219. return m_hTemplateEntities[iTemplateNumber];
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose:
  223. //-----------------------------------------------------------------------------
  224. void CPointTemplate::PerformPrecache()
  225. {
  226. // Go through all our templated map data and precache all the entities in it
  227. int iTemplates = m_hTemplates.Count();
  228. if ( !iTemplates )
  229. {
  230. Msg("Precache called on a point_template that has no templates: %s\n", STRING(GetEntityName()) );
  231. return;
  232. }
  233. // Tell the template system we're about to start a new template
  234. Templates_StartUniqueInstance();
  235. //HierarchicalSpawn_t *pSpawnList = (HierarchicalSpawn_t*)stackalloc( iTemplates * sizeof(HierarchicalSpawn_t) );
  236. int i;
  237. for ( i = 0; i < iTemplates; i++ )
  238. {
  239. //CBaseEntity *pEntity = NULL;
  240. char *pMapData;
  241. int iTemplateIndex = m_hTemplates[i].iTemplateIndex;
  242. // Some templates have Entity I/O connecting the entities within the template.
  243. // Unique versions of these templates need to be created whenever they're instanced.
  244. int nStringSize;
  245. if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) )
  246. {
  247. // This template requires instancing.
  248. // Create a new mapdata block and ask the template system to fill it in with
  249. // a unique version (with fixed Entity I/O connections).
  250. pMapData = Templates_GetEntityIOFixedMapData( iTemplateIndex );
  251. }
  252. else
  253. {
  254. // Use the unmodified mapdata
  255. pMapData = (char*)STRING( Templates_FindByIndex( iTemplateIndex ) );
  256. }
  257. nStringSize = Templates_GetStringSize( iTemplateIndex );
  258. // Create the entity from the mapdata
  259. MapEntity_PrecacheEntity( pMapData, nStringSize );
  260. }
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Purpose: Spawn the entities I contain
  264. // Input : &vecOrigin -
  265. // &vecAngles -
  266. // pEntities -
  267. // pEntityMaker - The Entity Maker entity that invoked this call.
  268. // Output : Returns true on success, false on failure.
  269. //-----------------------------------------------------------------------------
  270. bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecAngles, CUtlVector<CBaseEntity*> *pEntities, CBaseEntity *pEntityMaker, bool bCreateTime )
  271. {
  272. // Go through all our templated map data and spawn all the entities in it
  273. int iTemplates = m_hTemplates.Count();
  274. if ( !iTemplates )
  275. {
  276. Msg("CreateInstance called on a point_template that has no templates: %s\n", STRING(GetEntityName()) );
  277. return false;
  278. }
  279. // Tell the template system we're about to start a new template
  280. Templates_StartUniqueInstance();
  281. HierarchicalSpawn_t *pSpawnList = (HierarchicalSpawn_t*)stackalloc( iTemplates * sizeof(HierarchicalSpawn_t) );
  282. int i;
  283. for ( i = 0; i < iTemplates; i++ )
  284. {
  285. CBaseEntity *pEntity = NULL;
  286. char *pMapData;
  287. int iTemplateIndex = m_hTemplates[i].iTemplateIndex;
  288. // Some templates have Entity I/O connecting the entities within the template.
  289. // Unique versions of these templates need to be created whenever they're instanced.
  290. if ( AllowNameFixup() && ( Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) || m_ScriptScope.IsInitialized() ) )
  291. {
  292. // This template requires instancing.
  293. // Create a new mapdata block and ask the template system to fill it in with
  294. // a unique version (with fixed Entity I/O connections).
  295. pMapData = Templates_GetEntityIOFixedMapData( iTemplateIndex );
  296. }
  297. else
  298. {
  299. // Use the unmodified mapdata
  300. pMapData = (char*)STRING( Templates_FindByIndex( iTemplateIndex ) );
  301. }
  302. // Create the entity from the mapdata
  303. MapEntity_ParseEntity( pEntity, pMapData, NULL );
  304. if ( pEntity == NULL )
  305. {
  306. Msg("Failed to initialize templated entity with mapdata: %s\n", pMapData );
  307. return false;
  308. }
  309. // Get a matrix that'll convert from world to the new local space
  310. VMatrix matNewTemplateToWorld, matStoredLocalToWorld;
  311. matNewTemplateToWorld.SetupMatrixOrgAngles( vecOrigin, vecAngles );
  312. MatrixMultiply( matNewTemplateToWorld, m_hTemplates[i].matEntityToTemplate, matStoredLocalToWorld );
  313. // Get the world origin & angles from the stored local coordinates
  314. Vector vecNewOrigin;
  315. QAngle vecNewAngles;
  316. vecNewOrigin = matStoredLocalToWorld.GetTranslation();
  317. MatrixToAngles( matStoredLocalToWorld, vecNewAngles );
  318. // Set its origin & angles
  319. pEntity->SetAbsOrigin( vecNewOrigin );
  320. pEntity->SetAbsAngles( vecNewAngles );
  321. if( AllowNameFixup() )
  322. {
  323. pEntity->MarkNeedsNamePurge();
  324. }
  325. if ( ScriptPreInstanceSpawn( &m_ScriptScope, pEntity, Templates_FindByIndex( iTemplateIndex ) ) )
  326. {
  327. pSpawnList[i].m_pEntity = pEntity;
  328. }
  329. else
  330. {
  331. pSpawnList[i].m_pEntity = NULL;
  332. UTIL_RemoveImmediate( pEntity );
  333. }
  334. pSpawnList[i].m_nDepth = 0;
  335. pSpawnList[i].m_pDeferredParent = NULL;
  336. }
  337. SpawnHierarchicalList( iTemplates, pSpawnList, true );
  338. // Set the time of creation for these entities.
  339. if ( bCreateTime )
  340. {
  341. #if defined(ENABLE_CREATE_TIME)
  342. float flCreateTime = gpGlobals->curtime;
  343. for ( i = 0; i < iTemplates; ++i )
  344. {
  345. if ( pSpawnList[i].m_pEntity )
  346. {
  347. pSpawnList[i].m_pEntity->SetCreateTime( flCreateTime );
  348. }
  349. }
  350. #endif
  351. }
  352. for ( i = 0; i < iTemplates; ++i )
  353. {
  354. if ( pSpawnList[i].m_pEntity )
  355. {
  356. pEntities->AddToTail( pSpawnList[i].m_pEntity );
  357. }
  358. }
  359. return true;
  360. }
  361. //-----------------------------------------------------------------------------
  362. //
  363. //-----------------------------------------------------------------------------
  364. void CPointTemplate::CreationComplete( const CUtlVector<CBaseEntity*> &entities )
  365. {
  366. if ( !entities.Count() )
  367. return;
  368. ScriptPostSpawn( &m_ScriptScope, (CBaseEntity **)entities.Base(), entities.Count() );
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose:
  372. // Input : &inputdata -
  373. //-----------------------------------------------------------------------------
  374. void CPointTemplate::InputForceSpawn( inputdata_t &inputdata )
  375. {
  376. // Spawn our template
  377. CUtlVector<CBaseEntity*> hNewEntities;
  378. if ( !CreateInstance( GetAbsOrigin(), GetAbsAngles(), &hNewEntities ) )
  379. return;
  380. CreationComplete( hNewEntities );
  381. // Fire our output
  382. m_pOutputOnSpawned.FireOutput( this, this );
  383. }
  384. //-----------------------------------------------------------------------------
  385. //-----------------------------------------------------------------------------
  386. void ScriptInstallPreSpawnHook()
  387. {
  388. if ( g_pScriptVM && !g_pScriptVM->ValueExists( "__ExecutePreSpawn" ) )
  389. {
  390. g_pScriptVM->Run( g_Script_spawn_helper );
  391. }
  392. }
  393. //-----------------------------------------------------------------------------
  394. // Purpose: This function is called after a spawner creates its child entity
  395. // but before the keyvalues are injected. This gives us an
  396. // opportunity to change any keyvalues before the entity is
  397. // configured and spawned. In this case, we see if there is a VScript
  398. // that wants to change anything about this entity.
  399. //-----------------------------------------------------------------------------
  400. bool ScriptPreInstanceSpawn( CScriptScope *pScriptScope, CBaseEntity *pChild, string_t iszKeyValueData )
  401. {
  402. if ( !pScriptScope->IsInitialized() )
  403. {
  404. return true;
  405. }
  406. if ( !pScriptScope->ValueExists( "PreSpawnInstance" ) )
  407. {
  408. return true;
  409. }
  410. ScriptVariant_t result;
  411. if ( pScriptScope->Call( "__ExecutePreSpawn", &result, ToHScript( pChild ) ) != SCRIPT_DONE )
  412. return true;
  413. if ( ( result.m_type == FIELD_BOOLEAN && !result.m_bool ) || ( result.m_type == FIELD_INTEGER && !result.m_int ) )
  414. return false;
  415. return true;
  416. }
  417. void ScriptPostSpawn( CScriptScope *pScriptScope, CBaseEntity **ppEntities, int nEntities )
  418. {
  419. if ( !pScriptScope->IsInitialized() )
  420. return;
  421. HSCRIPT hPostSpawnFunc = pScriptScope->LookupFunction( "PostSpawn" );
  422. if ( !hPostSpawnFunc )
  423. return;
  424. ScriptVariant_t varEntityMakerResultTable;
  425. if ( g_pScriptVM->GetValue( *pScriptScope, "__EntityMakerResult", &varEntityMakerResultTable ) )
  426. {
  427. if ( varEntityMakerResultTable.m_type == FIELD_HSCRIPT )
  428. {
  429. HSCRIPT hEntityMakerResultTable = varEntityMakerResultTable.m_hScript;
  430. char szEntName[256];
  431. for ( int i = 0; i < nEntities; i++ )
  432. {
  433. V_strncpy( szEntName, ppEntities[i]->GetEntityNameAsCStr(), ARRAYSIZE(szEntName) );
  434. char *pAmpersand = V_strrchr( szEntName, '&' );
  435. if ( pAmpersand )
  436. *pAmpersand = 0;
  437. g_pScriptVM->SetValue( hEntityMakerResultTable, szEntName, ToHScript( ppEntities[i] ) );
  438. }
  439. pScriptScope->Call( hPostSpawnFunc, NULL, hEntityMakerResultTable );
  440. pScriptScope->Call( "__FinishSpawn" );
  441. }
  442. g_pScriptVM->ReleaseValue( varEntityMakerResultTable );
  443. }
  444. g_pScriptVM->ReleaseFunction( hPostSpawnFunc );
  445. }