diff options
-rw-r--r-- | TODO | 6 | ||||
-rw-r--r-- | base/plugins.cpp | 204 | ||||
-rw-r--r-- | base/plugins.h | 41 | ||||
-rw-r--r-- | queen/queen.cpp | 41 | ||||
-rw-r--r-- | scumm/scummvm.cpp | 56 | ||||
-rw-r--r-- | simon/simon.cpp | 38 | ||||
-rw-r--r-- | sky/sky.cpp | 29 | ||||
-rw-r--r-- | sword2/sword2.cpp | 37 |
8 files changed, 284 insertions, 168 deletions
@@ -8,12 +8,6 @@ General received). This is useful if multiple levels of event loops have to be ended * Fix the Map<> template, make it more robust; maybe use a red-black tree? * Allow for return-to-launcher instead of a normal "quit" ? -* Improve the argv (command line args) parser -* Extend the Plugin API to provide for "game detection": instead of the - GameSettings::detectname "hack" to detect files, provide a callback - in each Plugin which given a FSList returns a list of candidate targets. - This way, a plugin can implement tests more elaborate than filename - checking, e.g. it could actually peek into the files. * Make some generic "EventLoop" API/class which all backends and the GUI use. Initially this would just call the backend poll_event() etc. methods. But eventually the EventLoop object(s) could be made by the backend. diff --git a/base/plugins.cpp b/base/plugins.cpp index cd777e365d..d64593d952 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -29,6 +29,10 @@ /** Type of factory functions which make new Engine objects. */ typedef Engine *(*EngineFactory)(GameDetector *detector, OSystem *syst); +typedef const char *(*NameFunc)(); +typedef GameList (*TargetListFunc)(); +typedef GameList (*DetectFunc)(const FSList &fslist); + #ifdef DYNAMIC_MODULES @@ -38,37 +42,6 @@ typedef Engine *(*EngineFactory)(GameDetector *detector, OSystem *syst); #error No support for loading plugins on non-unix systems at this point! #endif -#else - -// Factory functions => no need to include the specific classes -// in this header. This serves two purposes: -// 1) Clean seperation from the game modules (scumm, simon) and the generic code -// 2) Faster (compiler doesn't have to parse lengthy header files) -#ifndef DISABLE_SCUMM -extern const GameSettings *Engine_SCUMM_targetList(); -extern Engine *Engine_SCUMM_create(GameDetector *detector, OSystem *syst); -#endif - -#ifndef DISABLE_SIMON -extern Engine *Engine_SIMON_create(GameDetector *detector, OSystem *syst); -extern const GameSettings *Engine_SIMON_targetList(); -#endif - -#ifndef DISABLE_SKY -extern const GameSettings *Engine_SKY_targetList(); -extern Engine *Engine_SKY_create(GameDetector *detector, OSystem *syst); -#endif - -#ifndef DISABLE_SWORD2 -extern const GameSettings *Engine_SWORD2_targetList(); -extern Engine *Engine_SWORD2_create(GameDetector *detector, OSystem *syst); -#endif - -#ifndef DISABLE_QUEEN -extern const GameSettings *Engine_QUEEN_targetList(); -extern Engine *Engine_QUEEN_create(GameDetector *detector, OSystem *syst); -#endif - #endif @@ -89,66 +62,21 @@ GameSettings Plugin::findGame(const char *gameName) const { return result; } + +#pragma mark - + + /** * Auxillary class to simplify transition from old plugin interface to the * new one (which provides an API for game detection). To be removed once * the transition is complete. */ class GameSettingsPlugin : public Plugin { - const GameSettings *_games; +private: + GameList _games; public: - GameSettingsPlugin(const GameSettings *games) : _games(games) { } - GameList getSupportedGames() const { - GameList games; - const GameSettings *g; - for (g = _games; g->gameName; ++g) { - games.push_back(*g); - } - return games; - } - GameList detectGames(const FSList &fslist) const { - GameList games; - const GameSettings *g; - char detectName[128]; - char detectName2[128]; - char detectName3[128]; - - for (g = _games; g->gameName; ++g) { - // Determine the 'detectname' for this game, that is, the name of a - // file that *must* be presented if the directory contains the data - // for this game. For example, FOA requires atlantis.000 - if (g->detectname) { - strcpy(detectName, g->detectname); - strcpy(detectName2, g->detectname); - strcat(detectName2, "."); - detectName3[0] = '\0'; - } else { - strcpy(detectName, g->gameName); - strcpy(detectName2, g->gameName); - strcpy(detectName3, g->gameName); - strcat(detectName, ".000"); - if (g->version >= 7) { - strcat(detectName2, ".la0"); - } else - strcat(detectName2, ".sm0"); - strcat(detectName3, ".he0"); - } - - // Iterate over all files in the given directory - for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) { - const char *gameName = file->displayName().c_str(); - - if ((0 == scumm_stricmp(detectName, gameName)) || - (0 == scumm_stricmp(detectName2, gameName)) || - (0 == scumm_stricmp(detectName3, gameName))) { - // Match found, add to list of candidates, then abort inner loop. - games.push_back(*g); - break; - } - } - } - return games; - } + GameSettingsPlugin(GameList games) : _games(games) { } + GameList getSupportedGames() const { return _games; } }; #pragma mark - @@ -157,9 +85,10 @@ public: class StaticPlugin : public GameSettingsPlugin { const char *_name; EngineFactory _ef; + DetectFunc _df; public: - StaticPlugin(const char *name, const GameSettings *games, EngineFactory ef) - : GameSettingsPlugin(games), _name(name), _ef(ef) { + StaticPlugin(const char *name, GameList games, EngineFactory ef, DetectFunc df) + : GameSettingsPlugin(games), _name(name), _ef(ef), _df(df) { } const char *getName() const { return _name; } @@ -167,6 +96,10 @@ public: Engine *createInstance(GameDetector *detector, OSystem *syst) const { return (*_ef)(detector, syst); } + + GameList detectGames(const FSList &fslist) const { + return (*_df)(fslist); + } }; @@ -181,12 +114,13 @@ class DynamicPlugin : public GameSettingsPlugin { Common::String _name; EngineFactory _ef; + DetectFunc _df; void *findSymbol(const char *symbol); public: DynamicPlugin(const char *filename) - : GameSettingsPlugin(0), _dlHandle(0), _filename(filename), _ef(0) {} + : GameSettingsPlugin(0), _dlHandle(0), _filename(filename), _ef(0), _df(0) {} const char *getName() const { return _name.c_str(); } @@ -195,6 +129,11 @@ public: return (*_ef)(detector, syst); } + GameList detectGames(const FSList &fslist) const { + assert(_df); + return (*_df)(fslist); + } + bool loadPlugin(); void unloadPlugin(); }; @@ -217,9 +156,6 @@ void *DynamicPlugin::findSymbol(const char *symbol) { #endif } -typedef const char *(*NameFunc)(); -typedef const GameSettings *(*TargetListFunc)(); - bool DynamicPlugin::loadPlugin() { assert(!_dlHandle); _dlHandle = dlopen(_filename.c_str(), RTLD_LAZY); @@ -238,20 +174,27 @@ bool DynamicPlugin::loadPlugin() { _name = nameFunc(); // Query the plugin for the targets it supports - TargetListFunc targetListFunc = (TargetListFunc)findSymbol("PLUGIN_getTargetList"); - if (!targetListFunc) { + TargetListFunc gameListFunc = (TargetListFunc)findSymbol("PLUGIN_getSupportedGames"); + if (!gameListFunc) { unloadPlugin(); return false; } - _games = targetListFunc(); + _games = gameListFunc(); - // Finally, retrieve the factory function + // Retrieve the factory function _ef = (EngineFactory)findSymbol("PLUGIN_createEngine"); if (!_ef) { unloadPlugin(); return false; } + // Retrieve the detector function + _df = (DetectFunc)findSymbol("PLUGIN_detectGames"); + if (!_df) { + unloadPlugin(); + return false; + } + return true; } @@ -276,29 +219,7 @@ PluginManager::~PluginManager() { } void PluginManager::loadPlugins() { -#ifndef DYNAMIC_MODULES - // "Load" the static plugins - #ifndef DISABLE_SCUMM - tryLoadPlugin(new StaticPlugin("scumm", Engine_SCUMM_targetList(), Engine_SCUMM_create)); - #endif - - #ifndef DISABLE_SIMON - tryLoadPlugin(new StaticPlugin("simon", Engine_SIMON_targetList(), Engine_SIMON_create)); - #endif - - #ifndef DISABLE_SKY - tryLoadPlugin(new StaticPlugin("sky", Engine_SKY_targetList(), Engine_SKY_create)); - #endif - - #ifndef DISABLE_SWORD2 - tryLoadPlugin(new StaticPlugin("sword2", Engine_SWORD2_targetList(), Engine_SWORD2_create)); - #endif - - #ifndef DISABLE_QUEEN - tryLoadPlugin(new StaticPlugin("queen", Engine_QUEEN_targetList(), Engine_QUEEN_create)); - #endif - -#else +#ifdef DYNAMIC_MODULES // Load dynamic plugins // TODO... this is right now just a nasty hack. // This should search one or multiple directories for all plugins it can @@ -313,26 +234,35 @@ void PluginManager::loadPlugins() { // Hence one more symbol should be exported by plugins which returns // the "ABI" version the plugin was built for, and we can compare that // to the ABI version of the executable. - #ifndef DISABLE_SCUMM - tryLoadPlugin(new DynamicPlugin("scumm/libscumm.so")); - #endif - - #ifndef DISABLE_SIMON - tryLoadPlugin(new DynamicPlugin("simon/libsimon.so")); - #endif - - #ifndef DISABLE_SKY - tryLoadPlugin(new DynamicPlugin("sky/libsky.so")); - #endif - - #ifndef DISABLE_SWORD2 - tryLoadPlugin(new DynamicPlugin("bs2/libbs2.so")); - #endif - - #ifndef DISABLE_QUEEN - tryLoadPlugin(new DynamicPlugin("queen/libqueen.so")); - #endif - + #define LOAD_MODULE(name, NAME) + tryLoadPlugin(new DynamicPlugin("scumm/lib" name ".so")); +#else + // "Loader" for the static plugins + #define LOAD_MODULE(name, NAME) \ + tryLoadPlugin(new StaticPlugin(name, Engine_##NAME##_gameList(), Engine_##NAME##_create, Engine_##NAME##_detectGames)); +#endif + + // Load all plugins. + // Right now the list is hardcoded. On the long run, of course it should + // automatically be determined. +#ifndef DISABLE_SCUMM + LOAD_MODULE("scumm", SCUMM); +#endif + +#ifndef DISABLE_SIMON + LOAD_MODULE("simon", SIMON); +#endif + +#ifndef DISABLE_SKY + LOAD_MODULE("sky", SKY); +#endif + +#ifndef DISABLE_SWORD2 + LOAD_MODULE("sword2", SWORD2); +#endif + +#ifndef DISABLE_QUEEN + LOAD_MODULE("queen", QUEEN); #endif } diff --git a/base/plugins.h b/base/plugins.h index eb380ec3a6..32946774e6 100644 --- a/base/plugins.h +++ b/base/plugins.h @@ -68,13 +68,14 @@ public: * @todo on Windows, we might need __declspec(dllexport) ? */ #ifndef DYNAMIC_MODULES -#define REGISTER_PLUGIN(name,targetListFactory,engineFactory) +#define REGISTER_PLUGIN(name,gameListFactory,engineFactory,detectGames) #else -#define REGISTER_PLUGIN(name,targetListFactory,engineFactory) \ +#define REGISTER_PLUGIN(name,gameListFactory,engineFactory,detectGames) \ extern "C" { \ const char *PLUGIN_name() { return name; } \ - const GameSettings *PLUGIN_getTargetList() { return targetListFactory(); } \ + GameList PLUGIN_getSupportedGames() { return gameListFactory(); } \ Engine *PLUGIN_createEngine(GameDetector *detector, OSystem *syst) { return engineFactory(detector, syst); } \ + GameList PLUGIN_detectGames(const FSList &fslist) { return detectGames(fslist); } } #endif @@ -107,4 +108,38 @@ public: const PluginList &getPlugins() { return _plugins; } }; + +#ifndef DYNAMIC_MODULES + +#define DECLARE_PLUGIN(name) \ + extern GameList Engine_##name##_gameList(); \ + extern Engine *Engine_##name##_create(GameDetector *detector, OSystem *syst); \ + extern GameList Engine_##name##_detectGames(const FSList &fslist); + +// Factory functions => no need to include the specific classes +// in this header. This serves two purposes: +// 1) Clean seperation from the game modules (scumm, simon) and the generic code +// 2) Faster (compiler doesn't have to parse lengthy header files) +#ifndef DISABLE_SCUMM +DECLARE_PLUGIN(SCUMM) +#endif + +#ifndef DISABLE_SIMON +DECLARE_PLUGIN(SIMON) +#endif + +#ifndef DISABLE_SKY +DECLARE_PLUGIN(SKY) +#endif + +#ifndef DISABLE_SWORD2 +DECLARE_PLUGIN(SWORD2) +#endif + +#ifndef DISABLE_QUEEN +DECLARE_PLUGIN(QUEEN) +#endif + +#endif + #endif diff --git a/queen/queen.cpp b/queen/queen.cpp index 65ad09c926..18ef1a6bd4 100644 --- a/queen/queen.cpp +++ b/queen/queen.cpp @@ -20,17 +20,17 @@ */ #include "stdafx.h" -#include "queen/queen.h" -#include "queen/cutaway.h" -#include "queen/talk.h" -#include "queen/walk.h" -#include "queen/graphics.h" -#include "common/config-manager.h" -#include "common/file.h" +#include "backends/fs/fs.h" #include "base/gameDetector.h" #include "base/plugins.h" +#include "common/config-manager.h" +#include "common/file.h" +#include "queen/cutaway.h" #include "queen/display.h" #include "queen/graphics.h" +#include "queen/queen.h" +#include "queen/talk.h" +#include "queen/walk.h" extern uint16 _debugLevel; @@ -47,15 +47,36 @@ static const GameSettings queen_settings[] = { { NULL, NULL, 0, 0, MDT_NONE, 0, NULL} }; -const GameSettings *Engine_QUEEN_targetList() { - return queen_settings; +GameList Engine_QUEEN_gameList() { + const GameSettings *g = queen_settings; + GameList games; + while (g->gameName) + games.push_back(*g++); + return games; +} + +GameList Engine_QUEEN_detectGames(const FSList &fslist) { + GameList detectedGames; + const GameSettings *g = &queen_settings[0]; + + // Iterate over all files in the given directory + for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *gameName = file->displayName().c_str(); + + if (0 == scumm_stricmp(g->detectname, gameName)) { + // Match found, add to list of candidates, then abort inner loop. + detectedGames.push_back(*g); + break; + } + } + return detectedGames; } Engine *Engine_QUEEN_create(GameDetector *detector, OSystem *syst) { return new Queen::QueenEngine(detector, syst); } -REGISTER_PLUGIN("Flight of the Amazon Queen", Engine_QUEEN_targetList, Engine_QUEEN_create); +REGISTER_PLUGIN("Flight of the Amazon Queen", Engine_QUEEN_gameList, Engine_QUEEN_create, Engine_QUEEN_detectGames); namespace Queen { diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp index e647512b35..86de4be748 100644 --- a/scumm/scummvm.cpp +++ b/scumm/scummvm.cpp @@ -22,6 +22,8 @@ #include "stdafx.h" +#include "backends/fs/fs.h" + #include "base/gameDetector.h" #include "base/plugins.h" @@ -2639,8 +2641,56 @@ const char *tag2str(uint32 tag) { using namespace Scumm; -const GameSettings *Engine_SCUMM_targetList() { - return scumm_settings; +GameList Engine_SCUMM_gameList() { + const GameSettings *g = scumm_settings; + GameList games; + while (g->gameName) + games.push_back(*g++); + return games; +} + +GameList Engine_SCUMM_detectGames(const FSList &fslist) { + GameList detectedGames; + const GameSettings *g; + char detectName[128]; + char detectName2[128]; + char detectName3[128]; + + for (g = scumm_settings; g->gameName; ++g) { + // Determine the 'detectname' for this game, that is, the name of a + // file that *must* be presented if the directory contains the data + // for this game. For example, FOA requires atlantis.000 + if (g->detectname) { + strcpy(detectName, g->detectname); + strcpy(detectName2, g->detectname); + strcat(detectName2, "."); + detectName3[0] = '\0'; + } else { + strcpy(detectName, g->gameName); + strcpy(detectName2, g->gameName); + strcpy(detectName3, g->gameName); + strcat(detectName, ".000"); + if (g->version >= 7) { + strcat(detectName2, ".la0"); + } else + strcat(detectName2, ".sm0"); + strcat(detectName3, ".he0"); + } + + // Iterate over all files in the given directory + for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *gameName = file->displayName().c_str(); + + if ((0 == scumm_stricmp(detectName, gameName)) || + (0 == scumm_stricmp(detectName2, gameName)) || + (0 == scumm_stricmp(detectName3, gameName))) { + // Match found, add to list of candidates, then abort inner loop. + detectedGames.push_back(*g); + break; + } + } + } + return detectedGames; } Engine *Engine_SCUMM_create(GameDetector *detector, OSystem *syst) { @@ -2698,4 +2748,4 @@ Engine *Engine_SCUMM_create(GameDetector *detector, OSystem *syst) { return engine; } -REGISTER_PLUGIN("Scumm Engine", Engine_SCUMM_targetList, Engine_SCUMM_create); +REGISTER_PLUGIN("Scumm Engine", Engine_SCUMM_gameList, Engine_SCUMM_create, Engine_SCUMM_detectGames); diff --git a/simon/simon.cpp b/simon/simon.cpp index 75c07fee7c..09e9a2eb56 100644 --- a/simon/simon.cpp +++ b/simon/simon.cpp @@ -21,6 +21,8 @@ #include "stdafx.h" +#include "backends/fs/fs.h" + #include "base/gameDetector.h" #include "base/plugins.h" @@ -62,15 +64,45 @@ static const GameSettings simon_settings[] = { {NULL, NULL, 0, 0, MDT_NONE, 0, NULL} }; -const GameSettings *Engine_SIMON_targetList() { - return simon_settings; +GameList Engine_SIMON_gameList() { + const GameSettings *g = simon_settings; + GameList games; + while (g->gameName) + games.push_back(*g++); + return games; +} + +GameList Engine_SIMON_detectGames(const FSList &fslist) { + GameList detectedGames; + const GameSettings *g; + char detectName[128]; + char detectName2[128]; + + for (g = simon_settings; g->gameName; ++g) { + strcpy(detectName, g->detectname); + strcpy(detectName2, g->detectname); + strcat(detectName2, "."); + + // Iterate over all files in the given directory + for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *gameName = file->displayName().c_str(); + + if ((0 == scumm_stricmp(detectName, gameName)) || + (0 == scumm_stricmp(detectName2, gameName))) { + // Match found, add to list of candidates, then abort inner loop. + detectedGames.push_back(*g); + break; + } + } + } + return detectedGames; } Engine *Engine_SIMON_create(GameDetector *detector, OSystem *syst) { return new Simon::SimonEngine(detector, syst); } -REGISTER_PLUGIN("Simon the Sorcerer", Engine_SIMON_targetList, Engine_SIMON_create); +REGISTER_PLUGIN("Simon the Sorcerer", Engine_SIMON_gameList, Engine_SIMON_create, Engine_SIMON_detectGames); namespace Simon { diff --git a/sky/sky.cpp b/sky/sky.cpp index 2ba3848461..ddec59eaa0 100644 --- a/sky/sky.cpp +++ b/sky/sky.cpp @@ -21,6 +21,8 @@ #include "stdafx.h" +#include "backends/fs/fs.h" + #include "base/gameDetector.h" #include "base/plugins.h" @@ -82,15 +84,36 @@ static const GameSettings sky_settings[] = { {NULL, NULL, 0, 0, MDT_NONE, 0, NULL} }; -const GameSettings *Engine_SKY_targetList() { - return sky_settings; +GameList Engine_SKY_gameList() { + const GameSettings *g = sky_settings; + GameList games; + while (g->gameName) + games.push_back(*g++); + return games; +} + +GameList Engine_SKY_detectGames(const FSList &fslist) { + GameList detectedGames; + const GameSettings *g = &sky_settings[0]; + + // Iterate over all files in the given directory + for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *gameName = file->displayName().c_str(); + + if (0 == scumm_stricmp(g->detectname, gameName)) { + // Match found, add to list of candidates, then abort inner loop. + detectedGames.push_back(*g); + break; + } + } + return detectedGames; } Engine *Engine_SKY_create(GameDetector *detector, OSystem *syst) { return new SkyEngine(detector, syst); } -REGISTER_PLUGIN("Beneath a Steel Sky", Engine_SKY_targetList, Engine_SKY_create); +REGISTER_PLUGIN("Beneath a Steel Sky", Engine_SKY_gameList, Engine_SKY_create, Engine_SKY_detectGames); void **SkyEngine::_itemList[300]; diff --git a/sword2/sword2.cpp b/sword2/sword2.cpp index 06de398c66..e43633467e 100644 --- a/sword2/sword2.cpp +++ b/sword2/sword2.cpp @@ -18,6 +18,7 @@ */ #include "stdafx.h" +#include "backends/fs/fs.h" #include "base/gameDetector.h" #include "base/plugins.h" #include "common/config-manager.h" @@ -56,15 +57,45 @@ static const GameSettings sword2_settings[] = { {NULL, NULL, 0, 0, MDT_NONE, 0, NULL} }; -const GameSettings *Engine_SWORD2_targetList() { - return sword2_settings; +GameList Engine_SWORD2_gameList() { + const GameSettings *g = sword2_settings; + GameList games; + while (g->gameName) + games.push_back(*g++); + return games; +} + +GameList Engine_SWORD2_detectGames(const FSList &fslist) { + GameList detectedGames; + const GameSettings *g; + char detectName[128]; + char detectName2[128]; + + for (g = sword2_settings; g->gameName; ++g) { + strcpy(detectName, g->detectname); + strcpy(detectName2, g->detectname); + strcat(detectName2, "."); + + // Iterate over all files in the given directory + for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) { + const char *gameName = file->displayName().c_str(); + + if ((0 == scumm_stricmp(detectName, gameName)) || + (0 == scumm_stricmp(detectName2, gameName))) { + // Match found, add to list of candidates, then abort inner loop. + detectedGames.push_back(*g); + break; + } + } + } + return detectedGames; } Engine *Engine_SWORD2_create(GameDetector *detector, OSystem *syst) { return new Sword2::Sword2Engine(detector, syst); } -REGISTER_PLUGIN("Broken Sword II", Engine_SWORD2_targetList, Engine_SWORD2_create); +REGISTER_PLUGIN("Broken Sword II", Engine_SWORD2_gameList, Engine_SWORD2_create, Engine_SWORD2_detectGames); namespace Sword2 { |