Difference between revisions of "HOWTO-Engines"

Jump to navigation Jump to search
2,094 bytes added ,  15:08, 25 October 2018
m
Text replacement - "<source lang=" to "<syntaxhighlight lang="
m (Text replacement - "<source lang=" to "<syntaxhighlight lang=")
(27 intermediate revisions by 11 users not shown)
Line 2: Line 2:
This page is meant as a mini-HOWTO which roughly outlines the steps needed to add a new engine to ScummVM. It does '''not''' tell you how to create an engine for a given game; rather it is meant to tell a developer how to properly "hook" into ScummVM.  
This page is meant as a mini-HOWTO which roughly outlines the steps needed to add a new engine to ScummVM. It does '''not''' tell you how to create an engine for a given game; rather it is meant to tell a developer how to properly "hook" into ScummVM.  


I will assume that you are at least roughly familiar with ScummVM, and have a fresh checkout of our Subversion repository. Note that it's strongly adviced to base your work on the current development version of ScummVM, and not on a release version. This will ease integration of your work.
I will assume that you are at least roughly familiar with ScummVM, and have a recent checkout of our source code repository. Note that it's strongly advised to base your work on the current development version of ScummVM, and not on a release version. This will ease integration of your work.


== Overview ==
== Overview ==
Line 15: Line 15:


# Add a new directory <tt>engines/quux/</tt>
# Add a new directory <tt>engines/quux/</tt>
# Add <tt>engines/quux/module.mk</tt> (take a look at module.mk files of 2-3 existing engines to understand the content).
# Add <tt>engines/quux/configure.engine</tt> (looking at configure.engine files of existing engines should make it clear what you have to do).
# Add <tt>engines/quux/module.mk</tt> (Again, just check out what is done for the existing engines).
# Add <tt>engines/quux/quux.h</tt> and <tt>engines/quux/quux.cpp</tt>; this will contain your Engine subclass (or at least parts of it).
# Add <tt>engines/quux/quux.h</tt> and <tt>engines/quux/quux.cpp</tt>; this will contain your Engine subclass (or at least parts of it).
# Add <tt>engines/quux/detection.cpp</tt>; It will contain the plugin interface code (more on that in the next section).
# Add <tt>engines/quux/detection.cpp</tt>; It will contain the plugin interface code (more on that in the next section).
# Modify <tt>engines/engines.mk</tt> by adding your engine. It should be clear what to do by looking at what is done for the other engines there.
# Modify <tt>configure</tt> by adding a new add_engine line. Again, just check out what is done for the existing engines.
# Modify <tt>base/plugins.cpp</tt>; in particular, you have to add your engine to the list in PluginManager::loadPlugins.


That's it. The difficult part is of course writing the Engine subclass. More on that in the next section!
That's it. The difficult part is of course writing the Engine subclass. More on that in the next section!
Line 49: Line 47:
|inter.cpp, logic.cpp, script.cpp || Game logic, resp. script/bytecode interpreter
|inter.cpp, logic.cpp, script.cpp || Game logic, resp. script/bytecode interpreter
|}
|}
Additionally, the files saved by each engine should be consistent.
* '''Saves''': These should be named <targetid>.### (where ### is the slot id) or <gameid>.###. The latter should be used when the saves can be shared across all game variants.
* '''Other files''': These should be named <targetid>-<filename> or <gameid>-<filename>. Again the latter when the files can be shared acress all variants of the game (an example for these type of files would be when a minigame saves a high score record).
Here, only use the <gameid> scheme if you are '''absolutely''' sure that such files can be shared across '''all''' (that is every game platform, every game language, every game patch version, every game release, etc.) versions. If you are not sure whether this is the case, then stick to the <targetid> based scheme.


=== Subclassing MetaEngine ===
=== Subclassing MetaEngine ===
Let's implement the plugin interface: You'll have to create a custom MetaEngine subclass which provides the information and functionality related to the engine that can be used without running any game. That includes detecting games, listing savegames and instancing the engine. You have to specify your MetaEngine class to the REGISTER_PLUGIN_* macros. (See the example below)
Let's implement the plugin interface:<br>
You'll have to create a custom MetaEngine subclass. This provides the information and functionality related to the engine that can be used by the launcher without loading and running the game engine, which includes detecting games, listing savegames and instancing the engine.


