|
|
|
@@ -45,12 +45,13 @@ import type {
|
|
|
|
|
ProjectNpcGroup,
|
|
|
|
|
ProjectNpcRelation,
|
|
|
|
|
Scene,
|
|
|
|
|
SceneAudioRef,
|
|
|
|
|
SceneGraphEdge,
|
|
|
|
|
SceneGraphNode,
|
|
|
|
|
SceneId,
|
|
|
|
|
SceneTrap,
|
|
|
|
|
} from '../../shared/types';
|
|
|
|
|
import { PROJECT_SCHEMA_VERSION } from '../../shared/types';
|
|
|
|
|
import { normalizeSceneAudioRef, PROJECT_SCHEMA_VERSION } from '../../shared/types';
|
|
|
|
|
import { normalizeMaterialLegend } from '../../shared/types/materialLegend';
|
|
|
|
|
import { normalizeSceneToken, type SceneToken } from '../../shared/types/appTokens';
|
|
|
|
|
import {
|
|
|
|
@@ -817,7 +818,14 @@ export class ZipProjectStore {
|
|
|
|
|
: null),
|
|
|
|
|
...(patch.grid !== undefined ? { grid: normalizeSceneGrid(patch.grid) } : null),
|
|
|
|
|
...(patch.settings ? { settings: { ...base.settings, ...patch.settings } } : null),
|
|
|
|
|
...(patch.media ? { media: { ...base.media, ...patch.media } } : null),
|
|
|
|
|
...(patch.media
|
|
|
|
|
? {
|
|
|
|
|
media: {
|
|
|
|
|
videos: patch.media.videos ?? base.media.videos,
|
|
|
|
|
audios: (patch.media.audios ?? base.media.audios).map((a) => normalizeSceneAudioRef(a)),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
: null),
|
|
|
|
|
...(patch.layout ? { layout: { ...base.layout, ...patch.layout } } : null),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@@ -1180,8 +1188,9 @@ export class ZipProjectStore {
|
|
|
|
|
else
|
|
|
|
|
media.audios.push({
|
|
|
|
|
assetId: asset.id,
|
|
|
|
|
autoplay: sc.settings.autoplayAudio,
|
|
|
|
|
loop: sc.settings.loopAudio,
|
|
|
|
|
autoplay: false,
|
|
|
|
|
loop: false,
|
|
|
|
|
volume: 1,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
@@ -1232,7 +1241,7 @@ export class ZipProjectStore {
|
|
|
|
|
for (const asset of staged) {
|
|
|
|
|
assets[asset.id] = asset;
|
|
|
|
|
if (asset.type !== 'audio') continue;
|
|
|
|
|
campaignAudios.push({ assetId: asset.id, autoplay: false, loop: false });
|
|
|
|
|
campaignAudios.push({ assetId: asset.id, autoplay: false, loop: false, volume: 1 });
|
|
|
|
|
}
|
|
|
|
|
return { ...p, assets, campaignAudios };
|
|
|
|
|
});
|
|
|
|
@@ -1245,7 +1254,10 @@ export class ZipProjectStore {
|
|
|
|
|
async setCampaignAudios(audios: Project['campaignAudios']): Promise<Project> {
|
|
|
|
|
const open = this.openProject;
|
|
|
|
|
if (!open) throw new Error('No open project');
|
|
|
|
|
await this.updateProject((p) => ({ ...p, campaignAudios: Array.isArray(audios) ? audios : [] }));
|
|
|
|
|
const normalized = (Array.isArray(audios) ? audios : [])
|
|
|
|
|
.filter((a) => a && typeof a === 'object' && a.assetId)
|
|
|
|
|
.map((a) => normalizeSceneAudioRef(a));
|
|
|
|
|
await this.updateProject((p) => ({ ...p, campaignAudios: normalized }));
|
|
|
|
|
const latest = this.getOpenProject();
|
|
|
|
|
if (!latest) throw new Error('No open project');
|
|
|
|
|
return latest;
|
|
|
|
@@ -2624,20 +2636,26 @@ function normalizeScene(s: Scene): Scene {
|
|
|
|
|
const audios = rawAudios
|
|
|
|
|
.map((a) => {
|
|
|
|
|
if (typeof a === 'string') {
|
|
|
|
|
return {
|
|
|
|
|
return normalizeSceneAudioRef({
|
|
|
|
|
assetId: a as AssetId,
|
|
|
|
|
autoplay: Boolean((s.settings as { autoplayAudio?: boolean } | undefined)?.autoplayAudio),
|
|
|
|
|
loop: Boolean((s.settings as { loopAudio?: boolean } | undefined)?.loopAudio),
|
|
|
|
|
};
|
|
|
|
|
volume: 1,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (a && typeof a === 'object') {
|
|
|
|
|
const obj = a as { assetId?: AssetId; autoplay?: boolean; loop?: boolean };
|
|
|
|
|
const obj = a as { assetId?: AssetId; autoplay?: boolean; loop?: boolean; volume?: unknown };
|
|
|
|
|
if (!obj.assetId) return null;
|
|
|
|
|
return { assetId: obj.assetId, autoplay: Boolean(obj.autoplay), loop: Boolean(obj.loop) };
|
|
|
|
|
return normalizeSceneAudioRef({
|
|
|
|
|
assetId: obj.assetId,
|
|
|
|
|
autoplay: Boolean(obj.autoplay),
|
|
|
|
|
loop: Boolean(obj.loop),
|
|
|
|
|
volume: obj.volume,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
})
|
|
|
|
|
.filter((x): x is { assetId: AssetId; autoplay: boolean; loop: boolean } => Boolean(x));
|
|
|
|
|
.filter((x): x is SceneAudioRef => Boolean(x));
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
...s,
|
|
|
|
@@ -2682,15 +2700,20 @@ function normalizeProject(p: Project): Project {
|
|
|
|
|
const rawCampaignAudios = (p as unknown as { campaignAudios?: unknown[] }).campaignAudios;
|
|
|
|
|
const campaignAudios = (Array.isArray(rawCampaignAudios) ? rawCampaignAudios : [])
|
|
|
|
|
.map((a) => {
|
|
|
|
|
if (typeof a === 'string') return { assetId: a as AssetId, autoplay: false, loop: false };
|
|
|
|
|
if (typeof a === 'string') return normalizeSceneAudioRef({ assetId: a as AssetId, autoplay: false, loop: false, volume: 1 });
|
|
|
|
|
if (a && typeof a === 'object') {
|
|
|
|
|
const obj = a as { assetId?: AssetId; autoplay?: boolean; loop?: boolean };
|
|
|
|
|
const obj = a as { assetId?: AssetId; autoplay?: boolean; loop?: boolean; volume?: unknown };
|
|
|
|
|
if (!obj.assetId) return null;
|
|
|
|
|
return { assetId: obj.assetId, autoplay: Boolean(obj.autoplay), loop: Boolean(obj.loop) };
|
|
|
|
|
return normalizeSceneAudioRef({
|
|
|
|
|
assetId: obj.assetId,
|
|
|
|
|
autoplay: Boolean(obj.autoplay),
|
|
|
|
|
loop: Boolean(obj.loop),
|
|
|
|
|
volume: obj.volume,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
})
|
|
|
|
|
.filter((x): x is { assetId: AssetId; autoplay: boolean; loop: boolean } => Boolean(x));
|
|
|
|
|
.filter((x): x is SceneAudioRef => Boolean(x));
|
|
|
|
|
const rawMaterials = (p as unknown as { materials?: unknown[] }).materials;
|
|
|
|
|
const materials = (Array.isArray(rawMaterials) ? rawMaterials : [])
|
|
|
|
|
.map((m) => {
|
|
|
|
|