Skip to content

Commit

Permalink
Fix: assume archives are full games when inferring DATs (#1230)
Browse files Browse the repository at this point in the history
  • Loading branch information
emmercm committed Jul 22, 2024
1 parent 1443fcd commit afb6449
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 32 deletions.
70 changes: 46 additions & 24 deletions src/modules/datGameInferrer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Game from '../types/dats/game.js';
import Header from '../types/dats/logiqx/header.js';
import LogiqxDAT from '../types/dats/logiqx/logiqxDat.js';
import ROM from '../types/dats/rom.js';
import Archive from '../types/files/archives/archive.js';
import ArchiveEntry from '../types/files/archives/archiveEntry.js';
import File from '../types/files/file.js';
import Options from '../types/options.js';
Expand Down Expand Up @@ -79,31 +80,52 @@ export default class DATGameInferrer extends Module {
].join('\n'),
});

const gameNamesToRomFiles = romFiles.reduce((map, file) => {
const gameName = DATGameInferrer.getGameName(file);
const gameRomFiles = map.get(gameName) ?? [];
gameRomFiles.push(file);
map.set(gameName, gameRomFiles);
return map;
}, new Map<string, File[]>());

const games = [...gameNamesToRomFiles.entries()].map(([gameName, gameRomFiles]) => {
const roms = gameRomFiles
.map((romFile) => new ROM({
name: path.basename(romFile.getExtractedFilePath()),
size: romFile.getSize(),
crc32: romFile.getCrc32(),
md5: romFile.getMd5(),
sha1: romFile.getSha1(),
sha256: romFile.getSha256(),
}))
.filter(ArrayPoly.filterUniqueMapped((rom) => rom.getName()));
return new Game({
name: gameName,
description: gameName,
rom: roms,
// For all non-archived files, group files of the same filename without extension together
const gameNamesToRawFiles = romFiles
.filter((file) => !(file instanceof ArchiveEntry))
.reduce((map, file) => {
const gameName = DATGameInferrer.getGameName(file);
map.set(gameName, [...(map.get(gameName) ?? []), file]);
return map;
}, new Map<string, File[]>());

// For archives, assume the entire archive is one game
const archivePathsToArchiveEntries = romFiles
.filter((file) => file instanceof ArchiveEntry)
.reduce((map, file) => {
const archivePath = file.getFilePath();
map.set(archivePath, [...(map.get(archivePath) ?? []), file]);
return map;
}, new Map<string, ArchiveEntry<Archive>[]>());
const gameNamesToArchiveEntries = [...archivePathsToArchiveEntries.values()]
.map((archiveEntries) => {
const gameName = DATGameInferrer.getGameName(archiveEntries[0]);
return [gameName, archiveEntries] satisfies [string, ArchiveEntry<Archive>[]];
});
});

const games = [
...gameNamesToRawFiles.entries(),
...gameNamesToArchiveEntries,
]
.map(([gameName, gameRomFiles]) => {
const roms = gameRomFiles
.map((romFile) => new ROM({
name: path.basename(romFile.getExtractedFilePath()),
size: romFile.getSize(),
crc32: romFile.getCrc32(),
md5: romFile.getMd5(),
sha1: romFile.getSha1(),
sha256: romFile.getSha256(),
}))
.filter(ArrayPoly.filterUniqueMapped((rom) => rom.getName()));
return new Game({
name: gameName,
description: gameName,
rom: roms,
});
})
// Filter out duplicate games
.filter(ArrayPoly.filterUniqueMapped((game) => game.hashCode()));

return new LogiqxDAT(header, games);
}
Expand Down
7 changes: 4 additions & 3 deletions test/igir.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -970,8 +970,8 @@ describe('with inferred DATs', () => {
[path.join('onetwothree', 'one.rom'), 'f817a89f'],
[path.join('onetwothree', 'three.rom'), 'ff46c5d8'],
[path.join('onetwothree', 'two.rom'), '96170874'],
[path.join('speed_test_v51', 'speed_test_v51.sfc'), '8beffd94'],
[path.join('speed_test_v51', 'speed_test_v51.smc'), '9adca6cc'],
['speed_test_v51.sfc', '8beffd94'],
['speed_test_v51.smc', '9adca6cc'],
['three.rom', 'ff46c5d8'],
['two.rom', '96170874'],
['unknown.rom', '377a7727'],
Expand Down Expand Up @@ -1014,6 +1014,8 @@ describe('with inferred DATs', () => {
const result = await runIgir({
commands: ['copy', 'zip', 'test'],
input: [path.join(inputTemp, 'roms')],
// Note: need to de-conflict headered & headerless ROMs due to duplicate output paths
inputExclude: [path.join(inputTemp, 'roms', 'headerless')],
output: outputTemp,
});

Expand Down Expand Up @@ -1044,7 +1046,6 @@ describe('with inferred DATs', () => {
['onetwothree.zip|one.rom', 'f817a89f'],
['onetwothree.zip|three.rom', 'ff46c5d8'],
['onetwothree.zip|two.rom', '96170874'],
['speed_test_v51.zip|speed_test_v51.sfc', '8beffd94'],
['speed_test_v51.zip|speed_test_v51.smc', '9adca6cc'],
['three.zip|three.rom', 'ff46c5d8'],
['two.zip|two.rom', '96170874'],
Expand Down
11 changes: 7 additions & 4 deletions test/modules/candidateWriter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,16 @@ describe('zip', () => {

it('should not write anything if the output is expected and overwriting invalid', async () => {
await copyFixturesToTemp(async (inputTemp, outputTemp) => {
// Note: need to de-conflict headered & headerless ROMs due to duplicate output paths
const inputGlob = '**/!(headerless)/*';

// Given
const options = new Options({ commands: ['copy', 'zip'] });
const inputFilesBefore = await walkAndStat(inputTemp);
await expect(walkAndStat(outputTemp)).resolves.toHaveLength(0);

// And we've written once
await candidateWriter(options, inputTemp, '**/*', undefined, outputTemp);
await candidateWriter(options, inputTemp, inputGlob, undefined, outputTemp);

// And files were written
const outputFilesBefore = await walkAndStat(outputTemp);
Expand All @@ -264,7 +267,7 @@ describe('zip', () => {
await candidateWriter({
...options,
overwriteInvalid: true,
}, inputTemp, '**/*', undefined, outputTemp);
}, inputTemp, inputGlob, undefined, outputTemp);

// Then the output wasn't touched
await expect(walkAndStat(outputTemp)).resolves.toEqual(outputFilesBefore);
Expand Down Expand Up @@ -570,8 +573,8 @@ describe('zip', () => {
[`ROMWriter Test.zip|${path.join('onetwothree', 'one.rom')}`, 'f817a89f'],
[`ROMWriter Test.zip|${path.join('onetwothree', 'three.rom')}`, 'ff46c5d8'],
[`ROMWriter Test.zip|${path.join('onetwothree', 'two.rom')}`, '96170874'],
[`ROMWriter Test.zip|${path.join('speed_test_v51', 'speed_test_v51.sfc')}`, '8beffd94'],
[`ROMWriter Test.zip|${path.join('speed_test_v51', 'speed_test_v51.smc')}`, '9adca6cc'],
['ROMWriter Test.zip|speed_test_v51.sfc', '8beffd94'],
['ROMWriter Test.zip|speed_test_v51.smc', '9adca6cc'],
['ROMWriter Test.zip|three.rom', 'ff46c5d8'],
['ROMWriter Test.zip|two.rom', '96170874'],
['ROMWriter Test.zip|unknown.rom', '377a7727'],
Expand Down
2 changes: 1 addition & 1 deletion test/modules/datGameInferrer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ test.each([
// No input paths
[[], {}],
// One input path
[['test/fixtures/roms/**/*'], { roms: 27 }],
[['test/fixtures/roms/**/*'], { roms: 28 }],
[['test/fixtures/roms/7z/*'], { '7z': 5 }],
[['test/fixtures/roms/gz/*'], { gz: 7 }],
[['test/fixtures/roms/rar/*'], { rar: 5 }],
Expand Down

0 comments on commit afb6449

Please sign in to comment.