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:
Ivan Fontosh
2026-04-22 19:06:16 +08:00
parent f823a7c05f
commit 1d051f8bf9
19 changed files with 1164 additions and 115 deletions
+5 -2
View File
@@ -20,9 +20,10 @@ void test('collectReferencedAssetIds: превью, видео и аудио', (
},
},
},
campaignAudios: [{ assetId: 'ca1' as AssetId, autoplay: true, loop: true }],
} as unknown as Project;
const s = collectReferencedAssetIds(p);
assert.deepEqual([...s].sort(), ['a1', 'pr', 'v1'].sort());
assert.deepEqual([...s].sort(), ['a1', 'ca1', 'pr', 'v1'].sort());
});
void test('reconcileAssetFiles: снимает осиротевшие assets и удаляет файлы', async () => {
@@ -62,11 +63,13 @@ void test('reconcileAssetFiles: снимает осиротевшие assets и
const prev: Project = {
...base,
scenes: {},
campaignAudios: [],
assets: { orphan: asset } as Project['assets'],
};
const next: Project = {
...base,
scenes: {},
campaignAudios: [],
assets: { orphan: asset } as Project['assets'],
};
@@ -111,7 +114,7 @@ void test('reconcileAssetFiles: удаляет файл при исключен
} as unknown as Project;
const prev: Project = { ...base, assets: { gone: asset } as Project['assets'] };
const next: Project = { ...base, assets: {} as Project['assets'] };
const next: Project = { ...base, campaignAudios: [], assets: {} as Project['assets'] };
const out = await reconcileAssetFiles(prev, next, tmp);
assert.deepEqual(out.assets, {});