import fs from 'node:fs'; import path from 'node:path'; import { CustomWorldProfile, WorldType } from '../types'; import { getDefaultCustomWorldSceneImage, resolveCustomWorldCampSceneImage, resolveCustomWorldLandmarkImageMap, } from './customWorldVisuals'; import { getScenePresetsByWorld } from './scenePresets'; function resolvePublicAssetPath(assetPath: string) { return path.resolve(process.cwd(), 'public', assetPath.replace(/^\/+/, '')); } describe('scene background assets', () => { it('ships background files for every wuxia and xianxia scene preset', () => { const scenes = [ ...getScenePresetsByWorld(WorldType.WUXIA), ...getScenePresetsByWorld(WorldType.XIANXIA), ]; expect(scenes.length).toBeGreaterThan(0); for (const scene of scenes) { expect(fs.existsSync(resolvePublicAssetPath(scene.imageSrc))).toBe(true); } }); it('returns existing default custom world backgrounds for both anchor worlds', () => { const wuxiaImage = getDefaultCustomWorldSceneImage('seed', 0, WorldType.WUXIA); const xianxiaImage = getDefaultCustomWorldSceneImage('seed', 0, WorldType.XIANXIA); expect(fs.existsSync(resolvePublicAssetPath(wuxiaImage))).toBe(true); expect(fs.existsSync(resolvePublicAssetPath(xianxiaImage))).toBe(true); }); it('keeps ungenerated custom world scenes on independent matched backgrounds', () => { const generatedImage = '/generated-custom-world-scenes/test-world/generated-ruins.png'; const profile: CustomWorldProfile = { id: 'custom-world-test', settingText: '荒城断碑与边关旧营并存的武侠世界', name: '断碑边城', subtitle: '烽烟未熄', summary: '边关旧营与残城废墟彼此相望,玩家要追查旧案余烬。', tone: '压抑、克制、潜伏危机', playerGoal: '追查残城旧案背后的真相', templateWorldType: WorldType.WUXIA, majorFactions: [], coreConflicts: ['边关旧案复起'], attributeSchema: { id: 'schema:test', worldId: 'custom:test', schemaVersion: 1, generatedFrom: { worldType: WorldType.CUSTOM, worldName: '断碑边城', settingSummary: '边关旧案', tone: '压抑', conflictCore: '旧案复起', }, slots: [], }, playableNpcs: [], storyNpcs: [], items: [], landmarks: [ { id: 'landmark-1', name: '残城旧营', description: '断墙、军帐与营火灰烬混在一起,像一处被遗弃的边关驻地。', dangerLevel: 'high', imageSrc: generatedImage, sceneNpcIds: [], connections: [], }, { id: 'landmark-2', name: '雾锁渡桥', description: '古桥横跨冷河,雾气压在水面上,只有残灯还在摇晃。', dangerLevel: 'medium', sceneNpcIds: [], connections: [], }, { id: 'landmark-3', name: '地宫裂隙', description: '墓道向下坍塌,石阶与机关残痕一路通往地底深处。', dangerLevel: 'extreme', sceneNpcIds: [], connections: [], }, ], themePack: null, storyGraph: null, creatorIntent: null, anchorPack: null, lockState: null, generationMode: 'full', generationStatus: 'complete', }; const landmarkImageMap = resolveCustomWorldLandmarkImageMap(profile); const secondImage = landmarkImageMap.get('landmark-2'); const thirdImage = landmarkImageMap.get('landmark-3'); const campImage = resolveCustomWorldCampSceneImage(profile); expect(landmarkImageMap.get('landmark-1')).toBe(generatedImage); expect(secondImage).toBeTruthy(); expect(thirdImage).toBeTruthy(); expect(secondImage).not.toBe(generatedImage); expect(thirdImage).not.toBe(generatedImage); expect(secondImage).not.toBe(thirdImage); expect(campImage).toBeTruthy(); expect(campImage).not.toBe(generatedImage); expect(fs.existsSync(resolvePublicAssetPath(secondImage!))).toBe(true); expect(fs.existsSync(resolvePublicAssetPath(thirdImage!))).toBe(true); expect(fs.existsSync(resolvePublicAssetPath(campImage))).toBe(true); }); });