You can alternatively subclass AdvancedMetaEngine from <tt>common/advancedDetector.h</tt> to reuse some common functionality like MD5 based game detection.
The following example illustrates this, '''but''':<br> It is recommended that most engines should instead subclass AdvancedMetaEngine.<br>
This can be found in <tt>engines/advancedDetector.*</tt> and provides a standard framework for filename and MD5 based game detection. To use this, all you will have to provide is a standard data table of ADGameDescription entries describing each game variant, which is usually placed in a separate detection_tables.h header.<br>
 
Finally, in either case, you will then have to specify your MetaEngine class to the REGISTER_PLUGIN_* macros.


=== Subclassing Engine ===
=== Subclassing Engine ===
Line 63: Line 73:


=== Infrastructure services ===
=== Infrastructure services ===
Header file common/scummsys.h provides services needed by virtually any source file:
Header file <code>common/scummsys.h</code> provides services needed by virtually any source file:


* defines platform endianness
* defines platform endianness
Line 75: Line 85:
* provides a lean environment to build win32 executables/libraries
* provides a lean environment to build win32 executables/libraries


TODO: give descriptions for other commonly used header files.
The <code>common</code> directory contains many more useful things, e.g. various container classes (for lists, hashmaps, resizeable arrays etc.), code for dealing with transparent endianess handling, for file I/O, etc. We recommend that you browse this a bit to get an idea of what is there. Likewise you should familiarize yourself with <code>graphics</code> and <code>sound</code>; for example we already have decoders for quite some audio formats in there. Before you roll your own code for all sorts of basic things, have a look and see if we already have code for that, and maybe also ask some veterans for advice.


=== Common portability issues ===
=== Common portability issues ===
Line 83: Line 93:
   min() -> MIN()
   min() -> MIN()
   rand() -> use Common::RandomSource class
   rand() -> use Common::RandomSource class
   stricmp() -> scumm_stricmp()
   strcasecmp() / stricmp() -> scumm_stricmp()
   strnicmp() -> scumm_strnicmp()
   strncasecmp() / strnicmp() -> scumm_strnicmp()
   strrev() -> scumm_strrev()
   strrev() -> scumm_strrev()


Line 105: Line 115:


=== Example: engines/quux/quux.h ===
=== Example: engines/quux/quux.h ===
<syntax type="C++">
<syntaxhighlight lang="cpp">
#ifndef QUUX_H
#ifndef QUUX_H
#define QUUX_H
#define QUUX_H
   
   
#include "common/random.h"
#include "engines/engine.h"
#include "engines/engine.h"
#include "gui/debugger.h"
#include "gui/debugger.h"
Line 116: Line 127:
class Console;
class Console;
   
   
// our engine debug levels
// our engine debug channels
enum {
enum {
kQuuxDebugExample = 1 << 0,
kQuuxDebugExample = 1 << 0,
kQuuxDebugExample2 = 1 << 1
kQuuxDebugExample2 = 1 << 1
// next new level must be 1 << 2 (4)
// next new channel must be 1 << 2 (4)
// the current limitation is 32 debug levels (1 << 31 is the last one)
// the current limitation is 32 debug channels (1 << 31 is the last one)
};
};
   
   
Line 135: Line 146:
   
   
// We need random numbers
// We need random numbers
Common::RandomSource _rnd;
Common::RandomSource *_rnd;
};
};
   
   
Line 148: Line 159:
   
   
#endif
#endif
</syntax>
</syntaxhighlight>


