aboutsummaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorVicent Marti2008-06-14 14:44:29 +0000
committerVicent Marti2008-06-14 14:44:29 +0000
commitd0b27cf9c66b9281899acf826cb205e19dcb7260 (patch)
tree74e813b1d1f081f35f41ca7a95da5d048951b9e7 /base
parentd51a0cab3fe494698f001d81d5d86cea7cd0395b (diff)
parent91d3ea31359950b59ee46af8355cc0f5790257e5 (diff)
downloadscummvm-rg350-d0b27cf9c66b9281899acf826cb205e19dcb7260.tar.gz
scummvm-rg350-d0b27cf9c66b9281899acf826cb205e19dcb7260.tar.bz2
scummvm-rg350-d0b27cf9c66b9281899acf826cb205e19dcb7260.zip
Merged trunk into the GUI branch.
Fixed MSVS9 project files. svn-id: r32702
Diffstat (limited to 'base')
-rw-r--r--base/commandLine.cpp27
-rw-r--r--base/game.cpp26
-rw-r--r--base/game.h11
-rw-r--r--base/main.cpp28
-rw-r--r--base/plugins.cpp231
-rw-r--r--base/plugins.h240
6 files changed, 359 insertions, 204 deletions
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index a4c867edee..b9fd4ecfb7 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"
@@ -46,6 +46,8 @@
#endif
#elif defined(__SYMBIAN32__)
#define DEFAULT_SAVE_PATH "Savegames"
+#elif defined(PALMOS_MODE)
+#define DEFAULT_SAVE_PATH "/PALM/Programs/ScummVM/Saved"
#endif
#define DETECTOR_TESTING_HACK
@@ -146,7 +148,7 @@ static void usage(const char *s, ...) {
vsnprintf(buf, STRINGBUFLEN, s, va);
va_end(va);
-#if !(defined(PALMOS_ARM) || defined(PALMOS_DEBUG) || defined(__GP32__) || defined (__SYMBIAN32__))
+#if !(defined(__GP32__) || defined (__SYMBIAN32__))
printf(USAGE_STRING, s_appName, buf, s_appName, s_appName);
#endif
exit(1);
@@ -229,6 +231,9 @@ void registerDefaults() {
ConfMan.registerDefault("savepath", savePath);
#elif defined (IPHONE)
ConfMan.registerDefault("savepath", OSystem_IPHONE::getSavePath());
+
+#elif defined(PALMOS_MODE)
+ ConfMan.registerDefault("savepath", DEFAULT_SAVE_PATH);
#endif
#endif // #ifdef DEFAULT_SAVE_PATH
@@ -559,10 +564,10 @@ static void listGames() {
printf("Game ID Full Title \n"
"-------------------- ------------------------------------------------------\n");
- const PluginList &plugins = PluginManager::instance().getPlugins();
- PluginList::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());
}
@@ -586,7 +591,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 +618,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);
@@ -622,7 +627,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);
@@ -667,7 +672,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 +745,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<SaveStateDescriptor> 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 d0da338e2a..20775f24db 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"
@@ -90,8 +91,8 @@ static bool launcherDialog(OSystem &system) {
#endif // vector renderer debug
}
-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());
@@ -102,23 +103,26 @@ static const Plugin *detectPlugin() {
ConfMan.set("gameid", gameid);
// 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);
+ printf("User picked target '%s' (gameid '%s')...\n", ConfMan.getActiveDomainName().c_str(), gameid.c_str());
+ printf(" Looking for a plugin supporting this gameid... ");
+ GameDescriptor game = EngineMan.findGame(gameid, &plugin);
if (plugin == 0) {
- printf("Failed game detection\n");
+ printf("failed\n");
warning("%s is an invalid gameid. Use the --list-games option to list supported gameid", gameid.c_str());
return 0;
+ } else {
+ printf("%s\n", plugin->getName());
}
// FIXME: Do we really need this one?
- printf("Trying to start game '%s'\n", game.description().c_str());
+ printf(" Starting '%s'\n", game.description().c_str());
return plugin;
}
// 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() != '/'
@@ -151,7 +155,7 @@ static int runGame(const Plugin *plugin, OSystem &system, const Common::String &
// 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...
@@ -181,7 +185,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())
@@ -311,11 +315,11 @@ 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
- PluginManager::instance().unloadPluginsExcept(plugin);
+ PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, plugin);
// Try to run the game
int result = runGame(plugin, system, specialDebug);
@@ -342,7 +346,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 9e2c2599ce..dcd394495f 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -24,12 +24,23 @@
*/
#include "base/plugins.h"
-#include "common/util.h"
+
+#include "common/func.h"
+
+#ifdef DYNAMIC_MODULES
+#include "common/config-manager.h"
+#endif
+
+// Plugin versioning
int pluginTypeVersions[PLUGIN_TYPE_MAX] = {
PLUGIN_TYPE_ENGINE_VERSION,
+ PLUGIN_TYPE_MUSIC_VERSION,
};
+
+// Abstract plugins
+
PluginType Plugin::getType() const {
return _type;
}
@@ -38,31 +49,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) {
@@ -99,6 +85,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
@@ -157,6 +144,49 @@ public:
LINK_PLUGIN(TOUCHE)
#endif
+ // Music 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;
}
};
@@ -167,30 +197,34 @@ PluginList FilePluginProvider::getPlugins() {
PluginList pl;
// Prepare the list of directories to search
- Common::StringList pluginDirs;
- // TODO: Add the user specified directory (via config file)
- pluginDirs.push_back(".");
- pluginDirs.push_back("plugins");
+ FSList pluginDirs;
+
+ // Add the default directories
+ pluginDirs.push_back(FilesystemNode("."));
+ pluginDirs.push_back(FilesystemNode("plugins"));
// Add the provider's custom directories
addCustomDirectories(pluginDirs);
- Common::StringList::const_iterator d;
- for (d = pluginDirs.begin(); d != pluginDirs.end(); d++) {
+ // Add the user specified directory
+ Common::String pluginsPath(ConfMan.get("pluginspath"));
+ if (!pluginsPath.empty())
+ pluginDirs.push_back(FilesystemNode(pluginsPath));
+
+ 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()));
}
}
@@ -199,25 +233,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
}
@@ -252,31 +286,30 @@ void PluginManager::loadPlugins() {
for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end();
++pp) {
- PluginList pl((**pp).getPlugins());
- for (PluginList::iterator plugin = pl.begin(); plugin != pl.end(); ++plugin) {
- tryLoadPlugin(*plugin);
- }
+ PluginList pl((*pp)->getPlugins());
+ Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
}
}
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 {
- (**p).unloadPlugin();
+ (*p)->unloadPlugin();
delete *p;
}
}
- _plugins.clear();
+ _plugins[type].clear();
if (found != NULL) {
- _plugins.push_back(found);
+ _plugins[type].push_back(found);
}
}
@@ -284,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.push_back(plugin);
+ // 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++;
+ }
- // 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... :-)
+ 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 {
@@ -303,15 +346,59 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
}
}
-GameList PluginManager::detectGames(const FSList &fslist) const {
+
+// Engine plugins
+
+#include "engines/metaengine.h"
+
+DECLARE_SINGLETON(EngineManager);
+
+GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
+ // Find the GameDescriptor for this target
+ const EnginePlugin::List &plugins = getPlugins();
+ GameDescriptor result;
+
+ if (plugin)
+ *plugin = 0;
+
+ EnginePlugin::List::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 EnginePlugin::List &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) {
- candidates.push_back((*iter)->detectGames(fslist));
+ EnginePlugin::List::const_iterator iter;
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ candidates.push_back((**iter)->detectGames(fslist));
}
return candidates;
}
+
+const EnginePlugin::List &EngineManager::getPlugins() const {
+ return (const EnginePlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_ENGINE);
+}
+
+
+// Music plugins
+
+#include "sound/musicplugin.h"
+
+DECLARE_SINGLETON(MusicManager);
+
+const MusicPlugin::List &MusicManager::getPlugins() const {
+ return (const MusicPlugin::List &)PluginManager::instance().getPlugins(PLUGIN_TYPE_MUSIC);
+}
diff --git a/base/plugins.h b/base/plugins.h
index ca08a0c628..9d3ce97c3b 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -26,98 +26,82 @@
#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"
+
+#ifdef DYNAMIC_MODULES
+#include "common/fs.h"
+#endif
/**
- * 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.
+ * @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
*/
-class PluginObject {
-public:
- virtual ~PluginObject() {}
- /** Returns the name of the plugin. */
- virtual const char *getName() const = 0;
-};
-#include "engines/metaengine.h"
-// Global Plugin API version
+// Plugin versioning
+
+/** Global Plugin API version */
#define PLUGIN_VERSION 1
enum PluginType {
PLUGIN_TYPE_ENGINE = 0,
+ PLUGIN_TYPE_MUSIC,
+ /* PLUGIN_TYPE_SCALER, */ // TODO: Add graphics scaler plugins
PLUGIN_TYPE_MAX
};
// 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_MUSIC_VERSION 1
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
+// Note: The spaces around ENABLE_##ID have been added on purpose for
+// MSVC. For some reason, MSVC tries to add the parenthesis after
+// ENABLE_##ID to the check, thus making it false all the time.
+// Please do NOT remove them, otherwise no engine plugins will be
+// registered under MSVC
+
#define PLUGIN_ENABLED_STATIC(ID) \
- (defined(ENABLE_##ID) && !PLUGIN_ENABLED_DYNAMIC(ID))
+ (defined( ENABLE_##ID ) && !PLUGIN_ENABLED_DYNAMIC(ID))
#define PLUGIN_ENABLED_DYNAMIC(ID) \
- (defined(ENABLE_##ID) && (ENABLE_##ID == DYNAMIC_PLUGIN) && defined(DYNAMIC_MODULES))
+ (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() { \
@@ -127,6 +111,15 @@ public:
#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; } \
@@ -141,44 +134,149 @@ public:
#endif // DYNAMIC_MODULES
-/** List of plugins. */
+// 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
+ */
+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.
+ *
+ * FIXME: This class needs better documentation, esp. how it differs from class PluginObject
+ */
+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 Plugin instances. */
typedef Common::Array<Plugin *> PluginList;
+/**
+ * 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 PO_t>
+class PluginSubclass : public Plugin {
+public:
+ PO_t *operator->() const {
+ return (PO_t *)_pluginObject;
+ }
+
+ typedef Common::Array<PluginSubclass *> 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.
+ *
+ * @return a list of Plugin instances
*/
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
+ * can overload the other protected methods to achieve custom behavior.
+ */
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:
- virtual Plugin* createPlugin(const Common::String &filename) const = 0;
+ /**
+ * 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 occurred.
+ */
+ 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;
- virtual void addCustomDirectories(Common::StringList &dirs) const;
+ /**
+ * Optionally add to the list of directories to be searched for
+ * plugins by getPlugins().
+ *
+ * @param dirs the reference to the list of directories to be used when
+ * searching for plugins.
+ */
+ virtual void addCustomDirectories(FSList &dirs) const;
};
+#endif // DYNAMIC_MODULES
+
/**
- * 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<PluginManager> {
- typedef Common::List<PluginProvider *> ProviderList;
+ typedef Common::Array<PluginProvider *> ProviderList;
private:
- PluginList _plugins;
+ PluginList _plugins[PLUGIN_TYPE_MAX];
ProviderList _providers;
bool tryLoadPlugin(Plugin *plugin);
@@ -193,11 +291,9 @@ public:
void loadPlugins();
void unloadPlugins();
- void unloadPluginsExcept(const Plugin *plugin);
-
- const PluginList &getPlugins() { return _plugins; }
+ void unloadPluginsExcept(PluginType type, const Plugin *plugin);
- GameList detectGames(const FSList &fslist) const;
+ const PluginList &getPlugins(PluginType t) { return _plugins[t]; }
};
#endif