From 95538e89ae447673bf21c4cc6f5d854e319f3c86 Mon Sep 17 00:00:00 2001 From: dukedotdev Date: Mon, 26 Oct 2026 11:22:36 -0400 Subject: [PATCH] [rooms] Preserve Studio export manifests on live saves (#143) --- apps/rooms/src/test/integration/api.test.ts | 27 +++++++++++++++++++++ packages/domain/src/rooms-db.ts | 13 ++++++++++ 2 files changed, 40 insertions(+) diff --git a/apps/rooms/src/test/integration/api.test.ts b/apps/rooms/src/test/integration/api.test.ts index 3361a5c..0621670 100644 --- a/apps/rooms/src/test/integration/api.test.ts +++ b/apps/rooms/src/test/integration/api.test.ts @@ -6404,6 +6404,33 @@ describe('studio room bundles', () => { })), }) } + // In-game saves reuse the compiled Studio asset. They must keep the export + // manifest when staging, saving again, and publishing the new scene data. + for (const autoPublish of [false, false, true]) { + const response = await SELF.fetch(`${ORIGIN}/rooms/9901/subrooms/99011/data`, { + method: 'POST', + headers: { ...(await bearer('1')), 'Content-Type': 'application/json' }, + body: JSON.stringify({ + UnityAssetId: ASSET.toUpperCase(), + SubRoomData: { Filename: 'in-game-save' }, + AutoPublish: autoPublish, + }), + }) + const result = (await response.json()) as { + success: boolean + value: { subRoomDataSave: { subRoomDataSaveId: number; unityAsset: string } } + } + expect(result.success).toBe(true) + expect(result.value.subRoomDataSave.unityAsset).toBe(winName) + const detail = await SELF.fetch( + `${ORIGIN}/rooms/9901/subrooms/99011/saves/${result.value.subRoomDataSave.subRoomDataSaveId}?unityAssetTarget=0`, + { headers: await bearer('1') } + ) + expect(await detail.json()).toMatchObject({ + UnityAsset: winName, + UnitySubAssets: [prefab, shared].map((UnityAssetId) => ({ UnityAssetId })), + }) + } await env.DB.prepare('DELETE FROM unity_asset WHERE unity_asset_id IN (?1,?2)') .bind(prefab, shared) .run() diff --git a/packages/domain/src/rooms-db.ts b/packages/domain/src/rooms-db.ts index c03cc2d..a1f04be 100644 --- a/packages/domain/src/rooms-db.ts +++ b/packages/domain/src/rooms-db.ts @@ -1924,6 +1924,19 @@ export async function saveSubRoomData( createdAt: new Date().toISOString(), unityAssetId: input.unityAssetId, }) + // A live client save changes the scene data while reusing the baked Studio + // asset. Its export manifest belongs to that asset and is needed again on the + // save's immediate reload (prefabs/materials live in separate bundles). + // A new Studio source upload must wait for its own cloud-build manifest. + if ( + !input.unitySource && + typeof input.unityAssetId === 'string' && + typeof previous?.UnityAssetId === 'string' && + input.unityAssetId.toLowerCase() === previous.UnityAssetId.toLowerCase() && + previous.ServerData != null + ) { + saveData.ServerData = previous.ServerData + } if (input.unitySource) { saveData.StudioSourceAsset = input.unitySource saveData.SavedOnPlatform = null