aboutsummaryrefslogtreecommitdiff
path: root/engines/metaengine.h
blob: dfe882ad0aadbcd4233595e6e2eba5fb6a909639 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#ifndef ENGINES_METAENGINE_H
#define ENGINES_METAENGINE_H

#include "common/scummsys.h"
#include "common/error.h"
#include "common/array.h"

#include "engines/game.h"
#include "engines/savestate.h"

#include "base/plugins.h"

class Engine;
class OSystem;

namespace Common {
class FSList;
class OutSaveFile;
class String;

typedef SeekableReadStream InSaveFile;
}

namespace Graphics {
struct Surface;
}

/**
 * Per-game extra GUI options structure.
 * Currently, this can only be used for options with checkboxes.
 */
struct ExtraGuiOption {
	const char *label;          // option label, e.g. "Fullscreen mode"
	const char *tooltip;        // option tooltip (when the mouse hovers above it)
	const char *configOption;   // confMan key, e.g. "fullscreen"
	bool defaultState;          // the detault state of the checkbox (checked or not)
};

typedef Common::Array<ExtraGuiOption> ExtraGuiOptions;

#define EXTENDED_SAVE_VERSION 3

struct ExtendedSavegameHeader {
	char id[6];
	uint8 version;
	Common::String saveName;
	Common::String description;
	uint32 date;
	uint16 time;
	uint32 playtime;
	Graphics::Surface *thumbnail;

	ExtendedSavegameHeader() {
		memset(id, 0, 6);
		version = 0;
		date = 0;
		time = 0;
		playtime = 0;
		thumbnail = nullptr;
	}
};

/**
 * A meta engine is essentially a factory for Engine instances with the
 * added ability of listing and detecting supported games.
 * Every engine "plugin" provides a hook to get an instance of a MetaEngine
 * subclass for that "engine plugin". E.g. SCUMM povides ScummMetaEngine.
 * This is then in turn used by the frontend code to detect games,
 * and instantiate actual Engine objects.
 */
class MetaEngine : public PluginObject {
public:
	virtual ~MetaEngine() {}

	/** Get the engine ID */
	virtual const char *getEngineId() const = 0;

	/** Returns some copyright information about the original engine. */
	virtual const char *getOriginalCopyright() const = 0;

	/** Returns a list of games supported by this engine. */
	virtual PlainGameList getSupportedGames() const = 0;

	/** Query the engine for a PlainGameDescriptor for the specified gameid, if any. */
	virtual PlainGameDescriptor findGame(const char *gameId) const = 0;

	/**
	 * Runs the engine's game detector on the given list of files, and returns a
	 * (possibly empty) list of games supported by the engine which it was able
	 * to detect amongst the given files.
	 */
	virtual DetectedGames detectGames(const Common::FSList &fslist) const = 0;

	/**
	 * Tries to instantiate an engine instance based on the settings of
	 * the currently active ConfMan target. That is, the MetaEngine should
	 * query the ConfMan singleton for the target, gameid, path etc. data.
	 *
	 * @param syst	Pointer to the global OSystem object
	 * @param engine	Pointer to a pointer which the MetaEngine sets to
	 *					the newly create Engine, or 0 in case of an error
	 * @return		a Common::Error describing the error which occurred, or kNoError
	 */
	virtual Common::Error createInstance(OSystem *syst, Engine **engine) const = 0;

	/**
	 * Return a list of all save states associated with the given target.
	 *
	 * The returned list is guaranteed to be sorted by slot numbers. That
	 * means smaller slot numbers are always stored before bigger slot numbers.
	 *
	 * The caller has to ensure that this (Meta)Engine is responsible
	 * for the specified target (by using findGame on it respectively
	 * on the associated gameid from the relevant ConfMan entry, if present).
	 *
	 * The default implementation returns an empty list.
	 *
	 * @note MetaEngines must indicate that this function has been implemented
	 *       via the kSupportsListSaves feature flag.
	 *
	 * @param target	name of a config manager target
	 * @return			a list of save state descriptors
	 */
	virtual SaveStateList listSaves(const char *target) const;

	/**
	 * Return a list of extra GUI options for the specified target.
	 * If no target is specified, all of the available custom GUI options are
	 * Returned for the plugin (used to set default values).
	 *
	 * Currently, this only supports options with checkboxes.
	 *
	 * The default implementation returns an empty list.
	 *
	 * @param target    name of a config manager target
	 * @return          a list of extra GUI options for an engine plugin and
	 *                  target
	 */
	virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const {
		return ExtraGuiOptions();
	}

	/**
	 * Return the maximum save slot that the engine supports.
	 *
	 * @note MetaEngines must indicate that this function has been implemented
	 *       via the kSupportsListSaves feature flag.
	 *
	 * The default implementation limits the save slots to zero (0).
	 *
	 * @return			maximum save slot number supported
	 */
	virtual int getMaximumSaveSlot() const {
		return 0;
	}

	/**
	 * Remove the specified save state.
	 *
	 * For most engines this just amounts to calling _saveFileMan->removeSaveFile().
	 * Engines which keep an index file will also update it accordingly.
	 *
	 * @note MetaEngines must indicate that this function has been implemented
	 *       via the kSupportsDeleteSave feature flag.
	 *
	 * @param target	name of a config manager target
	 * @param slot		slot number of the save state to be removed
	 */
	virtual void removeSaveState(const char *target, int slot) const;

	/**
	 * Returns meta infos from the specified save state.
	 *
	 * Depending on the MetaEngineFeatures set this can include
	 * thumbnails, save date / time, play time.
	 *
	 * @param target	name of a config manager target
	 * @param slot		slot number of the save state
	 */
	virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;

