fix: game audio persistence and editor perf
- Keep game/campaign audio assets referenced (no prune) - Flush pending project save on quit/switch/export to avoid losing campaignAudios - Control: prevent game music restarts on scene changes; allow always-on controls; handle autoplay-after-scene-audio - Editor: reduce ReactFlow churn with stable scene card map; lazy/async image decode - Add contract/unit tests and update test script Made-with: Cursor
This commit is contained in:
@@ -51,3 +51,48 @@ void test('readProjectJsonFromZip: sequential reads close yauzl (no EMFILE)', as
|
||||
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
void test('readProjectJsonFromZip: campaignAudios round-trips inside project.json', async () => {
|
||||
const tmp = await fs.mkdtemp(path.join(os.tmpdir(), 'dnd-zip-campaign-'));
|
||||
const zipPath = path.join(tmp, 'test.dnd.zip');
|
||||
const assetId = 'audio_asset_1';
|
||||
const minimal = {
|
||||
id: 'p1',
|
||||
meta: {
|
||||
name: 'n',
|
||||
fileBaseName: 'f',
|
||||
createdAt: '2020-01-01',
|
||||
updatedAt: '2020-01-01',
|
||||
createdWithAppVersion: '1',
|
||||
appVersion: '1',
|
||||
schemaVersion: PROJECT_SCHEMA_VERSION,
|
||||
},
|
||||
scenes: {},
|
||||
assets: {},
|
||||
campaignAudios: [{ assetId, autoplay: true, loop: false }],
|
||||
currentSceneId: null,
|
||||
currentGraphNodeId: null,
|
||||
sceneGraphNodes: [],
|
||||
sceneGraphEdges: [],
|
||||
};
|
||||
|
||||
const zipfile = new ZipFile();
|
||||
zipfile.addBuffer(Buffer.from(JSON.stringify(minimal), 'utf8'), 'project.json', { compressionLevel: 9 });
|
||||
const out = fssync.createWriteStream(zipPath);
|
||||
const done = new Promise<void>((resolve, reject) => {
|
||||
out.on('close', resolve);
|
||||
out.on('error', reject);
|
||||
});
|
||||
zipfile.outputStream.pipe(out);
|
||||
zipfile.end();
|
||||
await done;
|
||||
|
||||
const p = await readProjectJsonFromZip(zipPath);
|
||||
assert.ok(Array.isArray((p as { campaignAudios?: unknown }).campaignAudios));
|
||||
assert.deepEqual(
|
||||
(p as { campaignAudios: typeof minimal.campaignAudios }).campaignAudios,
|
||||
minimal.campaignAudios,
|
||||
);
|
||||
|
||||
await fs.rm(tmp, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user