1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef ENGINES_METAENGINE_H
24 #define ENGINES_METAENGINE_H
25 
26 #include "common/achievements.h"
27 #include "common/scummsys.h"
28 #include "common/error.h"
29 #include "common/array.h"
30 
31 #include "engines/game.h"
32 #include "engines/savestate.h"
33 
34 #include "base/plugins.h"
35 
36 class Engine;
37 class OSystem;
38 
39 namespace Common {
40 class Keymap;
41 class FSList;
42 class OutSaveFile;
43 class String;
44 
45 typedef SeekableReadStream InSaveFile;
46 }
47 
48 namespace Graphics {
49 struct Surface;
50 }
51 
52 namespace GUI {
53 class GuiObject;
54 class OptionsContainerWidget;
55 }
56 
57 /**
58  * @defgroup engines_metaengine Meta engine
59  * @ingroup engines
60  *
61  * @brief API for managing various functions of the meta engine.
62  *
63  * @{
64  */
65 
66 /**
67  * Per-game extra GUI options structure.
68  * Currently, this can only be used for options with checkboxes.
69  */
70 struct ExtraGuiOption {
71 	const char *label;         /*!< Option label, e.g. "Fullscreen mode". */
72 	const char *tooltip;       /*!< Option tooltip shown when the mouse cursor hovers over it. */
73 	const char *configOption;  /*!< confMan key, e.g. "fullscreen". */
74 	bool defaultState;         /*!< Default state of the checkbox (checked or not). */
75 };
76 
77 /**
78  * debug channels structure
79  */
80 struct DebugChannelDef {
81 	uint32 channel;				/*!< enum value, channel id, e.g. kDebugGlobalDetection */
82 	const char *name;			/*!< name of debug channel, e.g. "detection" */
83 	const char *description;	/*!< description of debug channel, e.g. "track scripts" */
84 };
85 
86 /**
87  * delimiter of the array of DebugChannelDef
88  */
89 #define DEBUG_CHANNEL_END {0, NULL, NULL}
90 
91 /**
92  * Array of ExtraGuiOption structures.
93  */
94 typedef Common::Array<ExtraGuiOption> ExtraGuiOptions;
95 
96 /**
97  * @todo Doc required
98  */
99 enum { kSavegameFilePattern = -99 };
100 
101 #define EXTENDED_SAVE_VERSION 4
102 
103 /**
104  * Structure describing a savegame file.
105  */
106 struct ExtendedSavegameHeader {
107 	char id[6];                   /*!< ID of the savegame file. */
108 	uint8 version;                /*!< Version of the savegame header. */
109 	Common::String saveName;      /*!< Name of the savegame. */
110 	Common::String description;   /*!< Description of the savegame, as entered by the user. */
111 	uint32 date;                  /*!< Date of the savegame. */
112 	uint16 time;                  /*!< Time of the savegame. */
113 	uint32 playtime;              /*!< Total play time until this savegame. */
114 	Graphics::Surface *thumbnail; /*!< Screen content shown as a thumbnail for this savegame. */
115 	bool isAutosave;              /*!< Whether this savegame is an autosave. */
116 
ExtendedSavegameHeaderExtendedSavegameHeader117 	ExtendedSavegameHeader() {
118 		memset(id, 0, 6);
119 		version = 0;
120 		date = 0;
121 		time = 0;
122 		playtime = 0;
123 		thumbnail = nullptr;
124 		isAutosave = false;
125 	}
126 };
127 
128 /**
129  * A meta engine factory for Engine instances with the
130  * added ability of listing and detecting supported games.
131  *
132  * Every engine "plugin" provides a hook to get an instance of a MetaEngineDetection
133  * subclass for that "engine plugin". For example, SCUMM provides ScummMetaEngineDetection.
134  * This is then in turn used by the frontend code to detect games, and other useful functionality.
135  *
136  * To instantiate actual Engine objects, see the class @ref MetaEngine.
137  */
138 class MetaEngineDetection : public PluginObject {
139 public:
~MetaEngineDetection()140 	virtual ~MetaEngineDetection() {}
141 
142 	/** Get the engine ID. */
143 	virtual const char *getEngineId() const = 0;
144 
145 	/** Return some copyright information about the original engine. */
146 	virtual const char *getOriginalCopyright() const = 0;
147 
148 	/** Return a list of games supported by this engine. */
149 	virtual PlainGameList getSupportedGames() const = 0;
150 
151 	/** Query the engine for a PlainGameDescriptor for the specified gameid, if any. */
152 	virtual PlainGameDescriptor findGame(const char *gameId) const = 0;
153 
154 	/**
155 	 * Run the engine's game detector on the given list of files, and return a
156 	 * (possibly empty) list of games supported by the engine that were
157 	 * found among the given files.
158 	 */
159 	virtual DetectedGames detectGames(const Common::FSList &fslist) const = 0;
160 
161 	/**
162 	 * Return a list of extra GUI options for the specified target.
163 	 *
164 	 * If no target is specified, all of the available custom GUI options are
165 	 * returned for the plugin (used to set default values).
166 	 *
167 	 * Currently, this only supports options with checkboxes.
168 	 *
169 	 * The default implementation returns an empty list.
170 	 *
171 	 * @param target  Name of a config manager target.
172 	 *
173 	 * @return A list of extra GUI options for an engine plugin and target.
174 	 */
getExtraGuiOptions(const Common::String & target)175 	virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const {
176 		return ExtraGuiOptions();
177 	}
178 
179 	/**
180 	 * Return a list of engine specified debug channels
181 	 *
182 	 * If engine has no specified debug channels or not supported yet, then it will return NULL
183 	 *
184 	 * @return A list of engine specified debug channels
185 	 */
getDebugChannels()186 	virtual const DebugChannelDef *getDebugChannels() const {
187 		return NULL;
188 	}
189 
190 	/**
191 	 * Register the default values for the settings that the engine uses into the
192 	 * configuration manager.
193 	 *
194 	 * @param target  Name of a config manager target.
195 	 */
196 	virtual void registerDefaultSettings(const Common::String &target) const;
197 
198 	/**
199 	 * Return a GUI widget container for configuring the specified target options.
200 	 *
201 	 * The returned widget is shown in the Engine tab in the Edit Game dialog.
202 	 * Engines can build custom option dialogs, but by default a simple widget
203 	 * allowing to configure the extra GUI options is used.
204 	 *
205 	 * Engines that are not supposed to have an Engine tab in the Edit Game dialog
206 	 * can return nullptr.
207 	 *
208 	 * @param boss     The widget or dialog that the returned widget is a child of.
209 	 * @param name     The name that the returned widget must use.
210 	 * @param target   Name of a config manager target.
211 	 */
212 	virtual GUI::OptionsContainerWidget *buildEngineOptionsWidgetStatic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const;
213 };
214 
215 /**
216  * A MetaEngine is another factory for Engine instances, and is very similar to MetaEngineDetection.
217  *
218  * This class, however, is made of of bridged functionalities that can be used to connect
219  * an actual Engine with a MetaEngine. Every engine "plugin" provides a hook to get an instance
220  * of the MetaEngine subclass for that "engine plugin.". For example, SCUMM provides a ScummMetaEngine.
221  * This is then in turn used for things like instantiating engine objects, listing savefiles,
222  * querying save metadata, etc.
223  *
224  * Since engine plugins can use external runtime libraries, these can live and build inside
225  * the engine, while a MetaEngine will always build into the executable to be able to detect code.
226  */
227 class MetaEngine : public PluginObject {
228 protected:
229 	/**
230 	 * Convert the current screen contents to a thumbnail. Can be overriden by individual
231 	 * engine meta engines to provide their own thumb, such as hiding any on-screen save
232 	 * dialog so that it won't appear in the thumbnail.
233 	 */
234 	virtual void getSavegameThumbnail(Graphics::Surface &thumb);
235 
236 	/**
237 	 * Finds the first empty save slot that can be used for this target
238 	 * @param target Name of a config manager target.
239 	 *
240 	 * @return The first empty save slot, or -1 if all are occupied.
241 	 */
242 	int findEmptySaveSlot(const char *target);
243 
244 public:
~MetaEngine()245 	virtual ~MetaEngine() {}
246 
247 	/**
248 	 * Name of the engine plugin.
249 	 *
250 	 * Classes inheriting a MetaEngine must provide an engineID here,
251 	 * which can then be used to match an Engine with MetaEngine.
252 	 *
253 	 * For example, ScummMetaEngineDetection inherits MetaEngineDetection and provides a
254 	 * engineID of "scumm". ScummMetaEngine inherits MetaEngine and provides the name
255 	 * "Scumm". This way, an Engine can be easily matched with a MetaEngine.
256 	 */
257 	virtual const char *getName() const = 0;
258 
259 	/**
260 	 * Instantiate an engine instance based on the settings of
261 	 * the currently active ConfMan target.
262 	 *
263 	 * The MetaEngine queries the ConfMan singleton for data like the target,
264 	 * gameid, path etc.
265 	 *
266 	 * @param syst    Pointer to the global OSystem object.
267 	 * @param engine  Pointer to a pointer that the MetaEngine sets to
268 	 *                the newly created Engine, or 0 in case of an error.
269 	 *
270 	 * @return A Common::Error describing the error that occurred, or kNoError.
271 	 */
272 	virtual Common::Error createInstance(OSystem *syst, Engine **engine) const = 0;
273 
274 	/**
275 	 * Return a list of all save states associated with the given target.
276 	 *
277 	 * The returned list is guaranteed to be sorted by slot numbers. That
278 	 * means smaller slot numbers are always stored before bigger slot numbers.
279 	 *
280 	 * The caller must ensure that this (Meta)Engine is responsible
281 	 * for the specified target. This is done by using findGame on it respectively
282 	 * on the associated gameid from the relevant ConfMan entry, if present.
283 	 *
284 	 * The default implementation returns an empty list.
285 	 *
286 	 * @note MetaEngines must indicate that this function has been implemented
287 	 *       via the kSupportsListSaves feature flag.
288 	 *
289 	 * @param target  Name of a config manager target.
290 	 *
291 	 * @return A list of save state descriptors.
292 	 */
293 	virtual SaveStateList listSaves(const char *target) const;
294 
295 	/**
296 	 * Return a list of all save states associated with the given target.
297 	 *
298 	 * This is a wrapper around the basic listSaves virtual method, but it has
299 	 * some extra logic for autosave handling.
300 	 *
301 	 * @param target    Name of a config manager target.
302 	 * @param saveMode  If true, get the list for a save dialog.
303 	 * @return A list of save state descriptors.
304 	 */
305 	SaveStateList listSaves(const char *target, bool saveMode) const;
306 
307 	/**
308 	 * Return the slot number that is used for autosaves, or -1 for engines that
309 	 * don't support autosave.
310 	 *
311 	 * @note This should match the engine getAutosaveSlot() method.
312 	 */
getAutosaveSlot()313 	virtual int getAutosaveSlot() const {
314 		return 0;
315 	}
316 
317 	/**
318 	 * Return the maximum number of save slots that the engine supports.
319 	 *
320 	 * @note MetaEngines must indicate that this function has been implemented
321 	 *       via the kSupportsListSaves feature flag.
322 	 *
323 	 * The default implementation limits the save slots to zero (0).
324 	 *
325 	 * @return Maximum save slot number supported.
326 	 */
getMaximumSaveSlot()327 	virtual int getMaximumSaveSlot() const {
328 		// For games using the new save format, assume 99 slots by default
329 		return hasFeature(kSavesUseExtendedFormat) ? 99 : 0;
330 	}
331 
332 	/**
333 	 * Remove the specified save state.
334 	 *
335 	 * For most engines, this just means calling _saveFileMan->removeSaveFile().
336 	 * Engines that keep an index file will also update it accordingly.
337 	 *
338 	 * @note MetaEngines must indicate that this function has been implemented
339 	 *       via the kSupportsDeleteSave feature flag.
340 	 *
341 	 * @param target  Name of a config manager target.
342 	 * @param slot    Slot number of the save state to be removed.
343 	 */
344 	virtual void removeSaveState(const char *target, int slot) const;
345 
346 	/**
347 	 * Return meta information from the specified save state.
348 	 *
349 	 * Depending on the MetaEngineFeatures set, this can include
350 	 * thumbnails, save date and time, play time.
351 	 *
352 	 * @param target  Name of a config manager target.
353 	 * @param slot    Slot number of the save state.
354 	 */
355 	virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
356 
357 	/**
358 	 * Return the name of the save file for the given slot and optional target,
359 	 * or a pattern for matching filenames against.
360 	 *
361 	 * @param saveGameIdx  Index of the save, or kSavegameFilePattern
362 	 *                     for returning a filename pattern.
363 	 * @param target       Game target. If omitted, then the engine ID is used.
364 	 */
365 	virtual Common::String getSavegameFile(int saveGameIdx, const char *target = nullptr) const;
366 
367 	/**
368 	 * Return the pattern for save files.
369 	 *
370 	 * @param target  Game target. If omitted, then the engine ID is used.
371 	 */
372 	Common::String getSavegameFilePattern(const char *target = nullptr) const {
373 		return getSavegameFile(kSavegameFilePattern, target);
374 	}
375 
376 	/**
377 	 * Return the keymap used by the target.
378 	 */
379 	virtual Common::Array<Common::Keymap *> initKeymaps(const char *target) const;
380 
381 	/**
382 	 * Return a GUI widget container for configuring the specified target options.
383 	 *
384 	 * Engines can build custom option dialogs from here.
385 	 *
386 	 * Engines that don't have an Engine tab in the Edit Game dialog, or that use
387 	 * ExtraGuiOptions in MetaEngineDetection can return nullptr.
388 	 *
389 	 * @param boss    The widget or dialog that the returned widget is a child of.
390 	 * @param name    The name that the returned widget must use.
391 	 * @param target  Name of a config manager target.
392 	 */
buildEngineOptionsWidgetDynamic(GUI::GuiObject * boss,const Common::String & name,const Common::String & target)393 	virtual GUI::OptionsContainerWidget *buildEngineOptionsWidgetDynamic(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const {
394 		return nullptr;
395 	}
396 
397 	/**
398 	 * MetaEngine feature flags.
399 	 *
400 	 * A feature in this context means an ability of the engine that can be
401 	 * either available or not.
402 	 */
403 	enum MetaEngineFeature {
404 		/**
405 		 * List all save states for a given target that is supported.
406 		 *
407 		 * For the target to be supported, the listSaves() and
408 		 * getMaximumSaveSlot methods must be implemented.
409 		 * Used for --list-saves support, as well as the GMM load dialog.
410 		 */
411 		kSupportsListSaves,
412 
413 		/**
414 		 * Load from the launcher or command line (-x).
415 		 */
416 		kSupportsLoadingDuringStartup,
417 
418 		/**
419 		 * Delete saves from the launcher.
420 		 *
421 		 * This means that the engine implements the removeSaveState() method.
422 		 */
423 		kSupportsDeleteSave,
424 
425 		/**
426 		 * Feature meta information for save states.
427 		 *
428 		 * This means that the engine implements the querySaveMetaInfos method properly.
429 		 *
430 		 * Engines implementing meta information always must provide
431 		 * the following entries in the save state descriptor queried
432 		 * by querySaveMetaInfos:
433 		 * - is_deletable - indicates whether a given save is
434 		 *                  safe for deletion
435 		 * - is_write_protected - indicates whether a given save
436 		 *                        can be overwritten by the user.
437 		 *                        You do not need to set this, default value is 'false'.
438 		 */
439 		kSavesSupportMetaInfo,
440 
441 		/**
442 		 * Feature a thumbnail in savegames.
443 		 *
444 		 * This means that the engine includes a thumbnail in save states
445 		 * returned via querySaveMetaInfo.
446 		 * This flag can only be set when kSavesSupportMetaInfo is set.
447 		 */
448 		kSavesSupportThumbnail,
449 
450 		/**
451 		 * Feature @c save_date and @c save_time entries in the
452 		 * save state returned by querySaveMetaInfo.
453 		 *
454 		 * These values indicate the date and time when the savegame was created.
455 		 * This flag can only be set when kSavesSupportMetaInfo is set.
456 		 */
457 		kSavesSupportCreationDate,
458 
459 		/**
460 		 * Feature @c play_time entry in the save state returned by
461 		 * querySaveMetaInfo.
462 		 *
463 		 * This indicates how long the user played the game until the save.
464 		 * This flag can only be set when kSavesSupportMetaInfo is set.
465 		 */
466 		kSavesSupportPlayTime,
467 
468 		/**
469 		* This feature is available if the engine's saves can be detected
470 		* with:
471 		* @code
472 		* <target>.###
473 		* @endcode
474 		* where ### corresponds to slot number.
475 		*
476 		* If that is not true, or if the engine uses some unusual way
477 		* of detecting saves and slot numbers, this should be
478 		* unavailable. In that case Save/Load dialog for the engine's
479 		* games is locked during cloud saves sync.
480 		*
481 		* NOTE: This flag is used by cloud code, but also in
482 		* MetaEngine::getSavegameFile(), for common save names.
483 		*/
484 		kSimpleSavesNames,
485 
486 		/**
487 		 * Use the default implementation of save header and thumbnail
488 		 * appended to the save.
489 		 *
490 		 * This flag requires the following flags to be set:
491 		 * - kSavesSupportMetaInfo
492 		 * - kSavesSupportThumbnail
493 		 * - kSavesSupportCreationDate
494 		 * - kSavesSupportPlayTime
495 		 */
496 		kSavesUseExtendedFormat
497 	};
498 
499 	/**
500 	 * Return a list of achievement descriptions for the specified target.
501 	 *
502 	 * @param target  Name of a config manager target.
503 	 *
504 	 * @return A list of achievement descriptions for an engine plugin and target.
505 	 */
506 	virtual const Common::AchievementsInfo getAchievementsInfo(const Common::String &target) const;
507 
508 	/**
509 	 * Return the achievement descriptions.
510 	 *
511 	 * @note The default implementation returns @c nullptr
512 	 *
513 	 * @return a list of achievement descriptions for an engine.
514 	 */
getAchievementDescriptionList()515 	virtual const Common::AchievementDescriptionList* getAchievementDescriptionList() const {
516 		return nullptr;
517 	}
518 
519 	/**
520 	 * Determine whether the engine supports the specified MetaEngine feature.
521 	 *
522 	 * Used by e.g. the launcher to determine whether to enable the Load button.
523 	 */
524 	virtual bool hasFeature(MetaEngineFeature f) const;
525 
526 	/**
527 	 * Write the extended savegame header to the given savegame file.
528 	 */
529 	void appendExtendedSave(Common::OutSaveFile *saveFile, uint32 playtime, Common::String desc, bool isAutosave);
530 
531 	/**
532 	 * Write the extended savegame header to the given WriteStream.
533 	 */
534 	void appendExtendedSaveToStream(Common::WriteStream *saveFile, uint32 playtime, Common::String desc, bool isAutosave, uint32 offset = 0);
535 
536 	/**
537 	 * Copies an existing save file to the first empty slot which is not autosave
538 	 * @param target Name of a config manager target.
539 	 * @param slot   Slot number of the save state.
540 	 *
541 	 * @return true if an empty slot was found and the save state was copied. false otherwise.
542 	 */
543 	bool copySaveFileToFreeSlot(const char *target, int slot);
544 
545 	/**
546 	 * Parse the extended savegame header to retrieve the SaveStateDescriptor information.
547 	 */
548 	static void parseSavegameHeader(ExtendedSavegameHeader *header, SaveStateDescriptor *desc);
549 	/**
550 	 * Populate the given extended savegame header with dummy values.
551 	 *
552 	 * This is used when failing to read the header from a savegame file.
553 	 */
554 	static void fillDummyHeader(ExtendedSavegameHeader *header);
555 	/**
556 	 * Read the extended savegame header from the given savegame file.
557 	 */
558 	static WARN_UNUSED_RESULT bool readSavegameHeader(Common::InSaveFile *in, ExtendedSavegameHeader *header, bool skipThumbnail = true);
559 };
560 
561 /**
562  * Singleton class that manages all engine plugins.
563  */
564 class EngineManager : public Common::Singleton<EngineManager> {
565 public:
566 	/**
567 	 * Given a list of FSNodes in a given directory, detect a set of games contained within.
568 	 *
569 	 * Returns an empty list if none are found.
570 	 */
571 	DetectionResults detectGames(const Common::FSList &fslist) const;
572 
573 	/** Find a plugin by its engine ID. */
574 	const Plugin *findPlugin(const Common::String &engineId) const;
575 
576 	/**
577 	 * Get the list of all plugins for the type specified.
578 	 *
579 	 * By default, it will get METAENGINES, for now.
580 	 * If usage of actual engines never occurs, the default arguments can be skipped,
581 	 * and always have it return PLUGIN_TYPE_ENGINE_DETECTION.
582 	 */
583 	const PluginList &getPlugins(const PluginType fetchPluginType = PLUGIN_TYPE_ENGINE_DETECTION) const;
584 
585 	/** Find a target. */
586 	QualifiedGameDescriptor findTarget(const Common::String &target, const Plugin **plugin = NULL) const;
587 
588 	/**
589 	 * List games matching the specified criteria.
590 	 *
591 	 * If the engine ID is not specified, this scans all the plugins,
592 	 * loading them from the disk if necessary. This is a slow operation on
593 	 * some platforms and should not be used for the happy path.
594 	 */
595 	QualifiedGameList findGamesMatching(const Common::String &engineId, const Common::String &gameId) const;
596 
597 	/**
598 	 * Create a target from the supplied game descriptor.
599 	 *
600 	 * @return The created target name.
601 	 */
602 	Common::String createTargetForGame(const DetectedGame &game);
603 
604 	/** Upgrade a target to the current configuration format. */
605 	void upgradeTargetIfNecessary(const Common::String &target) const;
606 
607 private:
608 	/** Find a game across all loaded plugins. */
609 	QualifiedGameList findGameInLoadedPlugins(const Common::String &gameId) const;
610 
611 	/** Use heuristics to complete a target lacking an engine ID. */
612 	void upgradeTargetForEngineId(const Common::String &target) const;
613 };
614 
615 /** Convenience shortcut for accessing the engine manager. */
616 #define EngineMan EngineManager::instance()
617 /** @} */
618 #endif
619