Difference between revisions of "Auto detection"

Jump to navigation Jump to search
8,870 bytes added ,  21:05, 8 April 2006
m (Changed section levels)
 
(6 intermediate revisions by the same user not shown)
Line 54: Line 54:


In addition, of course the filename itself carries valuable information. One can narrow down the SCUMM version, and in the case of newer games, also may deduce the gameid from the filename. And sometimes even the platform and/or language. We currently do not take full advantage of this.
In addition, of course the filename itself carries valuable information. One can narrow down the SCUMM version, and in the case of newer games, also may deduce the gameid from the filename. And sometimes even the platform and/or language. We currently do not take full advantage of this.
=== Building blocks ===
The core for the revised create/detect scheme would be a function <code>detectGames</code> that takes a path, and optionally a set of hints (like gameid, platform, language. (Note: I am not yet sure whether those 'hints' will be actually useful, so maybe we can do w/o them).
It returns a set of potential games. The set entries will contain: A ScummGameSettings record, a SubstResFileNames record (or equivalent, as I plan to modify the file name subsitution scheme, see below), an MD5 (computed, may be misssing), and the name/path of the 'detecfile' (the file that was used to identify that game, and to which the MD5 checksum belongs).
This function can then both be used by the regular detector, as well as the 'create' function. The latter would in fact become quite simple:
# Call <code>detectGames</code> to obtain <code>gameList</code>
# Remove all entries from <code>gameList</code> which do not match the user specified gameid
# (Not sure if this step is good/bad/necessary) Remove entries for which the platform does not match (UNK would act like a joker here)
# (Not sure if this step is good/bad/necessary) Remove entries for which the language does not match (UNK would act like a joker here)
# If the size of <code>gameList</code> does not equal (i.e. no unique match was found), abort with an error
# Finally, create a suitable Engine instance
Note: I am not yet sure how to handle target_md5 here. Maybe we don't need it anymore, maybe it could be passed as a hint to <code> detectGames </code>.
=== File name handling (revising the SubstResFileNames system) ===
The current file name substitution system, built around SubstResFileNames, tries to solve multiple goals at once: (TODO: Give a list here). This makes some things more complicated than necessary. Also, it can't do all that one would like to be able to do... for example, when used during detection, it should be possible to deduce language/platform information from those filenames (useful for the detector).
Also, there are some efficency issues: If we search through the full list of file name subsitutions for each game, we essentially arrive at a quadratical run time.
Taking a closer look at <code>substResFileNameTable</code>, one quickly notices that almost all entries in there really map a gameid to either a full fixed file name (usually for mac versions), or to a "pattern" filename (think of  GAME.LA0, GAME.LA1, GAME.LA2 etc.). The exception to this is the code to detect MM/Zak variants for NES and C64. If we add dedicated code for the latter, the table finally is reduced to what I just described: A map from gameids to file name "patterns".
Now, take a look at <code>ScummEngine::openRoom</code>. It actually also encodes a lot of knowledge about SCUMM filenames. This is duplicated knowledge. Instead of first putting effort into generating a "good" filename, and then putting more effort into trying to substitute that file name, and doing that over and over again -- wouldn't it be much better to check once which kinds of filenames are needed, and then always generate the right names immediately? In particular, the 'create' function already has to determine the file substitution required for that game... why throw that away?
Hence the idea is born to unify the knowledge / data found in <code>ScummEngine::openRoom</code> and <code>substResFileNameTable</code> into a single mechanism. This is why I wrote above that <code>detectGames</code> should return a SubstResFileNames (or equivalent recorde). We already pass that to the ScummEngine object. We simply extend this to allow to be used directly by <code>ScummEngine::openRoom</code> (and of course other methods) to generate suitable filenames from given data.
How to achieve this? I am not yet fully sure how to do this best... We probably need (at least) the following three parts:
# A way to determine what file naming scheme to be used (for the detector; i.e. a way to loop over all possible detect names for a given game)
# A way to encode the naming scheme (i.e. <code>substResFileNameTable</code> or a successor)
# A function that generates filenames from the <code>substResFileNameTable</code>, given some data (like room & disk number)
The first part should be good enough to also allow the detector to extract useful extra information about the game. E.g. if the filename is 00.man, we know that it's Maniac Mansion Demo; if it's toffzeit.he0, then we are dealing with the German putttime, etc.
Parts 2 and 3 go hand in hand. Unfortunately, we can't just use a prinft format string, since in some cases, the file names may need to encode the room number, in others the disk number, and in some cases even letters instead of numbers are used (for HE 98+ games, "(a)" and "(b)" are used as file name extensions, at least)
This is still a bit fuzzy. To decide how to proceed, it might help to write down a list of all possible file names, or even a map between filenames <-> gameid, but since that's a lot of work and may just as well be *not* useful at all, I am not doing this for now... :-)
TODO: Finish this
=== Incomplete code snippets ===
The following snippets are sketches. We may end up doing things totally different. It's just a way for me to make visible what goes on in my head right now, and is neither complete nor necessarily the best way to handle things. You have been warned :-)
Random thought: The detector could automatically populate the 'basename' field, too.
In particular, the first use of generateSubstResFileName in Sound::openSfxFile
is used to translate the "basename" of the game; this would be unnecessary if
the basename was already set to the right value.
For regular use (e.g. in ScummEngine::openRoom, and most places where
generateSubstResFileName is currently being used), we could use a new function like this one:
<pre>
Common::String generateFilename(int room, int diskNumber) {
char buf[128];
if (_game.version == 4) {
if (room == 0 || room >= 900) {
sprintf(buf, "%.3d.lfl", room);
} else {
sprintf(buf, "disk%.2d.lec", diskNumber);
}
} else if (_game.heversion >= 98) {
char c;
int disk = 0;
if (_heV7DiskOffsets)
disk = _heV7DiskOffsets[room];
switch(disk) {
case 2:
c = 'b';
break;
case 1:
c = 'a';
break;
default:
c = '0';
}
sprintf(buf, _substEntry.formatStr, c);
} else if (_substEntry.method == kGenDiskNum) {
sprintf(buf, _substEntry.formatStr, diskNumber);
} else if (_substEntry.method == kGenRoomNum) {
sprintf(buf, _substEntry.formatStr, room);
} else {
error("FOO");
}
return buf;
}
</pre>
For detection: We should touch every file at most once (in particular, it would be very bad to compute the MD5 of a file multiple times, since many of our targets aren't exactly fast when it comes to disk I/O speed). So instead of looping over all games, let's loop over the files and then split down into cases. At the same time, squeeze any information we can from the filenames and files.
<pre>
fullCandidateList = ()
FOR filename in files DO
bool filenameKnown = false;
IF length of filename < 4 THEN
NEXT
ENDIF
tempList = ()
IF (filename contains '.' and is at most 8+1+3=12 chars long) THEN
filenameKnown = true;
SWITCH filename {
case 00.MAN
add to tempList:
gameid = Maniac Mansion, platform = ?, language = en, extra = demo
subst pattern = "%02d.MAN", kGenWithRoomNum
case *.sm0
add to tempList:
gameid = Sam & Max, ...
case 00.LFL
look at the file to distinguish between V1, V2/V3OldBundle and V3SH
Then add all possible game variants to tempList
...
case 000.LFL
...
case *.000
...
case *.la0
...
case *.he0
...
case *.d64 // Non-extracted C64
add to tempList:
gameid = Maniac Mansion, platform = C64
OR
gameid = Zak, platform = C64
OR
error
...
default:
filenameKnown = false;
ENDSWITCH
ELSE
// Must be a mac name / long name
IF filename = "Maniac Mansion (*).prg" THEN
add to tempList:
gameid = Maniac Mansion, platform = NES, language = *
ELIF name is in mac container list THEN
...
ELSE
search the generic subst list
...
TODO
...
ENDIF
ENDIF
if filenameKnown then
compute MD5 of the file (we only do this for known filenames to avoid
computing the MD5 of every single file in the directory!)
IF MD5 is found in the table THEN
optionally: perform a sanity check, show if the exact match
  agrees with at least one of our guesses
add this exact match to fullCandidateList
ELSE
add tempList to fullCandidateList
ENDIF
ENDIF
ENDFOR
</pre>


== Standardized descriptions ==
== Standardized descriptions ==
Line 59: Line 229:
   (NAME, PLATFORM, LANGUAGE, EXTRA)
   (NAME, PLATFORM, LANGUAGE, EXTRA)


The game desc then is:
The game desc then is one of the following (which one to use in the end isn't the point of this text!):
   NAME (PLATFORM EXTRA LANGUAGE)
   NAME (PLATFORM EXTRA LANGUAGE)
  NAME (LANGUAGE PLATFORM EXTRA)
  NAME (EXTRA PLATFORM LANGUAGE)
  ...
I'll stick with the first version for now, but it's not set in stone (yet).


Missing/unknown information is left our. So, if none of the extra values are known, the description simply becomes:
Missing/unknown information is left our. So, if none of the extra values are known, the description simply becomes:
1,079

edits

Navigation menu