	/**
	 * Returns name of the save file for given slot and optional target.
	 *
	 * @param saveGameIdx	index of the save
	 * @param target		game target. If omitted, then the engine id is used
	 */
	virtual const char *getSavegameFile(int saveGameIdx, const char *target = nullptr) const;

	/**
	 * Returns pattern for save files.
	 *
	 * @param target		game target. If omitted, then the engine id is used
	 */
	virtual const char *getSavegamePattern(const char *target = nullptr) const;

	/** @name MetaEngineFeature flags */
	//@{

	/**
	 * A feature in this context means an ability of the engine which can be
	 * either available or not.
	 */
	enum MetaEngineFeature {
		/**
		 * Listing all Save States for a given target is supported, i.e.,
		 * the listSaves() and getMaximumSaveSlot methods are implemented.
		 * Used for --list-saves support, as well as the GMM load dialog.
		 */
		kSupportsListSaves,

		/**
		 * Loading from the Launcher / command line (-x)
		 */
		kSupportsLoadingDuringStartup,

		/**
		 * Deleting Saves from the Launcher (i.e. implements the
		 * removeSaveState() method)
		 */
		kSupportsDeleteSave,

		/**
		 * Features meta infos for savestates (i.e. implements the
		 * querySaveMetaInfos method properly).
		 *
		 * Engines implementing meta infos always have to provide
		 * the following entries in the save state descriptor queried
		 * by querySaveMetaInfos:
		 * - 'is_deletable', which indicates if a given save is
		 *                   safe for deletion
		 * - 'is_write_protected', which indicates if a given save
		 *                         can be overwritten by the user.
		 *                         (note: of course you do not have to
		 *                         set this, since it defaults to 'false')
		 */
		kSavesSupportMetaInfo,

		/**
		 * Features a thumbnail in savegames (i.e. includes a thumbnail
		 * in savestates returned via querySaveMetaInfo).
		 * This flag may only be set when 'kSavesSupportMetaInfo' is set.
		 */
		kSavesSupportThumbnail,

		/**
		 * Features 'save_date' and 'save_time' entries in the
		 * savestate returned by querySaveMetaInfo. Those values
		 * indicate the date/time the savegame was created.
		 * This flag may only be set when 'kSavesSupportMetaInfo' is set.
		 */
		kSavesSupportCreationDate,

		/**
		 * Features 'play_time' entry in the savestate returned by
		 * querySaveMetaInfo. It indicates how long the user played
		 * the game till the save.
		 * This flag may only be set when 'kSavesSupportMetaInfo' is set.
		 */
		kSavesSupportPlayTime,

		/**
		* Feature is available if engine's saves could be detected
		* with "<target>.###" pattern and "###" corresponds to slot
		* number.
		*
		* If that's not true or engine is using some unusual way
		* of detecting saves and slot numbers, this should be
		* unavailable. In that case Save/Load dialog for engine's
		* games is locked during cloud saves sync.
		*/
		kSimpleSavesNames,

		/**
		 * Uses default implementation of save header and thumbnail
		 * appended to the save.
		 * This flag requires the following flags to be set:
		 *   kSavesSupportMetaInfo, kSavesSupportThumbnail, kSavesSupportCreationDate,
		 *   kSavesSupportPlayTime
		 */
		kSavesUseExtendedFormat
	};

	/**
	 * Determine whether the engine supports the specified MetaEngine feature.
	 * Used by e.g. the launcher to determine whether to enable the "Load" button.
	 */
	virtual bool hasFeature(MetaEngineFeature f) const {
		return false;
	}

	static void appendExtendedSave(Common::OutSaveFile *saveFile, uint32 playtime, Common::String desc);
	static void parseSavegameHeader(ExtendedSavegameHeader *header, SaveStateDescriptor *desc);
	static void fillDummyHeader(ExtendedSavegameHeader *header);
	static WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, ExtendedSavegameHeader *header, bool skipThumbnail = true);

	//@}
};

/**
 * Singleton class which manages all Engine plugins.
 */
class EngineManager : public Common::Singleton<EngineManager> {
public:
	/**
	 * Given a list of FSNodes in a given directory, detect a set of games contained within
	 *
	 * Returns an empty list if none are found.
	 */
	DetectionResults detectGames(const Common::FSList &fslist) const;

	/** Find a plugin by its engine ID */
	const Plugin *findPlugin(const Common::String &engineId) const;

	/** Get the list of all engine plugins */
	const PluginList &getPlugins() const;

	/** Find a target */
	QualifiedGameDescriptor findTarget(const Common::String &target, const Plugin **plugin = NULL) const;

	/**
	 * List games matching the specified criteria
	 *
	 * If the engine id is not specified, this scans all the plugins,
	 * loading them from disk if necessary. This is a slow operation on
	 * some platforms and should not be used for the happy path.
	 */
	QualifiedGameList findGamesMatching(const Common::String &engineId, const Common::String &gameId) const;

	/**
	 * Create a target from the supplied game descriptor
	 *
	 * Returns the created target name.
	 */
	Common::String createTargetForGame(const DetectedGame &game);

	/** Upgrade a target to the current configuration format */
	void upgradeTargetIfNecessary(const Common::String &target) const;

private:
	/** Find a game across all loaded plugins */
	QualifiedGameList findGameInLoadedPlugins(const Common::String &gameId) const;

	/** Find a loaded plugin with the given engine ID */
	const Plugin *findLoadedPlugin(const Common::String &engineId) const;

	/** Use heuristics to complete a target lacking an engine ID */
	void upgradeTargetForEngineId(const Common::String &target) const;
};

/** Convenience shortcut for accessing the engine manager. */
#define EngineMan EngineManager::instance()

#endif