IExtension *CExtensionManager::FindExtensionByFile(const char *file) { List<CExtension *>::iterator iter; CExtension *pExt; /* Chomp off the path */ char lookup[PLATFORM_MAX_PATH]; g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file); for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { pExt = (*iter); char short_file[PLATFORM_MAX_PATH]; g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename()); if (strcmp(lookup, short_file) == 0) { return pExt; } } /* If we got no results, test if there was a platform extension. * If not, add one. */ if (!strstr(file, "." PLATFORM_LIB_EXT)) { char path[PLATFORM_MAX_PATH]; UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT); return FindExtensionByFile(path); } return NULL; }
IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface, const char *filepath, const char *filename, char *error, size_t maxlength) { IExtension *pAlready; if ((pAlready=FindExtensionByFile(filename)) != NULL) { return pAlready; } CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath); if (!pExt->Load(error, maxlength) || !pExt->IsLoaded()) { pExt->Unload(); delete pExt; return NULL; } m_Libs.push_back(pExt); return pExt; }
IExtension *CExtensionManager::LoadAutoExtension(const char *path) { if (!strstr(path, "." PLATFORM_LIB_EXT)) { char newpath[PLATFORM_MAX_PATH]; g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT); return LoadAutoExtension(newpath); } IExtension *pAlready; if ((pAlready=FindExtensionByFile(path)) != NULL) { return pAlready; } char error[256]; CExtension *p = new CLocalExtension(path); /* We put us in the list beforehand so extensions that check for each other * won't recursively load each other. */ m_Libs.push_back(p); if (!p->Load(error, sizeof(error)) || !p->IsLoaded()) { g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error); p->SetError(error); } return p; }
IExtension *CExtensionManager::LoadAutoExtension(const char *path) { /* Remove platform extension if it's there. Compat hack. */ const char *ext = libsys->GetFileExtension(path); if (strcmp(ext, PLATFORM_LIB_EXT) == 0) { char path2[PLATFORM_MAX_PATH]; smcore.Format(path2, sizeof(path2), "%s", path); path2[strlen(path) - strlen(PLATFORM_LIB_EXT) - 1] = '\0'; return LoadAutoExtension(path2); } IExtension *pAlready; if ((pAlready=FindExtensionByFile(path)) != NULL) { return pAlready; } char error[256]; CExtension *p = new CLocalExtension(path); /* We put us in the list beforehand so extensions that check for each other * won't recursively load each other. */ m_Libs.push_back(p); if (!p->Load(error, sizeof(error)) || !p->IsLoaded()) { smcore.LogError("[SM] Unable to load extension \"%s\": %s", path, error); p->SetError(error); } return p; }
IExtension *CExtensionManager::FindExtensionByName(const char *ext) { List<CExtension *>::iterator iter; CExtension *pExt; IExtensionInterface *pAPI; const char *name; for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { pExt = (*iter); if (!pExt->IsLoaded()) { continue; } if ((pAPI = pExt->GetAPI()) == NULL) { continue; } name = pAPI->GetExtensionName(); if (!name) { continue; } if (strcmp(name, ext) == 0) { return pExt; } } return NULL; }
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength) { /* Remove platform extension if it's there. Compat hack. */ const char *ext = libsys->GetFileExtension(file); if (strcmp(ext, PLATFORM_LIB_EXT) == 0) { char path2[PLATFORM_MAX_PATH]; smcore.Format(path2, sizeof(path2), "%s", file); path2[strlen(file) - strlen(PLATFORM_LIB_EXT) - 1] = '\0'; return LoadExtension(path2, error, maxlength); } IExtension *pAlready; if ((pAlready=FindExtensionByFile(file)) != NULL) { return pAlready; } CExtension *pExt = new CLocalExtension(file); if (!pExt->Load(error, maxlength) || !pExt->IsLoaded()) { pExt->Unload(); delete pExt; return NULL; } /* :TODO: do QueryRunning check if the map is loaded */ m_Libs.push_back(pExt); return pExt; }
ALERROR CExtension::CreateExtension (SDesignLoadCtx &Ctx, CXMLElement *pDesc, EFolderTypes iFolder, CExternalEntityTable *pEntities, CExtension **retpExtension) // CreateExtension // // Loads the given extension or adventure. We take ownership of pEntities. { ALERROR error; int i; // Create an extension object CExtension *pExtension; if (error = CreateExtensionFromRoot(Ctx.sResDb, pDesc, iFolder, pEntities, Ctx.dwInheritAPIVersion, &pExtension, &Ctx.sError)) return error; // Set up context Ctx.pExtension = pExtension; // Load all the design elements for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); if (error = pExtension->LoadDesignElement(Ctx, pItem)) { pExtension->m_pEntities = NULL; // Let our parent clean up. delete pExtension; return error; } } // If this is an adventure and we have no adventure descriptor then we // fail. if (pExtension->m_iType == extAdventure && pExtension->m_pAdventureDesc == NULL) { pExtension->m_pEntities = NULL; // Let our parent clean up. delete pExtension; Ctx.sError = CONSTLIT("Adventure must have an AdventureDesc type."); return ERR_FAIL; } pExtension->AddDefaultLibraryReferences(Ctx); // Restore Ctx.pExtension = NULL; // Done pExtension->m_iLoadState = (Ctx.bLoadAdventureDesc ? loadAdventureDesc : loadComplete); *retpExtension = pExtension; return NOERROR; }
DLLEXPORT void initializeExtension( CExtension &extension ) { extension.Requires( "ieCore" ); extension.RegisterTranslator( "ieProceduralHolder", "", ProceduralHolderTranslator::creator, ProceduralHolderTranslator::nodeInitialiser ); }
freettcn::CType::CType(const std::shared_ptr<const TciModuleId> &moduleId, const Tstring &name, const TciTypeClass &typeClass, const Tstring &encoding, const Tstring &encodingVariant, const CExtension &extension): _moduleId(moduleId), _name(new Tstring(name)), _class(typeClass), _encoding(new Tstring(encoding)), _encodingVariant(new Tstring(encodingVariant)), _extension(new CExtension) { std::for_each(extension.begin(), extension.end(), [this](Tstring *str) { _extension->push_back(new Tstring(*str)); }); }
void CExtensionManager::AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface) { CExtension *pExt = (CExtension *)ext; CExtension *pOwner = GetExtensionFromIdent(other); IfaceInfo info; info.iface = (SMInterface *)iface; info.owner = pOwner; pExt->AddDependency(&info); pOwner->AddChildDependent(pExt, (SMInterface *)iface); }
void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo) { CExtension *pExt = (CExtension *)pRequester; CExtension *pOwner = (CExtension *)pInfo->owner; pExt->AddDependency(pInfo); IExtensionInterface *pAPI = pExt->GetAPI(); if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface)) { pOwner->AddChildDependent(pExt, pInfo->iface); } }
DLLEXPORT void initializeExtension( CExtension &extension ) { const char * pluginVersion = "1.2"; MString info = "MTOA gpuCache Translator v"; info += pluginVersion; info += " using "; info += Alembic::AbcCoreAbstract::GetLibraryVersion().c_str(); MGlobal::displayInfo(info); extension.Requires( "gpuCache" ); extension.RegisterTranslator( "gpuCache", "", BB_gpuCacheTranslator::creator, BB_gpuCacheTranslator::nodeInitialiser ); }
void CDesignCollection::GetEnabledExtensions (TArray<CExtension *> *retExtensionList) // GetEnabledExtensions // // Returns the list of enabled extensions { int i; retExtensionList->DeleteAll(); for (i = 0; i < GetExtensionCount(); i++) { CExtension *pEntry = GetExtension(i); if (pEntry->GetType() == extExtension) retExtensionList->Insert(pEntry); } }
void CExtensionManager::MarkAllLoaded() { List<CExtension *>::iterator iter; CExtension *pExt; for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { pExt = (*iter); if (!pExt->IsLoaded()) { continue; } if (pExt->m_bFullyLoaded) { continue; } pExt->MarkAllLoaded(); } }
IExtension *CExtensionManager::FindExtensionByFile(const char *file) { List<CExtension *>::iterator iter; CExtension *pExt; /* Chomp off the path */ char lookup[PLATFORM_MAX_PATH]; libsys->GetFileFromPath(lookup, sizeof(lookup), file); for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { pExt = (*iter); if (pExt->IsSameFile(lookup)) { return pExt; } } return NULL; }
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength) { IExtension *pAlready; if ((pAlready=FindExtensionByFile(file)) != NULL) { return pAlready; } CExtension *pExt = new CLocalExtension(file); if (!pExt->Load(error, maxlength) || !pExt->IsLoaded()) { pExt->Unload(); delete pExt; return NULL; } /* :TODO: do QueryRunning check if the map is loaded */ m_Libs.push_back(pExt); return pExt; }
void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface) { CExtension *pExt = (CExtension *)pOwner; pExt->AddInterface(pInterface); }
ALERROR CExtension::CreateExtensionFromRoot (const CString &sFilespec, CXMLElement *pDesc, EFolderTypes iFolder, CExternalEntityTable *pEntities, DWORD dwInheritAPIVersion, CExtension **retpExtension, CString *retsError) // CreateExtension // // Loads the given extension or adventure. We take ownership of pEntities. { int i; // Create an extension object CExtension *pExtension = new CExtension; pExtension->m_sFilespec = sFilespec; pExtension->m_dwUNID = pDesc->GetAttributeInteger(UNID_ATTRIB); if (pExtension->m_dwUNID == 0) { delete pExtension; *retsError = CONSTLIT("Invalid UNID."); return ERR_FAIL; } if (strEquals(pDesc->GetTag(), TRANSCENDENCE_ADVENTURE_TAG)) { pExtension->m_iGame = gameTranscendence; pExtension->m_iType = extAdventure; } else if (strEquals(pDesc->GetTag(), TRANSCENDENCE_LIBRARY_TAG)) { pExtension->m_iGame = gameTranscendence; pExtension->m_iType = extLibrary; } else if (strEquals(pDesc->GetTag(), TRANSCENDENCE_EXTENSION_TAG)) { pExtension->m_iGame = gameTranscendence; pExtension->m_iType = extExtension; } else if (strEquals(pDesc->GetTag(), CORE_LIBRARY_TAG)) { // For core libraries, we don't care what game it is. It's always // whatever game the base file is. pExtension->m_iGame = gameUnknown; pExtension->m_iType = extLibrary; } else { delete pExtension; *retsError = strPatternSubst(CONSTLIT("Unknown root element: %s"), pDesc->GetTag()); return ERR_FAIL; } pExtension->m_iLoadState = loadEntities; pExtension->m_iFolderType = iFolder; pExtension->m_pEntities = pEntities; pExtension->m_ModifiedTime = fileGetModifiedTime(sFilespec); pExtension->m_bDebugOnly = pDesc->GetAttributeBool(DEBUG_ONLY_ATTRIB); pExtension->m_bRegistered = IsRegisteredUNID(pExtension->m_dwUNID); pExtension->m_bPrivate = pDesc->GetAttributeBool(PRIVATE_ATTRIB); pExtension->m_bAutoInclude = pDesc->GetAttributeBool(AUTO_INCLUDE_ATTRIB); pExtension->m_bUsesXML = pDesc->GetAttributeBool(USES_XML_ATTRIB); // API version CString sAPIVersion; if (pDesc->FindAttribute(API_VERSION_ATTRIB, &sAPIVersion)) { pExtension->m_dwAPIVersion = (DWORD)strToInt(sAPIVersion, 0); if (pExtension->m_dwAPIVersion < 12) pExtension->m_dwAPIVersion = 0; pExtension->m_sVersion = pDesc->GetAttribute(VERSION_ATTRIB); } else if (dwInheritAPIVersion) { pExtension->m_dwAPIVersion = dwInheritAPIVersion; pExtension->m_sVersion = pDesc->GetAttribute(VERSION_ATTRIB); } else { sAPIVersion = pDesc->GetAttribute(VERSION_ATTRIB); pExtension->m_dwAPIVersion = ::LoadExtensionVersion(sAPIVersion); } if (pExtension->m_dwAPIVersion == 0) { pExtension->m_pEntities = NULL; // Let our parent clean up. delete pExtension; *retsError = strPatternSubst(CONSTLIT("Unable to load extension: incompatible version: %s"), sAPIVersion); return ERR_FAIL; } // If this is a later version, then disabled it if (pExtension->m_dwAPIVersion > API_VERSION) pExtension->SetDisabled(CONSTLIT("Requires a newer version of Transcendence.exe")); // Release pExtension->m_dwRelease = pDesc->GetAttributeInteger(RELEASE_ATTRIB); // Registered extensions default to release 1. if (pExtension->m_dwRelease == 0 && iFolder == folderCollection) pExtension->m_dwRelease = 1; // Name pExtension->m_sName = pDesc->GetAttribute(NAME_ATTRIB); if (pExtension->m_sName.IsBlank()) pExtension->m_sName = strPatternSubst(CONSTLIT("Extension %x"), pExtension->m_dwUNID); // Image pExtension->m_dwCoverUNID = (DWORD)pDesc->GetAttributeInteger(COVER_IMAGE_UNID_ATTRIB); // Load credits (we parse them into a string array) CString sCredits = pDesc->GetAttribute(CREDITS_ATTRIB); if (!sCredits.IsBlank()) strDelimitEx(sCredits, ';', DELIMIT_TRIM_WHITESPACE, 0, &pExtension->m_Credits); // Load extends attrib CString sExtends = pDesc->GetAttribute(EXTENDS_ATTRIB); if (!sExtends.IsBlank()) { TArray<CString> Extends; strDelimitEx(sExtends, ';', DELIMIT_TRIM_WHITESPACE, 0, &Extends); for (i = 0; i < Extends.GetCount(); i++) { DWORD dwUNID = strToInt(Extends[i], INVALID_UNID); if (dwUNID != INVALID_UNID) pExtension->m_Extends.Insert(dwUNID); } } // Other options pExtension->m_dwAutoIncludeAPIVersion = (DWORD)pDesc->GetAttributeIntegerBounded(AUTO_INCLUDE_FOR_COMPATIBILITY_ATTRIB, 0, -1, 0); // Done *retpExtension = pExtension; return NOERROR; }
ALERROR CDesignCollection::BindDesign (const TArray<CExtension *> &BindOrder, bool bNewGame, bool bNoResources, CString *retsError) // BindDesign // // Binds the design collection to the set of design types in the given list of // extensions. { DEBUG_TRY ALERROR error; int i; // Unbind everything DEBUG_TRY CShipClass::UnbindGlobal(); for (i = 0; i < m_AllTypes.GetCount(); i++) m_AllTypes.GetEntry(i)->UnbindDesign(); m_AllTypes.DeleteAll(); DEBUG_CATCH_MSG("Crash unbinding types."); // Reset the bind tables for (i = 0; i < designCount; i++) m_ByType[i].DeleteAll(); m_CreatedTypes.DeleteAll(true); m_OverrideTypes.DeleteAll(); // Reset m_pTopology = NULL; m_pAdventureExtension = NULL; // Create a design load context SDesignLoadCtx Ctx; Ctx.bBindAsNewGame = bNewGame; Ctx.bNoResources = bNoResources; // Loop over the bind list in order and add appropriate types to m_AllTypes // (The order guarantees that the proper types override) for (i = 0; i < BindOrder.GetCount(); i++) { CExtension *pExtension = BindOrder[i]; try { const CDesignTable &Types = pExtension->GetDesignTypes(); #ifdef DEBUG_BIND ::OutputDebugString(strPatternSubst(CONSTLIT("EXTENSION %s\n"), pExtension->GetName())); for (int j = 0; j < Types.GetCount(); j++) { ::OutputDebugString(strPatternSubst(CONSTLIT("%08x: %s\n"), Types.GetEntry(j)->GetUNID(), Types.GetEntry(j)->GetTypeName())); } #endif // Run globals for the extension if (error = pExtension->ExecuteGlobals(Ctx)) { *retsError = Ctx.sError; return error; } // Add the types m_AllTypes.Merge(Types, &m_OverrideTypes); // If this is the adventure, then remember it if (pExtension->GetType() == extAdventure) { m_pAdventureExtension = pExtension; m_pAdventureDesc = pExtension->GetAdventureDesc(); } // If this is an adventure or the base extension then take the // topology. if (pExtension->GetType() == extAdventure || pExtension->GetType() == extBase) m_pTopology = &pExtension->GetTopology(); } catch (...) { ::kernelDebugLogMessage("Crash processing extension:"); CExtension::DebugDump(pExtension, true); throw; } } // If this is a new game, then create all the Template types if (bNewGame) { DEBUG_TRY m_DynamicUNIDs.DeleteAll(); m_DynamicTypes.DeleteAll(); if (error = FireOnGlobalTypesInit(Ctx)) { *retsError = Ctx.sError; return error; } if (error = CreateTemplateTypes(Ctx)) { *retsError = Ctx.sError; return error; } DEBUG_CATCH_MSG("Crash defining dynamic types."); } // Add all the dynamic types. These came either from the saved game file or // from the Template types above. m_AllTypes.Merge(m_DynamicTypes, &m_OverrideTypes); // Now resolve all overrides and inheritance if (error = ResolveOverrides(Ctx)) { *retsError = Ctx.sError; return error; } // Initialize the byType lists DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); m_ByType[pEntry->GetType()].AddEntry(pEntry); } DEBUG_CATCH_MSG("Crash initializing byType lists."); // Set our adventure desc as current; since adventure descs are always // loaded this is the only thing that we can use to tell if we should // call global events. // // This must happen after Unbind (because that clears it) and before // PrepareBindDesign. // // NOTE: m_pAdventureDesc can be NULL (e.g., in the intro screen). DEBUG_TRY if (m_pAdventureDesc) m_pAdventureDesc->SetCurrentAdventure(); DEBUG_CATCH_MSG("Crash setting current adventure."); // Cache a map between currency name and economy type // We need to do this before Bind because some types will lookup // a currency name during Bind. DEBUG_TRY m_EconomyIndex.DeleteAll(); for (i = 0; i < GetCount(designEconomyType); i++) { CEconomyType *pEcon = CEconomyType::AsType(GetEntry(designEconomyType, i)); const CString &sName = pEcon->GetSID(); bool bUnique; CEconomyType **ppDest = m_EconomyIndex.SetAt(sName, &bUnique); if (!bUnique) { pEcon->ComposeLoadError(Ctx, CONSTLIT("Currency ID must be unique")); *retsError = Ctx.sError; return ERR_FAIL; } *ppDest = pEcon; } DEBUG_CATCH_MSG("Crash initializing economies."); // Prepare to bind. This is used by design elements that need two passes // to bind. We also use it to set up the inheritence hierarchy, which means // that we rely on the map from UNID to valid design type (m_AllTypes) m_DisplayAttribs.DeleteAll(); DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->PrepareBindDesign(Ctx)) { *retsError = Ctx.sError; return error; } // We take this opportunity to build a list of display attributes // defined by each type. const CDisplayAttributeDefinitions &Attribs = pEntry->GetDisplayAttributes(); if (!Attribs.IsEmpty()) m_DisplayAttribs.Append(Attribs); } DEBUG_CATCH_MSG("Crash in PrepareBind."); // Now call Bind on all active design entries for (i = 0; i < evtCount; i++) m_EventsCache[i]->DeleteAll(); DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->BindDesign(Ctx)) { *retsError = Ctx.sError; return error; } // Cache some global events. We keep track of the global events for // all types so that we can access them faster. CacheGlobalEvents(pEntry); } DEBUG_CATCH_MSG("Crash in BindDesign."); // Finish binding. This pass is used by design elements // that need to do stuff after all designs are bound. DEBUG_TRY for (i = 0; i < m_AllTypes.GetCount(); i++) { CDesignType *pEntry = m_AllTypes.GetEntry(i); if (error = pEntry->FinishBindDesign(Ctx)) { *retsError = Ctx.sError; return error; } } DEBUG_CATCH_MSG("Crash in FinishBind."); // Remember what we bound m_BoundExtensions = BindOrder; return NOERROR; DEBUG_CATCH }
void CExtensionManager::AddLibrary(IExtension *pSource, const char *library) { CExtension *pExt = (CExtension *)pSource; pExt->AddLibrary(library); g_PluginSys.OnLibraryAction(library, false, false); }
void CExtensionManager::AddLibrary(IExtension *pSource, const char *library) { CExtension *pExt = (CExtension *)pSource; pExt->AddLibrary(library); scripts->OnLibraryAction(library, LibraryAction_Added); }
void CExtensionManager::BindChildPlugin(IExtension *pParent, SMPlugin *pPlugin) { CExtension *pExt = (CExtension *)pParent; pExt->AddPlugin(static_cast<CPlugin *>(pPlugin)); }
void HandleSystem::Dump(HANDLE_REPORTER rep) { unsigned int total_size = 0; rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory"); rep("--------------------------------------------------------------------------"); for (unsigned int i = 1; i <= m_HandleTail; i++) { if (m_Handles[i].set != HandleSet_Used) { continue; } /* Get the index */ unsigned int index = (m_Handles[i].serial << 16) | i; /* Determine the owner */ const char *owner = "UNKNOWN"; if (m_Handles[i].owner) { IdentityToken_t *pOwner = m_Handles[i].owner; if (pOwner == g_pCoreIdent) { owner = "CORE"; } else if (pOwner == g_PluginSys.GetIdentity()) { owner = "PLUGINSYS"; } else { CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner); if (ext) { owner = ext->GetFilename(); } else { CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner); if (pPlugin) { owner = pPlugin->GetFilename(); } } } } else { owner = "NONE"; } const char *type = "ANON"; QHandleType *pType = &m_Types[m_Handles[i].type]; unsigned int size = 0; if (pType->nameIdx != -1) { type = m_strtab->GetString(pType->nameIdx); } if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION || !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size)) { rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1"); } else { char buffer[32]; UTIL_Format(buffer, sizeof(buffer), "%d", size); rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer); total_size += size; } } rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size); }
void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin ) { CExtension *pExt = (CExtension *)pParent; pExt->AddPlugin(pPlugin); }
bool CExtensionManager::UnloadExtension(IExtension *_pExt) { if (!_pExt) { return false; } CExtension *pExt = (CExtension *)_pExt; if (m_Libs.find(pExt) == m_Libs.end()) { return false; } /* Tell it to unload */ if (pExt->IsLoaded()) { IExtensionInterface *pAPI = pExt->GetAPI(); pAPI->OnExtensionUnload(); } /* First remove us from internal lists */ g_ShareSys.RemoveInterfaces(_pExt); m_Libs.remove(pExt); List<CExtension *> UnloadQueue; /* Handle dependencies */ if (pExt->IsLoaded()) { /* Unload any dependent plugins */ List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin(); while (p_iter != pExt->m_Dependents.end()) { /* We have to manually unlink ourselves here, since we're no longer being managed */ scripts->UnloadPlugin((*p_iter)); p_iter = pExt->m_Dependents.erase(p_iter); } List<String>::iterator s_iter; for (s_iter = pExt->m_Libraries.begin(); s_iter != pExt->m_Libraries.end(); s_iter++) { scripts->OnLibraryAction((*s_iter).c_str(), LibraryAction_Removed); } /* Notify and/or unload all dependencies */ List<CExtension *>::iterator c_iter; CExtension *pDep; IExtensionInterface *pAPI; for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++) { pDep = (*c_iter); if ((pAPI=pDep->GetAPI()) == NULL) { continue; } if (pDep == pExt) { continue; } /* Now, get its dependency list */ bool dropped = false; List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin(); while (i_iter != pDep->m_Deps.end()) { if ((*i_iter).owner == _pExt) { if (!pAPI->QueryInterfaceDrop((*i_iter).iface)) { if (!dropped) { dropped = true; UnloadQueue.push_back(pDep); } } pAPI->NotifyInterfaceDrop((*i_iter).iface); i_iter = pDep->m_Deps.erase(i_iter); } else { i_iter++; } } /* Flush out any back references to this plugin */ i_iter = pDep->m_ChildDeps.begin(); while (i_iter != pDep->m_ChildDeps.end()) { if ((*i_iter).owner == pExt) { i_iter = pDep->m_ChildDeps.erase(i_iter); } else { i_iter++; } } } /* Unbind our natives from Core */ pExt->DropEverything(); } IdentityToken_t *pIdentity; if ((pIdentity = pExt->GetIdentity()) != NULL) { SMGlobalClass *glob = SMGlobalClass::head; while (glob) { glob->OnSourceModIdentityDropped(pIdentity); glob = glob->m_pGlobalClassNext; } } pExt->Unload(); delete pExt; List<CExtension *>::iterator iter; for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++) { /* NOTE: This is safe because the unload function backs out of anything not present */ UnloadExtension((*iter)); } return true; }
void CListSaveFilesTask::CreateFileEntry (CGameFile &GameFile, const CTimeDate &ModifiedTime, int yStart, IAnimatron **retpEntry, int *retcyHeight) // CreateFileEntry // // Creates a display entry for the save file { const CVisualPalette &VI = m_HI.GetVisuals(); const CG16bitFont &MediumFont = VI.GetFont(fontMedium); const CG16bitFont &SubTitleFont = VI.GetFont(fontSubTitle); int x = 0; int y = 0; int xText = x + ADVENTURE_ICON_WIDTH + ICON_SPACING_HORZ; int cxText = m_cxWidth - (ADVENTURE_ICON_WIDTH + 2 * ICON_SPACING_HORZ + SHIP_IMAGE_WIDTH); // Start with a sequencer CAniSequencer *pRoot = new CAniSequencer; pRoot->SetPropertyVector(PROP_POSITION, CVector(0, yStart)); // Add the character name and current star system CString sHeading = strPatternSubst(CONSTLIT("%s — %s"), GameFile.GetPlayerName(), GameFile.GetSystemName()); IAnimatron *pName = new CAniText; pName->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pName->SetPropertyVector(PROP_SCALE, CVector(10000, 1000)); pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput)); pName->SetPropertyFont(PROP_FONT, &SubTitleFont); pName->SetPropertyString(PROP_TEXT, sHeading); pRoot->AddTrack(pName, 0); y += SubTitleFont.GetHeight(); // Now add some additional information CShipClass *pClass = g_pUniverse->FindShipClass(GameFile.GetPlayerShip()); CString sShipClass = (pClass ? pClass->GetName() : NULL_STR); CString sGenome = strCapitalize(GetGenomeName(GameFile.GetPlayerGenome())); CString sState; if (GameFile.IsGameResurrect()) sState = strPatternSubst(CONSTLIT("Resurrect in the %s System"), GameFile.GetSystemName()); else sState = strPatternSubst(CONSTLIT("Continue in the %s System"), GameFile.GetSystemName()); CString sDesc; if (!sGenome.IsBlank() && !sShipClass.IsBlank()) sDesc = strPatternSubst(CONSTLIT("%s — %s — %s"), sGenome, sShipClass, sState); else sDesc = sState; IAnimatron *pDesc = new CAniText; pDesc->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000)); pDesc->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogInput)); pDesc->SetPropertyFont(PROP_FONT, &MediumFont); pDesc->SetPropertyString(PROP_TEXT, sDesc); RECT rcLine; pDesc->GetSpacingRect(&rcLine); pRoot->AddTrack(pDesc, 0); y += RectHeight(rcLine); // Adventure info CExtension *pAdventure = NULL; bool bHasAdventureIcon = false; if (g_pUniverse->FindExtension(GameFile.GetAdventure(), 0, &pAdventure)) { // Adventure icon CG16bitImage *pIcon; pAdventure->CreateIcon(ADVENTURE_ICON_WIDTH, ADVENTURE_ICON_HEIGHT, &pIcon); if (pIcon) { int xOffset = (ADVENTURE_ICON_WIDTH - pIcon->GetWidth()) / 2; IAnimatron *pIconAni = new CAniRect; pIconAni->SetPropertyVector(PROP_POSITION, CVector(x + xOffset, 0)); pIconAni->SetPropertyVector(PROP_SCALE, CVector(pIcon->GetWidth(), pIcon->GetHeight())); pIconAni->SetFillMethod(new CAniImageFill(pIcon, true)); pRoot->AddTrack(pIconAni, 0); bHasAdventureIcon = true; } // Adventure name pName = new CAniText; pName->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pName->SetPropertyVector(PROP_SCALE, CVector(10000, 1000)); pName->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel)); pName->SetPropertyFont(PROP_FONT, &MediumFont); pName->SetPropertyString(PROP_TEXT, pAdventure->GetName()); pRoot->AddTrack(pName, 0); y += MediumFont.GetHeight(); } // Create an image of the ship class if (pClass) { const CObjectImageArray &ObjImage = pClass->GetImage(); if (ObjImage.IsLoaded()) { RECT rcRect = ObjImage.GetImageRect(); CG16bitImage &Image = ObjImage.GetImage(NULL_STR); int cxImage = RectWidth(rcRect); int cyImage = RectHeight(rcRect); int cxNewWidth = Min(SHIP_IMAGE_WIDTH, cxImage); int cyNewHeight = cxNewWidth; CG16bitImage *pNewImage = new CG16bitImage; pNewImage->CreateFromImageTransformed(Image, rcRect.left, rcRect.top, cxImage, cyImage, (Metric)cxNewWidth / cxImage, (Metric)cyNewHeight / cyImage, 0.0); // Position int xImage = x + m_cxWidth - SHIP_IMAGE_WIDTH + (SHIP_IMAGE_WIDTH - cxNewWidth) / 2; int yImage = (SHIP_IMAGE_HEIGHT - cyNewHeight) / 2; // New image frame IAnimatron *pImageFrame = new CAniRect; pImageFrame->SetPropertyVector(PROP_POSITION, CVector(xImage, yImage)); pImageFrame->SetPropertyVector(PROP_SCALE, CVector(cxNewWidth, cyNewHeight)); pImageFrame->SetFillMethod(new CAniImageFill(pNewImage, true)); pRoot->AddTrack(pImageFrame, 0); } } // Extra information CString sEpitaph = GameFile.GetEpitaph(); int iScore = GameFile.GetScore(); CTimeDate LocalTime = ModifiedTime.ToLocalTime(); CString sModifiedTime = LocalTime.Format("%d %B %Y %I:%M %p"); CString sFilename = pathGetFilename(GameFile.GetFilespec()); CString sGameType; if (GameFile.IsRegistered()) sGameType = CONSTLIT("Registered"); else if (GameFile.IsDebug()) sGameType = CONSTLIT("Debug"); else sGameType = CONSTLIT("Unregistered"); CString sExtra; if (!sEpitaph.IsBlank()) sExtra = strPatternSubst(CONSTLIT("Score %d — %s\n%s — %s — %s"), iScore, sEpitaph, sGameType, sModifiedTime, sFilename); else if (iScore > 0) sExtra = strPatternSubst(CONSTLIT("Score %d\n%s — %s — %s"), iScore, sGameType, sModifiedTime, sFilename); else sExtra = strPatternSubst(CONSTLIT("%s — %s — %s"), sGameType, sModifiedTime, sFilename); pDesc = new CAniText; pDesc->SetPropertyVector(PROP_POSITION, CVector(xText, y)); pDesc->SetPropertyVector(PROP_SCALE, CVector(cxText, 1000)); pDesc->SetPropertyColor(PROP_COLOR, VI.GetColor(colorTextDialogLabel)); pDesc->SetPropertyFont(PROP_FONT, &MediumFont); pDesc->SetPropertyString(PROP_TEXT, sExtra); pDesc->GetSpacingRect(&rcLine); pRoot->AddTrack(pDesc, 0); y += RectHeight(rcLine); // Done *retpEntry = pRoot; if (retcyHeight) *retcyHeight = (bHasAdventureIcon ? Max(ADVENTURE_ICON_HEIGHT, y) : y); }
void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command) { int argcount = smcore.Argc(command); if (argcount >= 3) { const char *cmd = smcore.Arg(command, 2); if (strcmp(cmd, "list") == 0) { List<CExtension *>::iterator iter; CExtension *pExt; unsigned int num = 1; switch (m_Libs.size()) { case 1: { rootmenu->ConsolePrint("[SM] Displaying 1 extension:"); break; } case 0: { rootmenu->ConsolePrint("[SM] No extensions are loaded."); break; } default: { rootmenu->ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size()); break; } } for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++) { pExt = (*iter); if (pExt->IsLoaded()) { char error[255]; if (!pExt->IsRunning(error, sizeof(error))) { rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error); } else { IExtensionInterface *pAPI = pExt->GetAPI(); const char *name = pAPI->GetExtensionName(); const char *version = pAPI->GetExtensionVerString(); const char *descr = pAPI->GetExtensionDescription(); rootmenu->ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr); } } else { rootmenu->ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str()); } } return; } else if (strcmp(cmd, "load") == 0) { if (argcount < 4) { rootmenu->ConsolePrint("[SM] Usage: sm exts load <file>"); return; } const char *filename = smcore.Arg(command, 3); char path[PLATFORM_MAX_PATH]; char error[256]; smcore.Format(path, sizeof(path), "%s%s%s", filename, !strstr(filename, ".ext") ? ".ext" : "", !strstr(filename, "." PLATFORM_LIB_EXT) ? "." PLATFORM_LIB_EXT : ""); if (FindExtensionByFile(path) != NULL) { rootmenu->ConsolePrint("[SM] Extension %s is already loaded.", path); return; } if (LoadExtension(path, error, sizeof(error))) { rootmenu->ConsolePrint("[SM] Loaded extension %s successfully.", path); } else { rootmenu->ConsolePrint("[SM] Extension %s failed to load: %s", path, error); } return; } else if (strcmp(cmd, "info") == 0) { if (argcount < 4) { rootmenu->ConsolePrint("[SM] Usage: sm exts info <#>"); return; } const char *sId = smcore.Arg(command, 3); unsigned int id = atoi(sId); if (id <= 0) { rootmenu->ConsolePrint("[SM] Usage: sm exts info <#>"); return; } if (m_Libs.size() == 0) { rootmenu->ConsolePrint("[SM] No extensions are loaded."); return; } if (id > m_Libs.size()) { rootmenu->ConsolePrint("[SM] No extension was found with id %d.", id); return; } List<CExtension *>::iterator iter = m_Libs.begin(); CExtension *pExt = NULL; while (iter != m_Libs.end()) { if (--id == 0) { pExt = (*iter); break; } iter++; } /* This should never happen */ if (!pExt) { rootmenu->ConsolePrint("[SM] No extension was found with id %d.", id); return; } if (!pExt->IsLoaded()) { rootmenu->ConsolePrint(" File: %s", pExt->GetFilename()); rootmenu->ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str()); } else { char error[255]; if (!pExt->IsRunning(error, sizeof(error))) { rootmenu->ConsolePrint(" File: %s", pExt->GetFilename()); rootmenu->ConsolePrint(" Loaded: Yes"); rootmenu->ConsolePrint(" Running: No (%s)", error); } else { IExtensionInterface *pAPI = pExt->GetAPI(); rootmenu->ConsolePrint(" File: %s", pExt->GetFilename()); rootmenu->ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString()); rootmenu->ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription()); rootmenu->ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL()); rootmenu->ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString()); if (pExt->IsExternal()) { rootmenu->ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod"); } else if (pAPI->IsMetamodExtension()) { rootmenu->ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source"); } else { rootmenu->ConsolePrint(" Method: Loaded by SourceMod"); } } } return; } else if (strcmp(cmd, "unload") == 0) { if (argcount < 4) { rootmenu->ConsolePrint("[SM] Usage: sm exts unload <#> [code]"); return; } const char *arg = smcore.Arg(command, 3); unsigned int num = atoi(arg); CExtension *pExt = FindByOrder(num); if (!pExt) { rootmenu->ConsolePrint("[SM] Extension number %d was not found.", num); return; } if (argcount > 4 && pExt->unload_code) { const char *unload = smcore.Arg(command, 4); if (pExt->unload_code == (unsigned)atoi(unload)) { char filename[PLATFORM_MAX_PATH]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); UnloadExtension(pExt); rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename); } else { rootmenu->ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code); } return; } if (!pExt->IsLoaded() || (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size())) { char filename[PLATFORM_MAX_PATH]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); UnloadExtension(pExt); rootmenu->ConsolePrint("[SM] Extension %s is now unloaded.", filename); return; } else { List<CPlugin *> plugins; if (pExt->m_ChildDeps.size()) { rootmenu->ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename()); List<CExtension *>::iterator iter; CExtension *pOther; /* Get list of all extensions */ for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++) { List<IfaceInfo>::iterator i_iter; pOther = (*iter); if (!pOther->IsLoaded() || pOther == pExt) { continue; } /* Get their dependencies */ for (i_iter=pOther->m_Deps.begin(); i_iter!=pOther->m_Deps.end(); i_iter++) { /* Is this dependency to us? */ if ((*i_iter).owner != pExt) { continue; } /* Will our dependent care? */ if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface)) { rootmenu->ConsolePrint(" -> %s", pExt->GetFilename()); /* Add to plugin unload list */ List<CPlugin *>::iterator p_iter; for (p_iter=pOther->m_Dependents.begin(); p_iter!=pOther->m_Dependents.end(); p_iter++) { if (plugins.find((*p_iter)) == plugins.end()) { plugins.push_back((*p_iter)); } } } } } } if (pExt->m_Dependents.size()) { rootmenu->ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename()); List<CPlugin *>::iterator iter; CPlugin *pPlugin; for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++) { pPlugin = (*iter); if (plugins.find(pPlugin) == plugins.end()) { plugins.push_back(pPlugin); } } for (iter = plugins.begin(); iter != plugins.end(); iter++) { pPlugin = (*iter); rootmenu->ConsolePrint(" -> %s", pPlugin->GetFilename()); } } srand(static_cast<int>(time(NULL))); pExt->unload_code = (rand() % 877) + 123; //123 to 999 rootmenu->ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename()); rootmenu->ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code); return; } } else if (strcmp(cmd, "reload") == 0) { if (argcount < 4) { rootmenu->ConsolePrint("[SM] Usage: sm exts reload <#>"); return; } const char *arg = smcore.Arg(command, 3); unsigned int num = atoi(arg); CExtension *pExt = FindByOrder(num); if (!pExt) { rootmenu->ConsolePrint("[SM] Extension number %d was not found.", num); return; } if (pExt->IsLoaded()) { char filename[PLATFORM_MAX_PATH]; char error[255]; snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename()); if (pExt->Reload(error, sizeof(error))) { rootmenu->ConsolePrint("[SM] Extension %s is now reloaded.", filename); } else { rootmenu->ConsolePrint("[SM] Extension %s failed to reload: %s", filename, error); } return; } else { rootmenu->ConsolePrint("[SM] Extension %s is not loaded.", pExt->GetFilename()); return; } } } rootmenu->ConsolePrint("SourceMod Extensions Menu:"); rootmenu->DrawGenericOption("info", "Extra extension information"); rootmenu->DrawGenericOption("list", "List extensions"); rootmenu->DrawGenericOption("load", "Load an extension"); rootmenu->DrawGenericOption("reload", "Reload an extension"); rootmenu->DrawGenericOption("unload", "Unload an extension"); }
ALERROR CExtension::CreateBaseFile (SDesignLoadCtx &Ctx, EGameTypes iGame, CXMLElement *pDesc, CExternalEntityTable *pEntities, CExtension **retpBase, TArray<CXMLElement *> *retEmbedded) // CreateBaseFile // // Loads a new extension from the base file. { ALERROR error; int i; // Create an extension object CExtension *pExtension = new CExtension; pExtension->m_sFilespec = Ctx.sResDb; pExtension->m_dwUNID = 0; // Base is the only extension with 0 UNID. pExtension->m_iGame = iGame; pExtension->m_iType = extBase; pExtension->m_iLoadState = loadEntities; pExtension->m_iFolderType = folderBase; pExtension->m_pEntities = pEntities; pExtension->m_ModifiedTime = fileGetModifiedTime(Ctx.sResDb); pExtension->m_bRegistered = true; pExtension->m_bPrivate = true; pExtension->m_bAutoInclude = true; pExtension->m_bUsesXML = false; pExtension->m_bUsesCompatibilityLibrary = false; // Load the apiVersion CString sAPIVersion; if (pDesc->FindAttribute(API_VERSION_ATTRIB, &sAPIVersion)) { pExtension->m_dwAPIVersion = (DWORD)strToInt(sAPIVersion, 0); if (pExtension->m_dwAPIVersion < 12) pExtension->m_dwAPIVersion = 0; } // If this version is later than what we expect, then we fail. if (pExtension->m_dwAPIVersion > API_VERSION) { pExtension->m_pEntities = NULL; // Let our parent clean up delete pExtension; Ctx.sError = CONSTLIT("Newer version of the Transcendence engine is required."); return ERR_FAIL; } // We return the base extension *retpBase = pExtension; // Set up context Ctx.pExtension = pExtension; // Load the Main XML file for (i = 0; i < pDesc->GetContentElementCount(); i++) { CXMLElement *pItem = pDesc->GetContentElement(i); // <Images> if (strEquals(pItem->GetTag(), IMAGES_TAG)) error = pExtension->LoadImagesElement(Ctx, pItem); // <Sounds> else if (strEquals(pItem->GetTag(), SOUNDS_TAG)) error = pExtension->LoadSoundsElement(Ctx, pItem); // <SystemTypes> else if (strEquals(pItem->GetTag(), SYSTEM_TYPES_TAG)) error = pExtension->LoadSystemTypesElement(Ctx, pItem); // <TranscendenceAdventure> else if (strEquals(pItem->GetTag(), TRANSCENDENCE_ADVENTURE_TAG) || strEquals(pItem->GetTag(), TRANSCENDENCE_LIBRARY_TAG) || strEquals(pItem->GetTag(), CORE_LIBRARY_TAG)) { // Return this as an embedded extension retEmbedded->Insert(pItem); error = NOERROR; } // Other types else error = pExtension->LoadDesignElement(Ctx, pItem); // Check for error if (error) { pExtension->m_pEntities = NULL; // Let our parent clean up delete pExtension; return error; } } // Restore Ctx.pExtension = NULL; // Done pExtension->m_iLoadState = loadComplete; return NOERROR; }