//----------------------------------------------------------------------------- // Purpose: Only called on BSP load. Parses and spawns all the entities in the BSP. // Input : pMapData - Pointer to the entity data block to parse. //----------------------------------------------------------------------------- void MapEntity_ParseAllEntities(const char *pMapData, IMapEntityFilter *pFilter, bool bActivateEntities) { VPROF("MapEntity_ParseAllEntities"); HierarchicalSpawnMapData_t *pSpawnMapData = new HierarchicalSpawnMapData_t[NUM_ENT_ENTRIES]; HierarchicalSpawn_t *pSpawnList = new HierarchicalSpawn_t[NUM_ENT_ENTRIES]; CUtlVector< CPointTemplate* > pPointTemplates; int nEntities = 0; char szTokenBuffer[MAPKEY_MAXLENGTH]; // Allow the tools to spawn different things if ( serverenginetools ) { pMapData = serverenginetools->GetEntityData( pMapData ); } // Loop through all entities in the map data, creating each. for ( ; true; pMapData = MapEntity_SkipToNextEntity(pMapData, szTokenBuffer) ) { // // Parse the opening brace. // char token[MAPKEY_MAXLENGTH]; pMapData = MapEntity_ParseToken( pMapData, token ); // // Check to see if we've finished or not. // if (!pMapData) break; if (token[0] != '{') { Error( "MapEntity_ParseAllEntities: found %s when expecting {", token); continue; } // // Parse the entity and add it to the spawn list. // CBaseEntity *pEntity; const char *pCurMapData = pMapData; pMapData = MapEntity_ParseEntity(pEntity, pMapData, pFilter); if (pEntity == NULL) continue; if (pEntity->IsTemplate()) { // It's a template entity. Squirrel away its keyvalue text so that we can // recreate the entity later via a spawner. pMapData points at the '}' // so we must add one to include it in the string. Templates_Add(pEntity, pCurMapData, (pMapData - pCurMapData) + 2); // Remove the template entity so that it does not show up in FindEntityXXX searches. UTIL_Remove(pEntity); gEntList.CleanupDeleteList(); continue; } // To if ( dynamic_cast<CWorld*>( pEntity ) ) { VPROF( "MapEntity_ParseAllEntities_SpawnWorld"); pEntity->m_iParent = NULL_STRING; // don't allow a parent on the first entity (worldspawn) DispatchSpawn(pEntity); continue; } CNodeEnt *pNode = dynamic_cast<CNodeEnt*>(pEntity); if ( pNode ) { VPROF( "MapEntity_ParseAllEntities_SpawnTransients"); // We overflow the max edicts on large maps that have lots of entities. // Nodes & Lights remove themselves immediately on Spawn(), so dispatch their // spawn now, to free up the slot inside this loop. // NOTE: This solution prevents nodes & lights from being used inside point_templates. // // NOTE: Nodes spawn other entities (ai_hint) if they need to have a persistent presence. // To ensure keys are copied over into the new entity, we pass the mapdata into the // node spawn function. if ( pNode->Spawn( pCurMapData ) < 0 ) { gEntList.CleanupDeleteList(); } continue; } if ( dynamic_cast<CLight*>(pEntity) ) { VPROF( "MapEntity_ParseAllEntities_SpawnTransients"); // We overflow the max edicts on large maps that have lots of entities. // Nodes & Lights remove themselves immediately on Spawn(), so dispatch their // spawn now, to free up the slot inside this loop. // NOTE: This solution prevents nodes & lights from being used inside point_templates. if (DispatchSpawn(pEntity) < 0) { gEntList.CleanupDeleteList(); } continue; } // Build a list of all point_template's so we can spawn them before everything else CPointTemplate *pTemplate = dynamic_cast< CPointTemplate* >(pEntity); if ( pTemplate ) { pPointTemplates.AddToTail( pTemplate ); } else { // Queue up this entity for spawning pSpawnList[nEntities].m_pEntity = pEntity; pSpawnList[nEntities].m_nDepth = 0; pSpawnList[nEntities].m_pDeferredParentAttachment = NULL; pSpawnList[nEntities].m_pDeferredParent = NULL; pSpawnMapData[nEntities].m_pMapData = pCurMapData; pSpawnMapData[nEntities].m_iMapDataLength = (pMapData - pCurMapData) + 2; nEntities++; } } // Now loop through all our point_template entities and tell them to make templates of everything they're pointing to int iTemplates = pPointTemplates.Count(); for ( int i = 0; i < iTemplates; i++ ) { VPROF( "MapEntity_ParseAllEntities_SpawnTemplates"); CPointTemplate *pPointTemplate = pPointTemplates[i]; // First, tell the Point template to Spawn if ( DispatchSpawn(pPointTemplate) < 0 ) { UTIL_Remove(pPointTemplate); gEntList.CleanupDeleteList(); continue; } pPointTemplate->StartBuildingTemplates(); // Now go through all it's templates and turn the entities into templates int iNumTemplates = pPointTemplate->GetNumTemplateEntities(); for ( int iTemplateNum = 0; iTemplateNum < iNumTemplates; iTemplateNum++ ) { // Find it in the spawn list CBaseEntity *pEntity = pPointTemplate->GetTemplateEntity( iTemplateNum ); for ( int iEntNum = 0; iEntNum < nEntities; iEntNum++ ) { if ( pSpawnList[iEntNum].m_pEntity == pEntity ) { // Give the point_template the mapdata pPointTemplate->AddTemplate( pEntity, pSpawnMapData[iEntNum].m_pMapData, pSpawnMapData[iEntNum].m_iMapDataLength ); if ( pPointTemplate->ShouldRemoveTemplateEntities() ) { // Remove the template entity so that it does not show up in FindEntityXXX searches. UTIL_Remove(pEntity); gEntList.CleanupDeleteList(); // Remove the entity from the spawn list pSpawnList[iEntNum].m_pEntity = NULL; } break; } } } pPointTemplate->FinishBuildingTemplates(); } SpawnHierarchicalList( nEntities, pSpawnList, bActivateEntities ); delete [] pSpawnMapData; delete [] pSpawnList; }
//----------------------------------------------------------------------------- // Purpose: Spawn the entities I contain // Input : &vecOrigin - // &vecAngles - // pEntities - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPointTemplate::CreateInstance( const Vector &vecOrigin, const QAngle &vecAngles, CUtlVector<CBaseEntity*> *pEntities ) { // Go through all our templated map data and spawn all the entities in it int iTemplates = m_hTemplates.Count(); if ( !iTemplates ) { Msg("CreateInstance called on a point_template that has no templates: %s\n", STRING(GetEntityName()) ); return false; } // Tell the template system we're about to start a new template Templates_StartUniqueInstance(); HierarchicalSpawn_t *pSpawnList = (HierarchicalSpawn_t*)stackalloc( iTemplates * sizeof(HierarchicalSpawn_t) ); int i; for ( i = 0; i < iTemplates; i++ ) { CBaseEntity *pEntity = NULL; char *pMapData; int iTemplateIndex = m_hTemplates[i].iTemplateIndex; // Some templates have Entity I/O connecting the entities within the template. // Unique versions of these templates need to be created whenever they're instanced. if ( AllowNameFixup() && Templates_IndexRequiresEntityIOFixup( iTemplateIndex ) ) { // This template requires instancing. // Create a new mapdata block and ask the template system to fill it in with // a unique version (with fixed Entity I/O connections). pMapData = Templates_GetEntityIOFixedMapData( iTemplateIndex ); } else { // Use the unmodified mapdata pMapData = (char*)STRING( Templates_FindByIndex( iTemplateIndex ) ); } // Create the entity from the mapdata MapEntity_ParseEntity( pEntity, pMapData, NULL ); if ( pEntity == NULL ) { Msg("Failed to initialize templated entity with mapdata: %s\n", pMapData ); return false; } // Get a matrix that'll convert from world to the new local space VMatrix matNewTemplateToWorld, matStoredLocalToWorld; matNewTemplateToWorld.SetupMatrixOrgAngles( vecOrigin, vecAngles ); MatrixMultiply( matNewTemplateToWorld, m_hTemplates[i].matEntityToTemplate, matStoredLocalToWorld ); // Get the world origin & angles from the stored local coordinates Vector vecNewOrigin; QAngle vecNewAngles; vecNewOrigin = matStoredLocalToWorld.GetTranslation(); MatrixToAngles( matStoredLocalToWorld, vecNewAngles ); // Set its origin & angles pEntity->SetAbsOrigin( vecNewOrigin ); pEntity->SetAbsAngles( vecNewAngles ); pSpawnList[i].m_pEntity = pEntity; pSpawnList[i].m_nDepth = 0; } SpawnHierarchicalList( iTemplates, pSpawnList, true ); for ( i = 0; i < iTemplates; ++i ) { if ( pSpawnList[i].m_pEntity ) { pEntities->AddToTail( pSpawnList[i].m_pEntity ); } } return true; }