From 2c9968fe80c4ba78f895c9bac757dd6b1604ccce Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 12 May 2008 00:26:29 +0000 Subject: - Added an engine plugin manager and moved engine specific functionality into it - base/plugins.* reorganization svn-id: r32045 --- base/commandLine.cpp | 14 +++--- base/game.cpp | 26 ----------- base/game.h | 11 ----- base/main.cpp | 12 ++--- base/plugins.cpp | 95 +++++++++++++++++++++++++++------------ base/plugins.h | 124 ++++++++++++++++++++++++++++++--------------------- 6 files changed, 151 insertions(+), 131 deletions(-) (limited to 'base') diff --git a/base/commandLine.cpp b/base/commandLine.cpp index a4c867edee..5b919a495c 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -559,8 +559,8 @@ static void listGames() { printf("Game ID Full Title \n" "-------------------- ------------------------------------------------------\n"); - const PluginList &plugins = PluginManager::instance().getPlugins(); - PluginList::const_iterator iter = plugins.begin(); + const EnginePluginList &plugins = EngineMan.getPlugins(); + EnginePluginList::const_iterator iter = plugins.begin(); for (iter = plugins.begin(); iter != plugins.end(); ++iter) { GameList list = (*iter)->getSupportedGames(); for (GameList::iterator v = list.begin(); v != list.end(); ++v) { @@ -586,7 +586,7 @@ static void listTargets() { // to find the proper desc. In fact, the platform probably should // be taken into account, too. Common::String gameid(name); - GameDescriptor g = Base::findGame(gameid); + GameDescriptor g = EngineMan.findGame(gameid); if (g.description().size() > 0) description = g.description(); } @@ -613,8 +613,8 @@ static void listSaves(const char *target) { gameid.toLowercase(); // Normalize it to lower case // Find the plugin that will handle the specified gameid - const Plugin *plugin = 0; - GameDescriptor game = Base::findGame(gameid, &plugin); + const EnginePlugin *plugin = 0; + GameDescriptor game = EngineMan.findGame(gameid, &plugin); if (!plugin) { error("Could not find any plugin to handle gameid '%s' (target '%s')", gameid.c_str(), target); @@ -667,7 +667,7 @@ static void runDetectorTest() { continue; } - GameList candidates(PluginManager::instance().detectGames(files)); + GameList candidates(EngineMan.detectGames(files)); bool gameidDiffers = false; GameList::iterator x; for (x = candidates.begin(); x != candidates.end(); ++x) { @@ -740,7 +740,7 @@ bool processSettings(Common::String &command, Common::StringMap &settings) { // domain (i.e. a target) matching this argument, or alternatively // whether there is a gameid matching that name. if (!command.empty()) { - GameDescriptor gd = Base::findGame(command); + GameDescriptor gd = EngineMan.findGame(command); if (ConfMan.hasGameDomain(command) || !gd.gameid().empty()) { bool idCameFromCommandLine = false; diff --git a/base/game.cpp b/base/game.cpp index a79cfddec9..9628543672 100644 --- a/base/game.cpp +++ b/base/game.cpp @@ -75,29 +75,3 @@ void SaveStateDescriptor::setThumbnail(Graphics::Surface *t) { } _thumbnail = t; } - - -namespace Base { - -// TODO: Find a better name & place for this function. -GameDescriptor findGame(const Common::String &gameName, const Plugin **plugin) { - // Find the GameDescriptor for this target - const PluginList &plugins = PluginManager::instance().getPlugins(); - GameDescriptor result; - - if (plugin) - *plugin = 0; - - PluginList::const_iterator iter = plugins.begin(); - for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - result = (*iter)->findGame(gameName.c_str()); - if (!result.gameid().empty()) { - if (plugin) - *plugin = *iter; - break; - } - } - return result; -} - -} // End of namespace Base diff --git a/base/game.h b/base/game.h index 08d18247ef..18d7967388 100644 --- a/base/game.h +++ b/base/game.h @@ -179,15 +179,4 @@ public: /** List of savestates. */ typedef Common::Array SaveStateList; - -class Plugin; - -namespace Base { - -// TODO: Find a better name & place for this function. -GameDescriptor findGame(const Common::String &gameName, const Plugin **plugin = NULL); - -} // End of namespace Base - - #endif diff --git a/base/main.cpp b/base/main.cpp index 9129fcc7e1..80f77f89ab 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -77,8 +77,8 @@ static bool launcherDialog(OSystem &system) { return (dlg.runModal() != -1); } -static const Plugin *detectPlugin() { - const Plugin *plugin = 0; +static const EnginePlugin *detectPlugin() { + const EnginePlugin *plugin = 0; // Make sure the gameid is set in the config manager, and that it is lowercase. Common::String gameid(ConfMan.getActiveDomainName()); @@ -90,7 +90,7 @@ static const Plugin *detectPlugin() { // Query the plugins and find one that will handle the specified gameid printf("Looking for %s\n", gameid.c_str()); - GameDescriptor game = Base::findGame(gameid, &plugin); + GameDescriptor game = EngineMan.findGame(gameid, &plugin); if (plugin == 0) { printf("Failed game detection\n"); @@ -105,7 +105,7 @@ static const Plugin *detectPlugin() { } // TODO: specify the possible return values here -static int runGame(const Plugin *plugin, OSystem &system, const Common::String &edebuglevels) { +static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::String &edebuglevels) { Common::String gameDataPath(ConfMan.get("path")); if (gameDataPath.empty()) { } else if (gameDataPath.lastChar() != '/' @@ -168,7 +168,7 @@ static int runGame(const Plugin *plugin, OSystem &system, const Common::String & // Set the window caption to the game name Common::String caption(ConfMan.get("description")); - Common::String desc = Base::findGame(ConfMan.get("gameid")).description(); + Common::String desc = EngineMan.findGame(ConfMan.get("gameid")).description(); if (caption.empty() && !desc.empty()) caption = desc; if (caption.empty()) @@ -298,7 +298,7 @@ extern "C" int scummvm_main(int argc, char *argv[]) { // cleanly, so this is now enabled to encourage people to fix bits :) while (0 != ConfMan.getActiveDomain()) { // Try to find a plugin which feels responsible for the specified game. - const Plugin *plugin = detectPlugin(); + const EnginePlugin *plugin = detectPlugin(); if (plugin) { // Unload all plugins not needed for this game, // to save memory diff --git a/base/plugins.cpp b/base/plugins.cpp index aa813297fc..5eca8f394d 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -24,16 +24,21 @@ */ #include "base/plugins.h" -#include "common/util.h" #ifdef DYNAMIC_MODULES #include "common/config-manager.h" +#include "common/fs.h" #endif +// Plugin versioning + int pluginTypeVersions[PLUGIN_TYPE_MAX] = { PLUGIN_TYPE_ENGINE_VERSION, }; + +// Abstract plugins + PluginType Plugin::getType() const { return _type; } @@ -42,31 +47,6 @@ const char *Plugin::getName() const { return _pluginObject->getName(); } -const char *Plugin::getCopyright() const { - return ((MetaEngine*)_pluginObject)->getCopyright(); -} - -PluginError Plugin::createInstance(OSystem *syst, Engine **engine) const { - return ((MetaEngine*)_pluginObject)->createInstance(syst, engine); -} - -GameList Plugin::getSupportedGames() const { - return ((MetaEngine*)_pluginObject)->getSupportedGames(); -} - -GameDescriptor Plugin::findGame(const char *gameid) const { - return ((MetaEngine*)_pluginObject)->findGame(gameid); -} - -GameList Plugin::detectGames(const FSList &fslist) const { - return ((MetaEngine*)_pluginObject)->detectGames(fslist); -} - -SaveStateList Plugin::listSaves(const char *target) const { - return ((MetaEngine*)_pluginObject)->listSaves(target); -} - - class StaticPlugin : public Plugin { public: StaticPlugin(PluginObject *pluginobject, PluginType type) { @@ -315,15 +295,72 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) { } } -GameList PluginManager::detectGames(const FSList &fslist) const { + +// Engine plugins + +#include "engines/metaengine.h" + +const char *EnginePlugin::getCopyright() const { + return ((MetaEngine*)_pluginObject)->getCopyright(); +} + +PluginError EnginePlugin::createInstance(OSystem *syst, Engine **engine) const { + return ((MetaEngine*)_pluginObject)->createInstance(syst, engine); +} + +GameList EnginePlugin::getSupportedGames() const { + return ((MetaEngine*)_pluginObject)->getSupportedGames(); +} + +GameDescriptor EnginePlugin::findGame(const char *gameid) const { + return ((MetaEngine*)_pluginObject)->findGame(gameid); +} + +GameList EnginePlugin::detectGames(const FSList &fslist) const { + return ((MetaEngine*)_pluginObject)->detectGames(fslist); +} + +SaveStateList EnginePlugin::listSaves(const char *target) const { + return ((MetaEngine*)_pluginObject)->listSaves(target); +} + +DECLARE_SINGLETON(EngineManager); + +GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const { + // Find the GameDescriptor for this target + const EnginePluginList &plugins = getPlugins(); + GameDescriptor result; + + if (plugin) + *plugin = 0; + + EnginePluginList::const_iterator iter = plugins.begin(); + for (iter = plugins.begin(); iter != plugins.end(); ++iter) { + result = (*iter)->findGame(gameName.c_str()); + if (!result.gameid().empty()) { + if (plugin) + *plugin = *iter; + break; + } + } + return result; +} + +GameList EngineManager::detectGames(const FSList &fslist) const { GameList candidates; + const EnginePluginList &plugins = getPlugins(); + // Iterate over all known games and for each check if it might be // the game in the presented directory. - PluginList::const_iterator iter; - for (iter = _plugins.begin(); iter != _plugins.end(); ++iter) { + EnginePluginList::const_iterator iter; + for (iter = plugins.begin(); iter != plugins.end(); ++iter) { candidates.push_back((*iter)->detectGames(fslist)); } return candidates; } + +const EnginePluginList &EngineManager::getPlugins() const { + return (const EnginePluginList&)PluginManager::instance().getPlugins(); +} diff --git a/base/plugins.h b/base/plugins.h index ec947ee6ad..14ce2a3aa4 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -26,27 +26,12 @@ #ifndef BASE_PLUGINS_H #define BASE_PLUGINS_H -#include "common/array.h" #include "common/error.h" #include "common/list.h" #include "common/singleton.h" -#include "common/util.h" #include "base/game.h" -/** - * 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. - */ -class PluginObject { -public: - virtual ~PluginObject() {} - - /** Returns the name of the plugin. */ - virtual const char *getName() const = 0; -}; - -#include "engines/metaengine.h" +// Plugin versioning // Global Plugin API version #define PLUGIN_VERSION 1 @@ -63,42 +48,8 @@ enum PluginType { extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; -class Engine; -class FSList; -class OSystem; - -/** - * Abstract base class for the plugin system. - * Subclasses for this can be used to wrap both static and dynamic - * plugins. - */ -class Plugin { -protected: - PluginObject *_pluginObject; - PluginType _type; - -public: - Plugin() : _pluginObject(0) {} - virtual ~Plugin() { - //if (isLoaded()) - //unloadPlugin(); - } - -// virtual bool isLoaded() const = 0; // TODO - virtual bool loadPlugin() = 0; // TODO: Rename to load() ? - virtual void unloadPlugin() = 0; // TODO: Rename to unload() ? - - PluginType getType() const; - const char *getName() const; - const char *getCopyright() const; - - PluginError createInstance(OSystem *syst, Engine **engine) const; - GameList getSupportedGames() const; - GameDescriptor findGame(const char *gameid) const; - GameList detectGames(const FSList &fslist) const; - SaveStateList listSaves(const char *target) const; -}; +// Plugin linking #define STATIC_PLUGIN 1 #define DYNAMIC_PLUGIN 2 @@ -147,10 +98,49 @@ public: #endif // DYNAMIC_MODULES +// 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. + */ +class PluginObject { +public: + virtual ~PluginObject() {} + + /** Returns the name of the plugin. */ + virtual const char *getName() const = 0; +}; + +/** + * Abstract base class for the plugin system. + * Subclasses for this can be used to wrap both static and dynamic + * plugins. + */ +class Plugin { +protected: + PluginObject *_pluginObject; + PluginType _type; + +public: + Plugin() : _pluginObject(0) {} + virtual ~Plugin() { + //if (isLoaded()) + //unloadPlugin(); + } + +// virtual bool isLoaded() const = 0; // TODO + virtual bool loadPlugin() = 0; // TODO: Rename to load() ? + virtual void unloadPlugin() = 0; // TODO: Rename to unload() ? + + PluginType getType() const; + const char *getName() const; +}; + /** List of plugins. */ typedef Common::Array PluginList; - class PluginProvider { public: virtual ~PluginProvider() {} @@ -202,8 +192,38 @@ public: void unloadPluginsExcept(const Plugin *plugin); const PluginList &getPlugins() { return _plugins; } +}; + +// Engine plugins + +class Engine; +class FSList; +class OSystem; + +class EnginePlugin : public Plugin { +public: + const char *getCopyright() const; + PluginError createInstance(OSystem *syst, Engine **engine) const; + GameList getSupportedGames() const; + GameDescriptor findGame(const char *gameid) const; GameList detectGames(const FSList &fslist) const; + SaveStateList listSaves(const char *target) const; }; +typedef Common::Array EnginePluginList; + +class EngineManager : public Common::Singleton { +private: + friend class Common::Singleton; + +public: + GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const; + GameList detectGames(const FSList &fslist) const; + const EnginePluginList &getPlugins() const; +}; + +/** Shortcut for accessing the engine manager. */ +#define EngineMan EngineManager::instance() + #endif -- cgit v1.2.3 From 9ba353b9d8f6c4336ca4b6001fe5f22b85a8fb81 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Mon, 12 May 2008 01:26:43 +0000 Subject: Keep separated arrays for each type of plugin svn-id: r32046 --- base/main.cpp | 4 ++-- base/plugins.cpp | 15 ++++++++------- base/plugins.h | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) (limited to 'base') diff --git a/base/main.cpp b/base/main.cpp index 80f77f89ab..8b697e120d 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -302,7 +302,7 @@ extern "C" int scummvm_main(int argc, char *argv[]) { if (plugin) { // Unload all plugins not needed for this game, // to save memory - PluginManager::instance().unloadPluginsExcept(plugin); + PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, plugin); // Try to run the game int result = runGame(plugin, system, specialDebug); @@ -329,7 +329,7 @@ extern "C" int scummvm_main(int argc, char *argv[]) { launcherDialog(system); } - PluginManager::instance().unloadPluginsExcept(NULL); + PluginManager::instance().unloadPlugins(); PluginManager::destroy(); Common::ConfigManager::destroy(); GUI::NewGui::destroy(); diff --git a/base/plugins.cpp b/base/plugins.cpp index 5eca8f394d..d2bd9b398a 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -253,12 +253,13 @@ void PluginManager::loadPlugins() { } void PluginManager::unloadPlugins() { - unloadPluginsExcept(NULL); + for (int i = 0; i < PLUGIN_TYPE_MAX; i++) + unloadPluginsExcept((PluginType)i, NULL); } -void PluginManager::unloadPluginsExcept(const Plugin *plugin) { +void PluginManager::unloadPluginsExcept(PluginType type, const Plugin *plugin) { Plugin *found = NULL; - for (PluginList::iterator p = _plugins.begin(); p != _plugins.end(); ++p) { + for (PluginList::iterator p = _plugins[type].begin(); p != _plugins[type].end(); ++p) { if (*p == plugin) { found = *p; } else { @@ -266,9 +267,9 @@ void PluginManager::unloadPluginsExcept(const Plugin *plugin) { delete *p; } } - _plugins.clear(); + _plugins[type].clear(); if (found != NULL) { - _plugins.push_back(found); + _plugins[type].push_back(found); } } @@ -277,7 +278,7 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) { // Try to load the plugin if (plugin->loadPlugin()) { // If successful, add it to the list of known plugins and return. - _plugins.push_back(plugin); + _plugins[plugin->getType()].push_back(plugin); // TODO/FIXME: We should perform some additional checks here: // * Check for some kind of "API version" (possibly derived from the @@ -362,5 +363,5 @@ GameList EngineManager::detectGames(const FSList &fslist) const { } const EnginePluginList &EngineManager::getPlugins() const { - return (const EnginePluginList&)PluginManager::instance().getPlugins(); + return (const EnginePluginList&)PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE); } diff --git a/base/plugins.h b/base/plugins.h index 14ce2a3aa4..3f2d19fd50 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -174,7 +174,7 @@ protected: class PluginManager : public Common::Singleton { typedef Common::List ProviderList; private: - PluginList _plugins; + PluginList _plugins[PLUGIN_TYPE_MAX]; ProviderList _providers; bool tryLoadPlugin(Plugin *plugin); @@ -189,9 +189,9 @@ public: void loadPlugins(); void unloadPlugins(); - void unloadPluginsExcept(const Plugin *plugin); + void unloadPluginsExcept(PluginType type, const Plugin *plugin); - const PluginList &getPlugins() { return _plugins; } + const PluginList &getPlugins(PluginType t) { return _plugins[t]; } }; -- cgit v1.2.3 From fe58f0ee4b9d91f4ed349bafb16d2a8d6fb59faa Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Tue, 13 May 2008 09:30:23 +0000 Subject: - Added operator-> to Plugin subclasses so they don't have to reimplement the PluginObject subclass interfaces (thanks to Fingolfin for suggesting it) - Added the PluginSubclass template to help creating Plugin subclasses svn-id: r32082 --- base/commandLine.cpp | 10 +++++----- base/main.cpp | 3 ++- base/plugins.cpp | 40 ++++++++-------------------------------- base/plugins.h | 28 ++++++++++++++-------------- 4 files changed, 29 insertions(+), 52 deletions(-) (limited to 'base') diff --git a/base/commandLine.cpp b/base/commandLine.cpp index 5b919a495c..d2f286cc4a 100644 --- a/base/commandLine.cpp +++ b/base/commandLine.cpp @@ -23,7 +23,7 @@ * */ -#include "engines/engine.h" +#include "engines/metaengine.h" #include "base/commandLine.h" #include "base/plugins.h" #include "base/version.h" @@ -559,10 +559,10 @@ static void listGames() { printf("Game ID Full Title \n" "-------------------- ------------------------------------------------------\n"); - const EnginePluginList &plugins = EngineMan.getPlugins(); - EnginePluginList::const_iterator iter = plugins.begin(); + const EnginePlugin::list &plugins = EngineMan.getPlugins(); + EnginePlugin::list::const_iterator iter = plugins.begin(); for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - GameList list = (*iter)->getSupportedGames(); + GameList list = (**iter)->getSupportedGames(); for (GameList::iterator v = list.begin(); v != list.end(); ++v) { printf("%-20s %s\n", v->gameid().c_str(), v->description().c_str()); } @@ -622,7 +622,7 @@ static void listSaves(const char *target) { } // Query the plugin for a list of savegames - SaveStateList saveList = plugin->listSaves(target); + SaveStateList saveList = (*plugin)->listSaves(target); // TODO: Include more info about the target (desc, engine name, ...) ??? printf("Saves for target '%s':\n", target); diff --git a/base/main.cpp b/base/main.cpp index 8b697e120d..c36c506d7f 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -32,6 +32,7 @@ */ #include "engines/engine.h" +#include "engines/metaengine.h" #include "base/commandLine.h" #include "base/plugins.h" #include "base/version.h" @@ -138,7 +139,7 @@ static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::St // Create the game engine Engine *engine = 0; - PluginError err = plugin->createInstance(&system, &engine); + PluginError err = (*plugin)->createInstance(&system, &engine); if (!engine || err != kNoError) { // TODO: Show an error dialog or so? // TODO: Also take 'err' into consideration... diff --git a/base/plugins.cpp b/base/plugins.cpp index d2bd9b398a..d4153f17d3 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -301,43 +301,19 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) { #include "engines/metaengine.h" -const char *EnginePlugin::getCopyright() const { - return ((MetaEngine*)_pluginObject)->getCopyright(); -} - -PluginError EnginePlugin::createInstance(OSystem *syst, Engine **engine) const { - return ((MetaEngine*)_pluginObject)->createInstance(syst, engine); -} - -GameList EnginePlugin::getSupportedGames() const { - return ((MetaEngine*)_pluginObject)->getSupportedGames(); -} - -GameDescriptor EnginePlugin::findGame(const char *gameid) const { - return ((MetaEngine*)_pluginObject)->findGame(gameid); -} - -GameList EnginePlugin::detectGames(const FSList &fslist) const { - return ((MetaEngine*)_pluginObject)->detectGames(fslist); -} - -SaveStateList EnginePlugin::listSaves(const char *target) const { - return ((MetaEngine*)_pluginObject)->listSaves(target); -} - DECLARE_SINGLETON(EngineManager); GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const { // Find the GameDescriptor for this target - const EnginePluginList &plugins = getPlugins(); + const EnginePlugin::list &plugins = getPlugins(); GameDescriptor result; if (plugin) *plugin = 0; - EnginePluginList::const_iterator iter = plugins.begin(); + EnginePlugin::list::const_iterator iter = plugins.begin(); for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - result = (*iter)->findGame(gameName.c_str()); + result = (**iter)->findGame(gameName.c_str()); if (!result.gameid().empty()) { if (plugin) *plugin = *iter; @@ -350,18 +326,18 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng GameList EngineManager::detectGames(const FSList &fslist) const { GameList candidates; - const EnginePluginList &plugins = getPlugins(); + const EnginePlugin::list &plugins = getPlugins(); // Iterate over all known games and for each check if it might be // the game in the presented directory. - EnginePluginList::const_iterator iter; + EnginePlugin::list::const_iterator iter; for (iter = plugins.begin(); iter != plugins.end(); ++iter) { - candidates.push_back((*iter)->detectGames(fslist)); + candidates.push_back((**iter)->detectGames(fslist)); } return candidates; } -const EnginePluginList &EngineManager::getPlugins() const { - return (const EnginePluginList&)PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE); +const EnginePlugin::list &EngineManager::getPlugins() const { + return (const EnginePlugin::list&)PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE); } diff --git a/base/plugins.h b/base/plugins.h index 3f2d19fd50..858c8d9106 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -141,6 +141,17 @@ public: /** List of plugins. */ typedef Common::Array PluginList; +/** Template to help defining Plugin subclasses */ +template +class PluginSubclass : public Plugin { +public: + PO_t *operator->() const { + return (PO_t *)_pluginObject; + } + + typedef Common::Array list; +}; + class PluginProvider { public: virtual ~PluginProvider() {} @@ -197,21 +208,10 @@ public: // Engine plugins -class Engine; class FSList; -class OSystem; - -class EnginePlugin : public Plugin { -public: - const char *getCopyright() const; - PluginError createInstance(OSystem *syst, Engine **engine) const; - GameList getSupportedGames() const; - GameDescriptor findGame(const char *gameid) const; - GameList detectGames(const FSList &fslist) const; - SaveStateList listSaves(const char *target) const; -}; +class MetaEngine; -typedef Common::Array EnginePluginList; +typedef PluginSubclass EnginePlugin; class EngineManager : public Common::Singleton { private: @@ -220,7 +220,7 @@ private: public: GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const; GameList detectGames(const FSList &fslist) const; - const EnginePluginList &getPlugins() const; + const EnginePlugin::list &getPlugins() const; }; /** Shortcut for accessing the engine manager. */ -- cgit v1.2.3 From 2bb39e591f4184f0ae8102c8f547586bf95d2b50 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 13 May 2008 10:41:32 +0000 Subject: Moved the engine plugin code to engines/metaengine.h; added/clarified/corrected various Doxygen comments for the plugin system svn-id: r32083 --- base/plugins.h | 77 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 33 deletions(-) (limited to 'base') diff --git a/base/plugins.h b/base/plugins.h index 858c8d9106..b1236eeeb1 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -33,7 +33,7 @@ // Plugin versioning -// Global Plugin API version +/** Global Plugin API version */ #define PLUGIN_VERSION 1 enum PluginType { @@ -67,14 +67,14 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; (defined(ENABLE_##ID) && (ENABLE_##ID == DYNAMIC_PLUGIN) && defined(DYNAMIC_MODULES)) /** - * REGISTER_PLUGIN is a convenience macro meant to ease writing - * the plugin interface for our modules. In particular, using it - * makes it possible to compile the very same code in a module - * both as a static and a dynamic plugin. + * REGISTER_PLUGIN_STATIC is a convenience macro which is used to declare + * the plugin interface for static plugins. Code (such as game engines) + * which needs to implement a static plugin can simply invoke this macro + * with a plugin ID, plugin type and PluginObject subclass, and the correct + * wrapper code will be inserted. * - * @todo add some means to query the plugin API version etc. + * @see REGISTER_PLUGIN_DYNAMIC */ - #define REGISTER_PLUGIN_STATIC(ID,TYPE,PLUGINCLASS) \ PluginType g_##ID##_type = TYPE; \ PluginObject *g_##ID##_getObject() { \ @@ -84,6 +84,15 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; #ifdef DYNAMIC_MODULES +/** + * REGISTER_PLUGIN_DYNAMIC is a convenience macro which is used to declare + * the plugin interface for dynamically loadable plugins. Code (such as game engines) + * which needs to implement a dynamic plugin can simply invoke this macro + * with a plugin ID, plugin type and PluginObject subclass, and the correct + * wrapper code will be inserted. + * + * @see REGISTER_PLUGIN_STATIC + */ #define REGISTER_PLUGIN_DYNAMIC(ID,TYPE,PLUGINCLASS) \ extern "C" { \ PLUGIN_EXPORT int32 PLUGIN_getVersion() { return PLUGIN_VERSION; } \ @@ -138,10 +147,14 @@ public: const char *getName() const; }; -/** List of plugins. */ +/** List of Plugin instances. */ typedef Common::Array PluginList; -/** Template to help defining Plugin subclasses */ +/** + * Convenience template to make it easier defining normal Plugin + * subclasses. Namely, the PluginSubclass will manage PluginObjects + * of a type specified via the PO_t template parameter. + */ template class PluginSubclass : public Plugin { public: @@ -152,24 +165,43 @@ public: typedef Common::Array list; }; +/** + * Abstract base class for Plugin factories. Subclasses of this + * are responsible for creating plugin objects, e.g. by loading + * loadable modules from storage media; by creating "fake" plugins + * from static code; or whatever other means. + */ class PluginProvider { public: virtual ~PluginProvider() {} /** * Return a list of Plugin objects. The caller is responsible for actually - * loading/unloading them (by invoking the appropriate methods). + * loading/unloading them (by invoking the appropriate Plugin methods). * Furthermore, the caller is responsible for deleting these objects * eventually. */ virtual PluginList getPlugins() = 0; }; +/** + * Abstract base class for Plugin factories which load binary code from files. + * Subclasses only have to implement the createPlugin() method, and optionally + * can overload the other protected methods to achieve custom behavior. + */ class FilePluginProvider : public PluginProvider { public: virtual PluginList getPlugins(); protected: + /** + * Create a Plugin instance from a loadable code module with the specified name. + * Subclasses of FilePluginProvider have to at least overload this method. + * If the file is not found, or does not contain loadable code, 0 is returned instead. + * + * @param filename the name of the loadable code module + * @return a pointer to a Plugin instance, or 0 if an error occured. + */ virtual Plugin* createPlugin(const Common::String &filename) const = 0; virtual const char* getPrefix() const; @@ -179,8 +211,8 @@ protected: }; /** - * Instances of this class manage all plugins, including loading them, - * making wrapper objects of class Plugin available, and unloading them. + * Singleton class which manages all plugins, including loading them, + * managing all Plugin class instances, and unloading them. */ class PluginManager : public Common::Singleton { typedef Common::List ProviderList; @@ -205,25 +237,4 @@ public: const PluginList &getPlugins(PluginType t) { return _plugins[t]; } }; - -// Engine plugins - -class FSList; -class MetaEngine; - -typedef PluginSubclass EnginePlugin; - -class EngineManager : public Common::Singleton { -private: - friend class Common::Singleton; - -public: - GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const; - GameList detectGames(const FSList &fslist) const; - const EnginePlugin::list &getPlugins() const; -}; - -/** Shortcut for accessing the engine manager. */ -#define EngineMan EngineManager::instance() - #endif -- cgit v1.2.3 From f7a682edf9c2c9a50cba9b869f447a9781def64b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 13 May 2008 11:00:25 +0000 Subject: Some more Doxygen comments, as well as some FIXMEs/TODOs svn-id: r32084 --- base/plugins.h | 48 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'base') diff --git a/base/plugins.h b/base/plugins.h index b1236eeeb1..8c0158a912 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -31,6 +31,28 @@ #include "common/singleton.h" #include "base/game.h" + +/** + * @page pagePlugins An overview of the ScummVM plugin system + * This is a brief overview of how plugins (dynamically loadable code modules) + * work in ScummVM. We will explain how to write plugins, how they work internally, + * and sketch how porters can add support for them in their ports. + * + * \section secPluginImpl Implementing a plugin + * TODO + * + * \section secPluginUse Using plugins + * TODO + * + * \section secPluginInternals How plugins work internally + * TODO + * + * \section secPluginBackend How to add support for dynamic plugins to a port + * TODO + */ + + + // Plugin versioning /** Global Plugin API version */ @@ -113,6 +135,8 @@ extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; * 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 */ class PluginObject { public: @@ -126,6 +150,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 */ class Plugin { protected: @@ -180,6 +206,8 @@ public: * loading/unloading them (by invoking the appropriate Plugin methods). * Furthermore, the caller is responsible for deleting these objects * eventually. + * + * @return a list of Plugin instances */ virtual PluginList getPlugins() = 0; }; @@ -191,6 +219,15 @@ public: */ class FilePluginProvider : public PluginProvider { public: + /** + * Return a list of Plugin objects loaded via createPlugin from disk. + * For this, a list of directories is searched for plugin objects: + * The current dir and its "plugins" subdirectory (if present), a list + * of custom search dirs (see addCustomDirectories) and finally the + * directory specified via the "pluginspath" config variable (if any). + * + * @return a list of Plugin instances + */ virtual PluginList getPlugins(); protected: @@ -200,13 +237,22 @@ protected: * If the file is not found, or does not contain loadable code, 0 is returned instead. * * @param filename the name of the loadable code module - * @return a pointer to a Plugin instance, or 0 if an error occured. + * @return a pointer to a Plugin instance, or 0 if an error occurred. + * + * FIXME: Instead of using getPrefix & getSuffix, how about adding a + * isPluginFilename() class, so that more flexible checks can be performed? */ virtual Plugin* createPlugin(const Common::String &filename) const = 0; virtual const char* getPrefix() const; virtual const char* getSuffix() const; + /** + * Optionally add to the list of directories to be searched for + * plugins by getPlugins(). + * + * FIXME: This should be using FSNodes, not strings! + */ virtual void addCustomDirectories(Common::StringList &dirs) const; }; -- cgit v1.2.3 From a392bc4b0e860429ec8ba7a79bc6ed4eab8f0335 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Tue, 13 May 2008 13:24:49 +0000 Subject: Taken care of FilePluginProvider's FIXMEs svn-id: r32085 --- base/plugins.cpp | 49 ++++++++++++++++++++++--------------------------- base/plugins.h | 25 ++++++++++++++++++------- 2 files changed, 40 insertions(+), 34 deletions(-) (limited to 'base') diff --git a/base/plugins.cpp b/base/plugins.cpp index d4153f17d3..c39b877eb8 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -27,7 +27,6 @@ #ifdef DYNAMIC_MODULES #include "common/config-manager.h" -#include "common/fs.h" #endif // Plugin versioning @@ -151,38 +150,34 @@ PluginList FilePluginProvider::getPlugins() { PluginList pl; // Prepare the list of directories to search - Common::StringList pluginDirs; + FSList pluginDirs; // Add the default directories - pluginDirs.push_back("."); - pluginDirs.push_back("plugins"); + pluginDirs.push_back(FilesystemNode(".")); + pluginDirs.push_back(FilesystemNode("plugins")); // Add the provider's custom directories addCustomDirectories(pluginDirs); // Add the user specified directory Common::String pluginsPath(ConfMan.get("pluginspath")); - if (!pluginsPath.empty()) { - FilesystemNode dir(pluginsPath); - pluginDirs.push_back(dir.getPath()); - } + if (!pluginsPath.empty()) + pluginDirs.push_back(FilesystemNode(pluginsPath)); - Common::StringList::const_iterator d; - for (d = pluginDirs.begin(); d != pluginDirs.end(); d++) { + FSList::const_iterator dir; + for (dir = pluginDirs.begin(); dir != pluginDirs.end(); dir++) { // Load all plugins. // Scan for all plugins in this directory - FilesystemNode dir(*d); FSList files; - if (!dir.getChildren(files, FilesystemNode::kListFilesOnly)) { - debug(1, "Couldn't open plugin directory '%s'", d->c_str()); + if (!dir->getChildren(files, FilesystemNode::kListFilesOnly)) { + debug(1, "Couldn't open plugin directory '%s'", dir->getPath().c_str()); continue; } else { - debug(1, "Reading plugins from plugin directory '%s'", d->c_str()); + debug(1, "Reading plugins from plugin directory '%s'", dir->getPath().c_str()); } for (FSList::const_iterator i = files.begin(); i != files.end(); ++i) { - Common::String name(i->getName()); - if (name.hasPrefix(getPrefix()) && name.hasSuffix(getSuffix())) { + if (isPluginFilename(i->getName())) { pl.push_back(createPlugin(i->getPath())); } } @@ -191,25 +186,25 @@ PluginList FilePluginProvider::getPlugins() { return pl; } -const char* FilePluginProvider::getPrefix() const { +bool FilePluginProvider::isPluginFilename(const Common::String &filename) const { #ifdef PLUGIN_PREFIX - return PLUGIN_PREFIX; -#else - return ""; + // Check the plugin prefix + if (!filename.hasPrefix(PLUGIN_PREFIX)) + return false; #endif -} -const char* FilePluginProvider::getSuffix() const { #ifdef PLUGIN_SUFFIX - return PLUGIN_SUFFIX; -#else - return ""; + // Check the plugin suffix + if (!filename.hasSuffix(PLUGIN_SUFFIX)) + return false; #endif + + return true; } -void FilePluginProvider::addCustomDirectories(Common::StringList &dirs) const { +void FilePluginProvider::addCustomDirectories(FSList &dirs) const { #ifdef PLUGIN_DIRECTORY - dirs.push_back(PLUGIN_DIRECTORY); + dirs.push_back(FilesystemNode(PLUGIN_DIRECTORY)); #endif } diff --git a/base/plugins.h b/base/plugins.h index 8c0158a912..92b317498f 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -31,6 +31,9 @@ #include "common/singleton.h" #include "base/game.h" +#ifdef DYNAMIC_MODULES +#include "common/fs.h" +#endif /** * @page pagePlugins An overview of the ScummVM plugin system @@ -212,6 +215,8 @@ public: virtual PluginList getPlugins() = 0; }; +#ifdef DYNAMIC_MODULES + /** * Abstract base class for Plugin factories which load binary code from files. * Subclasses only have to implement the createPlugin() method, and optionally @@ -238,24 +243,30 @@ protected: * * @param filename the name of the loadable code module * @return a pointer to a Plugin instance, or 0 if an error occurred. - * - * FIXME: Instead of using getPrefix & getSuffix, how about adding a - * isPluginFilename() class, so that more flexible checks can be performed? */ virtual Plugin* createPlugin(const Common::String &filename) const = 0; - virtual const char* getPrefix() const; - virtual const char* getSuffix() const; + /** + * Check if the supplied filename corresponds to a loadable plugin file in + * the current platform. + * + * @param filename the name of the file to check + * @return true if the filename corresponds to a plugin, false otherwise + */ + virtual bool isPluginFilename(const Common::String &filename) const; /** * Optionally add to the list of directories to be searched for * plugins by getPlugins(). * - * FIXME: This should be using FSNodes, not strings! + * @param dirs the reference to the list of directories to be used when + * searching for plugins. */ - virtual void addCustomDirectories(Common::StringList &dirs) const; + virtual void addCustomDirectories(FSList &dirs) const; }; +#endif // DYNAMIC_MODULES + /** * Singleton class which manages all plugins, including loading them, * managing all Plugin class instances, and unloading them. -- cgit v1.2.3 From eb6c809d2b3ccf238fa5efbf45b6cd2b00a82cd9 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Wed, 14 May 2008 14:56:29 +0000 Subject: - Added more information (ID and capabilities) to the MIDI drivers - Added the MidiPlugin interface to the remaining MIDI drivers - Added an initial MidiManager to handle the MIDI plugins (just static plugins by now) svn-id: r32117 --- base/plugins.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ base/plugins.h | 2 ++ 2 files changed, 58 insertions(+) (limited to 'base') diff --git a/base/plugins.cpp b/base/plugins.cpp index c39b877eb8..7dae94e006 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -33,6 +33,7 @@ int pluginTypeVersions[PLUGIN_TYPE_MAX] = { PLUGIN_TYPE_ENGINE_VERSION, + PLUGIN_TYPE_MIDI_VERSION, }; @@ -82,6 +83,7 @@ public: // "Loader" for the static plugins. // Iterate over all registered (static) plugins and load them. + // Engine plugins #if PLUGIN_ENABLED_STATIC(SCUMM) LINK_PLUGIN(SCUMM) #endif @@ -140,6 +142,49 @@ public: LINK_PLUGIN(TOUCHE) #endif + // MIDI plugins + // TODO: Use defines to disable or enable each MIDI driver as a + // static/dynamic plugin, like it's done for the engines + LINK_PLUGIN(NULL) + #if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) + LINK_PLUGIN(WINDOWS) + #endif + #if defined(UNIX) && defined(USE_ALSA) + LINK_PLUGIN(ALSA) + #endif + #if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) + LINK_PLUGIN(SEQ) + #endif + #if defined(IRIX) + LINK_PLUGIN(DMEDIA) + #endif + #if defined(__amigaos4__) + LINK_PLUGIN(CAMD) + #endif + #if defined(MACOSX) + LINK_PLUGIN(COREAUDIO) + LINK_PLUGIN(COREMIDI) + LINK_PLUGIN(QUICKTIME) + #endif + #if defined(PALMOS_MODE) + # if defined(COMPILE_CLIE) + LINK_PLUGIN(YPA1) + # elif defined(COMPILE_ZODIAC) && (!defined(ENABLE_SCUMM) || !defined(PALMOS_ARM)) + LINK_PLUGIN(ZODIAC) + # endif + #endif + #ifdef USE_FLUIDSYNTH + LINK_PLUGIN(FLUIDSYNTH) + #endif + #ifdef USE_MT32EMU + LINK_PLUGIN(MT32) + #endif + LINK_PLUGIN(ADLIB) + LINK_PLUGIN(TOWNS) + #if defined (UNIX) + LINK_PLUGIN(TIMIDITY) + #endif + return pl; } }; @@ -336,3 +381,14 @@ GameList EngineManager::detectGames(const FSList &fslist) const { const EnginePlugin::list &EngineManager::getPlugins() const { return (const EnginePlugin::list&)PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE); } + + +// MIDI plugins + +#include "sound/midiplugin.h" + +DECLARE_SINGLETON(MidiManager); + +const MidiPlugin::list &MidiManager::getPlugins() const { + return (const MidiPlugin::list&)PluginManager::instance().getPlugins(PLUGIN_TYPE_MIDI); +} diff --git a/base/plugins.h b/base/plugins.h index 92b317498f..b64334074c 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -63,6 +63,7 @@ enum PluginType { PLUGIN_TYPE_ENGINE = 0, + PLUGIN_TYPE_MIDI, PLUGIN_TYPE_MAX }; @@ -70,6 +71,7 @@ enum PluginType { // TODO: Make the engine API version depend on ScummVM's version // because of the backlinking #define PLUGIN_TYPE_ENGINE_VERSION 1 +#define PLUGIN_TYPE_MIDI_VERSION 1 extern int pluginTypeVersions[PLUGIN_TYPE_MAX]; -- cgit v1.2.3 From b35941c3c2da0b1c184390ee601689cedebdb32c Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Wed, 14 May 2008 17:26:05 +0000 Subject: Added plugin priority so there's just one plugin that provides a module functionality. svn-id: r32121 --- base/plugins.cpp | 30 ++++++++++++++++++++---------- base/plugins.h | 7 +++---- 2 files changed, 23 insertions(+), 14 deletions(-) (limited to 'base') diff --git a/base/plugins.cpp b/base/plugins.cpp index 7dae94e006..ac8e498469 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -317,16 +317,26 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) { assert(plugin); // Try to load the plugin if (plugin->loadPlugin()) { - // If successful, add it to the list of known plugins and return. - _plugins[plugin->getType()].push_back(plugin); - - // TODO/FIXME: We should perform some additional checks here: - // * Check for some kind of "API version" (possibly derived from the - // SVN tree revision?) - // * If two plugins provide the same engine, we should only load one. - // To detect this situation, we could just compare the plugin name. - // To handle it, simply prefer modules loaded earlier to those coming. - // Or vice versa... to be determined... :-) + // The plugin is valid, see if it provides the same module as an + // already loaded one and should replace it. + bool found = false; + + PluginList::iterator pl = _plugins[plugin->getType()].begin(); + while (!found && pl != _plugins[plugin->getType()].end()) { + if (!strcmp(plugin->getName(), (*pl)->getName())) { + // Found a duplicated module. Replace the old one. + found = true; + delete *pl; + *pl = plugin; + debug(1, "Replaced the duplicated plugin: '%s'", plugin->getName()); + } + pl++; + } + + if (!found) { + // If it provides a new module, just add it to the list of known plugins. + _plugins[plugin->getType()].push_back(plugin); + } return true; } else { diff --git a/base/plugins.h b/base/plugins.h index b64334074c..d03a240922 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -27,9 +27,8 @@ #define BASE_PLUGINS_H #include "common/error.h" -#include "common/list.h" #include "common/singleton.h" -#include "base/game.h" +#include "common/util.h" #ifdef DYNAMIC_MODULES #include "common/fs.h" @@ -69,7 +68,7 @@ enum PluginType { }; // TODO: Make the engine API version depend on ScummVM's version -// because of the backlinking +// because of the backlinking (posibly from the SVN revision) #define PLUGIN_TYPE_ENGINE_VERSION 1 #define PLUGIN_TYPE_MIDI_VERSION 1 @@ -274,7 +273,7 @@ protected: * managing all Plugin class instances, and unloading them. */ class PluginManager : public Common::Singleton { - typedef Common::List ProviderList; + typedef Common::Array ProviderList; private: PluginList _plugins[PLUGIN_TYPE_MAX]; ProviderList _providers; -- cgit v1.2.3