factored out the game detection code into the Plugin class; this is the first step towards allowing more powerful, plugin specific detection code; also, moved the Plugin GameSettings APIs to a slightly higher level

svn-id: r10858
This commit is contained in:
Max Horn 2003-10-17 12:18:58 +00:00
parent 79e681282e
commit 116dbee1fc
6 changed files with 123 additions and 123 deletions

View file

@ -240,41 +240,39 @@ void GameDetector::list_games() {
// 2) List all available (configured) targets, including those with custom // 2) List all available (configured) targets, including those with custom
// names, e.g. "monkey-mac", "skycd-demo", ... // names, e.g. "monkey-mac", "skycd-demo", ...
const PluginList &plugins = PluginManager::instance().getPlugins(); const PluginList &plugins = PluginManager::instance().getPlugins();
const GameSettings *v;
printf("Game Full Title \n" printf("Game Full Title \n"
"---------------- ------------------------------------------------------\n"); "---------------- ------------------------------------------------------\n");
PluginList::ConstIterator iter = plugins.begin(); PluginList::ConstIterator iter = plugins.begin();
for (iter = plugins.begin(); iter != plugins.end(); ++iter) { for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
v = (*iter)->getSupportedGames(); GameList list = (*iter)->getSupportedGames();
while (v->gameName && v->description) { for (GameList::Iterator v = list.begin(); v != list.end(); ++v) {
#if 1 #if 1
printf("%-17s%-56s\n", v->gameName, v->description); printf("%-17s%-56s\n", v->gameName, v->description);
#else #else
const char *config = (g_config->has_domain(v->gameName)) ? "Yes" : ""; const char *config = (g_config->has_domain(v->gameName)) ? "Yes" : "";
printf("%-17s%-56s%s\n", v->gameName, v->description, config); printf("%-17s%-56s%s\n", v->gameName, v->description, config);
#endif #endif
v++;
} }
} }
} }
const GameSettings *GameDetector::findGame(const String &gameName, const Plugin **plugin) const { GameSettings GameDetector::findGame(const String &gameName, const Plugin **plugin) {
// Find the GameSettings for this target // Find the GameSettings for this target
const GameSettings *target;
const PluginList &plugins = PluginManager::instance().getPlugins(); const PluginList &plugins = PluginManager::instance().getPlugins();
GameSettings result = {NULL, NULL, 0, 0, MDT_NONE, 0, NULL};
PluginList::ConstIterator iter = plugins.begin(); PluginList::ConstIterator iter = plugins.begin();
for (iter = plugins.begin(); iter != plugins.end(); ++iter) { for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
target = (*iter)->findGame(gameName.c_str()); result = (*iter)->findGame(gameName.c_str());
if (target) { if (result.gameName) {
if (plugin) if (plugin)
*plugin = *iter; *plugin = *iter;
return target; break;
} }
} }
return 0; return result;
} }
void GameDetector::parseCommandLine(int argc, char **argv) { void GameDetector::parseCommandLine(int argc, char **argv) {
@ -454,7 +452,7 @@ void GameDetector::parseCommandLine(int argc, char **argv) {
// To verify this, check if there is either a game domain (i.e // To verify this, check if there is either a game domain (i.e
// a configured target) matching this argument, or if we can // a configured target) matching this argument, or if we can
// find any target with that name. // find any target with that name.
if (i == (argc - 1) && (ConfMan.hasGameDomain(s) || findGame(s))) { if (i == (argc - 1) && (ConfMan.hasGameDomain(s) || findGame(s).gameName)) {
setTarget(s); setTarget(s);
} else { } else {
if (current_option == NULL) if (current_option == NULL)
@ -543,7 +541,6 @@ int GameDetector::parseMusicDriver(const String &str) {
} }
bool GameDetector::detectGame() { bool GameDetector::detectGame() {
const GameSettings *target;
String realGame; String realGame;
if (ConfMan.hasKey("gameid")) if (ConfMan.hasKey("gameid"))
@ -552,10 +549,9 @@ bool GameDetector::detectGame() {
realGame = _targetName; realGame = _targetName;
printf("Looking for %s\n", realGame.c_str()); printf("Looking for %s\n", realGame.c_str());
target = findGame(realGame, &_plugin); _game = findGame(realGame, &_plugin);
if (target) { if (_game.gameName) {
_game = *target;
printf("Trying to start game '%s'\n", _game.description); printf("Trying to start game '%s'\n", _game.description);
return true; return true;
} else { } else {

View file

@ -23,6 +23,7 @@
#ifndef GAMEDETECTOR_H #ifndef GAMEDETECTOR_H
#define GAMEDETECTOR_H #define GAMEDETECTOR_H
#include "base/plugins.h"
#include "common/str.h" #include "common/str.h"
class Engine; class Engine;
@ -117,7 +118,7 @@ public:
static Language parseLanguage(const String &s); static Language parseLanguage(const String &s);
static Platform parsePlatform(const String &s); static Platform parsePlatform(const String &s);
const GameSettings *findGame(const String &gameName, const Plugin **plugin = NULL) const; static GameSettings findGame(const String &gameName, const Plugin **plugin = NULL);
protected: protected:
bool detectGame(void); bool detectGame(void);

View file

@ -20,12 +20,13 @@
* *
*/ */
#include "backends/fs/fs.h"
#include "base/gameDetector.h" #include "base/gameDetector.h"
#include "base/plugins.h" #include "base/plugins.h"
#include "base/engine.h" #include "base/engine.h"
#include "common/util.h" #include "common/util.h"
/** Type of factory functions which make new Engine objects. */
typedef Engine *(*EngineFactory)(GameDetector *detector, OSystem *syst); typedef Engine *(*EngineFactory)(GameDetector *detector, OSystem *syst);
@ -74,47 +75,95 @@ extern Engine *Engine_QUEEN_create(GameDetector *detector, OSystem *syst);
#pragma mark - #pragma mark -
int Plugin::countSupportedGames() const { GameSettings Plugin::findGame(const char *gameName) const {
const GameSettings *target = getSupportedGames(); // Find the GameSettings for this game
int count;
for (count = 0; target->gameName; target++, count++)
;
return count;
}
const GameSettings *Plugin::findGame(const char *gameName) const {
// Find the GameSettings for this target
const GameSettings *target = getSupportedGames();
assert(gameName); assert(gameName);
while (target->gameName) { GameList games = getSupportedGames();
if (!scumm_stricmp(target->gameName, gameName)) { GameSettings result = {NULL, NULL, 0, 0, MDT_NONE, 0, NULL};
return target; for (GameList::Iterator g = games.begin(); g != games.end(); ++g) {
if (!scumm_stricmp(g->gameName, gameName)) {
result = *g;
break;
} }
target++;
} }
return 0; return result;
} }
/**
* 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;
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;
}
};
#pragma mark - #pragma mark -
class StaticPlugin : public Plugin { class StaticPlugin : public GameSettingsPlugin {
const char *_name; const char *_name;
const GameSettings *_targets;
int _targetCount;
EngineFactory _ef; EngineFactory _ef;
public: public:
StaticPlugin(const char *name, const GameSettings *targets, EngineFactory ef) StaticPlugin(const char *name, const GameSettings *games, EngineFactory ef)
: _name(name), _targets(targets), _ef(ef) { : GameSettingsPlugin(games), _name(name), _ef(ef) {
_targetCount = Plugin::countSupportedGames();
} }
const char *getName() const { return _name; } const char *getName() const { return _name; }
int countSupportedGames() const { return _targetCount; }
const GameSettings *getSupportedGames() const { return _targets; }
Engine *createInstance(GameDetector *detector, OSystem *syst) const { Engine *createInstance(GameDetector *detector, OSystem *syst) const {
return (*_ef)(detector, syst); return (*_ef)(detector, syst);
} }
@ -126,26 +175,21 @@ public:
#ifdef DYNAMIC_MODULES #ifdef DYNAMIC_MODULES
class DynamicPlugin : public Plugin { class DynamicPlugin : public GameSettingsPlugin {
void *_dlHandle; void *_dlHandle;
Common::String _filename; Common::String _filename;
Common::String _name; Common::String _name;
const GameSettings *_targets;
int _targetCount;
EngineFactory _ef; EngineFactory _ef;
void *findSymbol(const char *symbol); void *findSymbol(const char *symbol);
public: public:
DynamicPlugin(const char *filename) DynamicPlugin(const char *filename)
: _dlHandle(0), _filename(filename), _targets(0), _targetCount(0), _ef(0) {} : GameSettingsPlugin(0), _dlHandle(0), _filename(filename), _ef(0) {}
const char *getName() const { return _name.c_str(); } const char *getName() const { return _name.c_str(); }
int countSupportedGames() const { return _targetCount; }
const GameSettings *getSupportedGames() const { return _targets; }
Engine *createInstance(GameDetector *detector, OSystem *syst) const { Engine *createInstance(GameDetector *detector, OSystem *syst) const {
assert(_ef); assert(_ef);
return (*_ef)(detector, syst); return (*_ef)(detector, syst);
@ -199,7 +243,7 @@ bool DynamicPlugin::loadPlugin() {
unloadPlugin(); unloadPlugin();
return false; return false;
} }
_targets = targetListFunc(); _games = targetListFunc();
// Finally, retrieve the factory function // Finally, retrieve the factory function
_ef = (EngineFactory)findSymbol("PLUGIN_createEngine"); _ef = (EngineFactory)findSymbol("PLUGIN_createEngine");

View file

@ -27,16 +27,19 @@
#include "common/singleton.h" #include "common/singleton.h"
class Engine; class Engine;
class FSList;
class GameDetector; class GameDetector;
class OSystem; class OSystem;
struct GameSettings; struct GameSettings;
/** List of GameSettings- */
typedef Common::List<GameSettings> GameList;
/** /**
* Abstract base class for the plugin system. * Abstract base class for the plugin system.
* Subclasses for this can be used to wrap both static and dynamic * Subclasses for this can be used to wrap both static and dynamic
* plugins. * plugins.
*/ */
//typedef Common::List<GameSettings> GameList;
class Plugin { class Plugin {
public: public:
virtual ~Plugin() {} virtual ~Plugin() {}
@ -47,10 +50,9 @@ public:
virtual const char *getName() const = 0; virtual const char *getName() const = 0;
virtual int getVersion() const { return 0; } // TODO! virtual int getVersion() const { return 0; } // TODO!
virtual int countSupportedGames() const; virtual GameList getSupportedGames() const = 0;
virtual const GameSettings *getSupportedGames() const = 0; virtual GameSettings findGame(const char *gameName) const;
virtual const GameSettings *findGame(const char *gameName) const; virtual GameList detectGames(const FSList &fslist) const = 0;
//virtual GameList detectGames(const FSList &fslist) const;
virtual Engine *createInstance(GameDetector *detector, OSystem *syst) const = 0; virtual Engine *createInstance(GameDetector *detector, OSystem *syst) const = 0;
}; };

View file

@ -50,8 +50,6 @@ enum {
kQuitCmd = 'QUIT' kQuitCmd = 'QUIT'
}; };
typedef Common::List<const GameSettings *> GameList;
/* /*
* A dialog that allows the user to edit a config game entry. * A dialog that allows the user to edit a config game entry.
* TODO: add widgets for some/all of the following * TODO: add widgets for some/all of the following
@ -80,7 +78,7 @@ class EditGameDialog : public Dialog {
typedef Common::String String; typedef Common::String String;
typedef Common::StringList StringList; typedef Common::StringList StringList;
public: public:
EditGameDialog(NewGui *gui, const String &domain, const GameSettings *target); EditGameDialog(NewGui *gui, const String &domain, GameSettings target);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
@ -92,19 +90,19 @@ protected:
CheckboxWidget *_amigaCheckbox; CheckboxWidget *_amigaCheckbox;
}; };
EditGameDialog::EditGameDialog(NewGui *gui, const String &domain, const GameSettings *target) EditGameDialog::EditGameDialog(NewGui *gui, const String &domain, GameSettings target)
: Dialog(gui, 8, 50, 320 - 2 * 8, 200 - 2 * 40), : Dialog(gui, 8, 50, 320 - 2 * 8, 200 - 2 * 40),
_domain(domain) { _domain(domain) {
// Determine the description string // Determine the description string
String description(ConfMan.get("description", domain)); String description(ConfMan.get("description", domain));
if (description.isEmpty() && target) { if (description.isEmpty() && target.description) {
description = target->description; description = target.description;
} }
// Determine whether this is a SCUMM game // Determine whether this is a SCUMM game
// FIXME: This check is evil, as it requires us to hard code GIDs. // FIXME: This check is evil, as it requires us to hard code GIDs.
bool isScumm = target && (GID_SCUMM_FIRST <= target->id && target->id <= GID_SCUMM_LAST); bool isScumm = (GID_SCUMM_FIRST <= target.id && target.id <= GID_SCUMM_LAST);
// Label & edit widget for the game ID // Label & edit widget for the game ID
@ -247,9 +245,9 @@ void LauncherDialog::updateListing() {
if (name.isEmpty()) if (name.isEmpty())
name = iter->_key; name = iter->_key;
if (description.isEmpty()) { if (description.isEmpty()) {
const GameSettings *v = _detector.findGame(name); GameSettings g = _detector.findGame(name);
if (v && v->description) if (g.description)
description = v->description; description = g.description;
} }
if (!name.isEmpty() && !description.isEmpty()) { if (!name.isEmpty() && !description.isEmpty()) {
@ -270,61 +268,20 @@ void LauncherDialog::updateListing() {
/* /*
* Return a list of all games which might be the game in the specified directory. * Return a list of all games which might be the game in the specified directory.
*/ */
GameList findGame(FilesystemNode *dir) { GameList detectGames(FilesystemNode *dir) {
GameList list; GameList detectedGames;
FSList *files = dir->listDir(FilesystemNode::kListFilesOnly); FSList *files = dir->listDir(FilesystemNode::kListFilesOnly);
const int size = files->size();
char detectName[128];
char detectName2[128];
char detectName3[128];
// Iterate over all known games and for each check if it might be // Iterate over all known games and for each check if it might be
// the game in the presented directory. // the game in the presented directory.
const PluginList &plugins = PluginManager::instance().getPlugins(); const PluginList &plugins = PluginManager::instance().getPlugins();
int p; PluginList::ConstIterator iter = plugins.begin();
for (p = 0; p < plugins.size(); p++) { for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
const GameSettings *v = plugins[p]->getSupportedGames(); detectedGames.push_back((*iter)->detectGames(*files));
while (v->gameName && v->description) {
// 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 (v->detectname) {
strcpy(detectName, v->detectname);
strcpy(detectName2, v->detectname);
strcat(detectName2, ".");
detectName3[0] = '\0';
} else {
strcpy(detectName, v->gameName);
strcpy(detectName2, v->gameName);
strcpy(detectName3, v->gameName);
strcat(detectName, ".000");
if (v->version >= 7) {
strcat(detectName2, ".la0");
} else
strcat(detectName2, ".sm0");
strcat(detectName3, ".he0");
}
// Iterate over all files in the given directory
for (int i = 0; i < size; i++) {
const char *gameName = (*files)[i].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.
list.push_back(v);
break;
}
}
v++;
}
} }
return list; return detectedGames;
} }
void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
@ -349,8 +306,8 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
// ...so let's determine a list of candidates, games that // ...so let's determine a list of candidates, games that
// could be contained in the specified directory. // could be contained in the specified directory.
GameList candidates = findGame(dir); GameList candidates = detectGames(dir);
const GameSettings *v = 0; GameSettings result = {NULL, NULL, 0, 0, MDT_NONE, 0, NULL};
if (candidates.isEmpty()) { if (candidates.isEmpty()) {
// No game was found in the specified directory // No game was found in the specified directory
@ -358,25 +315,25 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
alert.runModal(); alert.runModal();
} else if (candidates.size() == 1) { } else if (candidates.size() == 1) {
// Exact match // Exact match
v = candidates[0]; result = candidates[0];
} else { } else {
// Display the candidates to the user and let her/him pick one // Display the candidates to the user and let her/him pick one
StringList list; StringList list;
int i; int i;
for (i = 0; i < candidates.size(); i++) for (i = 0; i < candidates.size(); i++)
list.push_back(candidates[i]->description); list.push_back(candidates[i].description);
ChooserDialog dialog(_gui, "Pick the game:", list); ChooserDialog dialog(_gui, "Pick the game:", list);
i = dialog.runModal(); i = dialog.runModal();
if (0 <= i && i < candidates.size()) if (0 <= i && i < candidates.size())
v = candidates[i]; result = candidates[i];
} }
if (v != 0) { if (result.gameName != 0) {
// The auto detector or the user made a choice. // The auto detector or the user made a choice.
// Pick a domain name which does not yet exist (after all, we // Pick a domain name which does not yet exist (after all, we
// are *adding* a game to the config, not replacing). // are *adding* a game to the config, not replacing).
String domain(v->gameName); String domain(result.gameName);
if (ConfMan.hasGameDomain(domain)) { if (ConfMan.hasGameDomain(domain)) {
char suffix = 'a'; char suffix = 'a';
domain += suffix; domain += suffix;
@ -385,13 +342,13 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
suffix++; suffix++;
domain += suffix; domain += suffix;
} }
ConfMan.set("gameid", v->gameName, domain); ConfMan.set("gameid", result.gameName, domain);
ConfMan.set("description", v->description, domain); ConfMan.set("description", result.description, domain);
} }
ConfMan.set("path", dir->path(), domain); ConfMan.set("path", dir->path(), domain);
// Display edit dialog for the new entry // Display edit dialog for the new entry
EditGameDialog editDialog(_gui, domain, v); EditGameDialog editDialog(_gui, domain, result);
if (editDialog.runModal()) { if (editDialog.runModal()) {
// User pressed OK, so make changes permanent // User pressed OK, so make changes permanent

View file

@ -21,7 +21,7 @@
#ifndef LAUNCHER_DIALOG_H #ifndef LAUNCHER_DIALOG_H
#define LAUNCHER_DIALOG_H #define LAUNCHER_DIALOG_H
#include "dialog.h" #include "gui/dialog.h"
#include "common/str.h" #include "common/str.h"
#include "common/list.h" #include "common/list.h"