=== Example: engines/quux/quux.cpp ===
=== Example: engines/quux/quux.cpp ===
<syntax type="C++">
<syntaxhighlight lang="cpp">
#include "common/scummsys.h"
#include "common/scummsys.h"
   
   
#include "common/config-manager.h"
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/debug.h"
#include "common/EventRecorder.h"
#include "common/debug-channels.h"
#include "common/error.h"
#include "gui/EventRecorder.h"
#include "common/file.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/fs.h"
   
   
#include "engines/util.h"
#include "quux/quux.h"
#include "quux/quux.h"
   
   
Line 165: Line 180:
   
   
QuuxEngine::QuuxEngine(OSystem *syst)  
QuuxEngine::QuuxEngine(OSystem *syst)  
  : Engine(syst) {
  : Engine(syst), _console(nullptr) {
// Put your engine in a sane state, but do nothing big yet;
// Put your engine in a sane state, but do nothing big yet;
// in particular, do not load data from files; rather, if you
// in particular, do not load data from files; rather, if you
// need to do such things, do them from init().
// need to do such things, do them from run().
   
   
// Do not initialize graphics here
// Do not initialize graphics here
// Do not initialize audio devices here
   
   
// However this is the place to specify all default directories
// However this is the place to specify all default directories
SearchMan.addSubDirectoryMatching(_gameDataDir, "sound");
const Common::FSNode gameDataDir(ConfMan.get("path"));
SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
   
   
// Here is the right place to set up the engine specific debug levels
// Here is the right place to set up the engine specific debug channels
Common::addDebugChannel(kQuuxDebugExample, "example", "this is just an example for a engine specific debug level");
DebugMan.addDebugChannel(kQuuxDebugExample, "example", "this is just an example for a engine specific debug channel");
Common::addDebugChannel(kQuuxDebugExample2, "example2", "also an example");
DebugMan.addDebugChannel(kQuuxDebugExample2, "example2", "also an example");
   
   
// Don't forget to register your random source
// Don't forget to register your random source
g_eventRec.registerRandomSource(_rnd, "quux");
_rnd = new Common::RandomSource("quux");
   
   
printf("QuuxEngine::QuuxEngine\n");
debug("QuuxEngine::QuuxEngine");
}
}
   
   
QuuxEngine::~QuuxEngine() {
QuuxEngine::~QuuxEngine() {
debug("QuuxEngine::~QuuxEngine");
// Dispose your resources here
// Dispose your resources here
printf("QuuxEngine::~QuuxEngine\n");
delete _rnd;
   
   
// Remove all of our debug levels here
// Remove all of our debug levels here
Common::clearAllDebugChannels();
DebugMan.clearAllDebugChannels();
}
}
   
   
Line 216: Line 235:
   
   
// Additional setup.
// Additional setup.
printf("QuuxEngine::init\n");
debug("QuuxEngine::init");
 
// Your main even loop should be (invoked from) here.
// Your main even loop should be (invoked from) here.
printf("QuuxEngine::go: Hello, World!\n");
debug("QuuxEngine::go: Hello, World!");
   
   
// This test will show up if -d1 and --debugflags=example are specified on the commandline
// This test will show up if -d1 and --debugflags=example are specified on the commandline
Line 231: Line 250:
   
   
} // End of namespace Quux
} // End of namespace Quux
</syntax>
</syntaxhighlight>


=== Example: engines/quux/detection.cpp ===
=== Example: engines/quux/detection.cpp ===
The following example implements a custom MetaEngine instead of using the AdvancedMetaEngine.
The following example implements a custom MetaEngine instead of using the AdvancedMetaEngine.
<syntax type="C++">
<syntaxhighlight lang="cpp">
#include "quux/quux.h"
#include "quux/quux.h"
   
   
Line 307: Line 326:
Common::FSNode dir(ConfMan.get("path"));
Common::FSNode dir(ConfMan.get("path"));
if (!dir.getChildren(fslist, Common::FSNode::kListAll)) {
if (!dir.getChildren(fslist, Common::FSNode::kListAll)) {
return Common::kInvalidPathError;
return Common::kNoGameDataFoundError;
}
}
   
   
Line 332: Line 351:
REGISTER_PLUGIN_STATIC(QUUX, PLUGIN_TYPE_ENGINE, QuuxMetaEngine);
REGISTER_PLUGIN_STATIC(QUUX, PLUGIN_TYPE_ENGINE, QuuxMetaEngine);
#endif
#endif
</syntax>
</syntaxhighlight>


=== Example: engines/quux/module.mk ===
=== Example: engines/quux/module.mk ===
<syntax type="make">
<syntaxhighlight lang="make">
MODULE := engines/quux
MODULE := engines/quux
   
   
Line 352: Line 371:
# Include common rules  
# Include common rules  
include $(srcdir)/rules.mk
include $(srcdir)/rules.mk
</syntax>
</syntaxhighlight>
 
=== Example: engines/quux/configure.engine ===
<syntaxhighlight lang="bash">
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
add_engine quux "Quux" no
</syntaxhighlight>
TrustedUser
2,147

edits

Navigation menu