aboutsummaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/plugins.cpp103
-rw-r--r--base/plugins.h35
2 files changed, 121 insertions, 17 deletions
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 62ff15bf81..83377600af 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -335,16 +335,15 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
_providers.push_back(pp);
}
-//
-// This should only be run once
+/**
+ * This should only be called once by main()
+ **/
void PluginManagerUncached::init() {
unloadAllPlugins();
_allEnginePlugins.clear();
- // We need to resize our pluginsInMem list to prevent fragmentation
- // Otherwise, as soon as we add our 1 engine plugin (which is all we'll have in memory at a time)
- // We'll get an allocation in memory that will never go away
- _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2); // more than we need
+ // Resize our pluginsInMem list to prevent fragmentation
+ _pluginsInMem[PLUGIN_TYPE_ENGINE].resize(2);
for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end();
@@ -371,6 +370,63 @@ void PluginManagerUncached::init() {
}
}
+/**
+ * Try to load the plugin by searching in the ConfigManager for a matching
+ * gameId under the domain 'plugin_files'.
+ **/
+bool PluginManagerUncached::loadPluginFromGameId(const Common::String &gameId) {
+ Common::ConfigManager::Domain *domain = ConfMan.getDomain("plugin_files");
+
+ if (domain) {
+ if (domain->contains(gameId)) {
+ Common::String filename = (*domain)[gameId];
+
+ if (loadPluginByFileName(filename)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Load a plugin with a filename taken from ConfigManager.
+ **/
+bool PluginManagerUncached::loadPluginByFileName(const Common::String &filename) {
+ if (filename.empty())
+ return false;
+
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
+
+ PluginList::iterator i;
+ for (i = _allEnginePlugins.begin(); i != _allEnginePlugins.end(); ++i) {
+ if (Common::String((*i)->getFileName()) == filename && (*i)->loadPlugin()) {
+ addToPluginsInMemList(*i);
+ _currentPlugin = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Update the config manager with a plugin file name that we found can handle
+ * the game.
+ **/
+void PluginManagerUncached::updateConfigWithFileName(const Common::String &gameId) {
+ // Check if we have a filename for the current plugin
+ if ((*_currentPlugin)->getFileName()) {
+ if (!ConfMan.hasMiscDomain("plugin_files"))
+ ConfMan.addMiscDomain("plugin_files");
+
+ Common::ConfigManager::Domain *domain = ConfMan.getDomain("plugin_files");
+ assert(domain);
+ (*domain)[gameId] = (*_currentPlugin)->getFileName();
+
+ ConfMan.flushToDisk();
+ }
+}
+
void PluginManagerUncached::loadFirstPlugin() {
unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
@@ -395,6 +451,10 @@ bool PluginManagerUncached::loadNextPlugin() {
return false; // no more in list
}
+/**
+ * Used by only the cached plugin manager. The uncached manager can only have
+ * one plugin in memory at a time.
+ **/
void PluginManager::loadAllPlugins() {
for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end();
@@ -426,6 +486,9 @@ void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin, b
}
}
+/*
+ * Used only by the cached plugin manager since it deletes the plugin.
+ */
bool PluginManager::tryLoadPlugin(Plugin *plugin) {
assert(plugin);
// Try to load the plugin
@@ -439,6 +502,9 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
}
}
+/**
+ * Add to the list of plugins loaded in memory.
+ */
void PluginManager::addToPluginsInMemList(Plugin *plugin) {
bool found = false;
// The plugin is valid, see if it provides the same module as an
@@ -468,16 +534,35 @@ void PluginManager::addToPluginsInMemList(Plugin *plugin) {
DECLARE_SINGLETON(EngineManager);
+/**
+ * This function works for both cached and uncached PluginManagers.
+ * For the cached version, most of the logic here will short circuit.
+ *
+ * For the uncached version, we first try to find the plugin using the gameId
+ * and only if we can't find it there, we loop through the plugins.
+ **/
GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
GameDescriptor result;
-
- PluginManager::instance().loadFirstPlugin();
+
+ // first look for the game using the gameId
+ if (PluginMan.loadPluginFromGameId(gameName)) {
+ result = findGameInLoadedPlugins(gameName, plugin);
+ if (!result.gameid().empty()) {
+ return result;
+ }
+ }
+
+ // We failed to find it using the gameid. Scan the list of plugins
+ PluginMan.loadFirstPlugin();
do {
result = findGameInLoadedPlugins(gameName, plugin);
if (!result.gameid().empty()) {
+ // Update with new plugin file name
+ PluginMan.updateConfigWithFileName(gameName);
break;
}
- } while (PluginManager::instance().loadNextPlugin());
+ } while (PluginMan.loadNextPlugin());
+
return result;
}
diff --git a/base/plugins.h b/base/plugins.h
index 928be85c32..4f6d37ac86 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -152,11 +152,11 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX];
// Abstract plugins
/**
- * Abstract base class for the plugin objects which handle plugins
- * instantiation. Subclasses for this may be used for engine plugins
- * and other types of plugins.
- *
- * FIXME: This class needs better documentation, esp. how it differs from class Plugin
+ * Abstract base class for the plugin objects which handle plugins
+ * instantiation. Subclasses for this may be used for engine plugins and other
+ * types of plugins. An existing PluginObject refers to an executable file
+ * loaded in memory and ready to run. The plugin, on the other hand, is just
+ * a handle to the file/object, whether it's loaded in memory or not.
*/
class PluginObject {
public:
@@ -169,9 +169,8 @@ public:
/**
* Abstract base class for the plugin system.
* Subclasses for this can be used to wrap both static and dynamic
- * plugins.
- *
- * FIXME: This class needs better documentation, esp. how it differs from class PluginObject
+ * plugins. This class refers to a plugin which may or may not be loaded in
+ * memory.
*/
class Plugin {
protected:
@@ -189,8 +188,19 @@ public:
virtual bool loadPlugin() = 0; // TODO: Rename to load() ?
virtual void unloadPlugin() = 0; // TODO: Rename to unload() ?
+ /**
+ * The following functions query information from the plugin object once
+ * it's loaded into memory.
+ **/
PluginType getType() const;
const char *getName() const;
+
+ /**
+ * The getFileName() function gets the name of the plugin file for those
+ * plugins that have files (ie. not static). It doesn't require the plugin
+ * object to be loaded into memory, unlike getName()
+ **/
+ virtual const char *getFileName() const { return 0; }
};
/** List of Plugin instances. */
@@ -294,6 +304,8 @@ protected:
#endif // DYNAMIC_MODULES
+#define PluginMan PluginManager::instance()
+
/**
* Singleton class which manages all plugins, including loading them,
* managing all Plugin class instances, and unloading them.
@@ -319,10 +331,14 @@ public:
void addPluginProvider(PluginProvider *pp);
+ // Functions used by the uncached PluginManager
virtual void init() {}
virtual void loadFirstPlugin() {}
virtual bool loadNextPlugin() { return false; }
+ virtual bool loadPluginFromGameId(const Common::String &gameId) { return false; }
+ virtual void updateConfigWithFileName(const Common::String &gameId) {}
+ // Functions used only by the cached PluginManager
virtual void loadAllPlugins();
void unloadAllPlugins();
@@ -342,11 +358,14 @@ protected:
PluginList::iterator _currentPlugin;
PluginManagerUncached() {}
+ bool loadPluginByFileName(const Common::String &filename);
public:
virtual void init();
virtual void loadFirstPlugin();
virtual bool loadNextPlugin();
+ virtual bool loadPluginFromGameId(const Common::String &gameId);
+ virtual void updateConfigWithFileName(const Common::String &gameId);
virtual void loadAllPlugins() {} // we don't allow this
};