This commit is contained in:
766
packages/shared/src/contracts/rpgCreationFixtures.ts
Normal file
766
packages/shared/src/contracts/rpgCreationFixtures.ts
Normal file
@@ -0,0 +1,766 @@
|
||||
import type {
|
||||
CustomWorldLibraryEntry,
|
||||
CustomWorldProfileRecord,
|
||||
} from './runtime';
|
||||
import type { RpgAgentSupportedAction } from './rpgAgentActions';
|
||||
import type { RpgCreationAnchorContent } from './rpgAgentAnchors';
|
||||
import type {
|
||||
RpgAgentAssetCoverageSummary,
|
||||
RpgAgentDraftCardSummary,
|
||||
RpgAgentFoundationDraftProfile,
|
||||
} from './rpgAgentDraft';
|
||||
import type { RpgAgentSessionSnapshot } from './rpgAgentSession';
|
||||
import type { RpgCreationPreviewEnvelope } from './rpgCreationPreview';
|
||||
import type {
|
||||
ListRpgCreationWorksResponse,
|
||||
RpgCreationWorkSummary,
|
||||
} from './rpgCreationWorkSummary';
|
||||
|
||||
const RPG_CREATION_FIXTURE_SESSION_ID = 'rpg-session-fixture';
|
||||
const RPG_CREATION_FIXTURE_PROFILE_ID = 'rpg-profile-fixture';
|
||||
const RPG_CREATION_FIXTURE_USER_ID = 'fixture-user';
|
||||
const RPG_CREATION_FIXTURE_UPDATED_AT = '2026-04-21T09:30:00.000Z';
|
||||
const RPG_CREATION_FIXTURE_PUBLISHED_AT = '2026-04-21T10:00:00.000Z';
|
||||
|
||||
function cloneFixture<T>(value: T): T {
|
||||
return JSON.parse(JSON.stringify(value)) as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 共享八锚点 fixture。
|
||||
* 用于 contract test、session fixture 和 works 集成测试复用同一份创作意图样本。
|
||||
*/
|
||||
export function createRpgCreationAnchorContentFixture(): RpgCreationAnchorContent {
|
||||
return cloneFixture({
|
||||
worldPromise:
|
||||
'被海雾吞没的旧航路群岛,灯塔与禁航令共同决定谁能活着穿过去,体验压抑、悬疑、潮湿。',
|
||||
playerFantasy:
|
||||
'玩家回到群岛调查沉船真相,核心追求是找出失控航路背后的真相,风险是失去最后一个还能对上旧案的人。',
|
||||
themeBoundary:
|
||||
'压抑、潮湿、悬疑;旧灯塔、潮雾、断裂航路;不要出现现代枪械。',
|
||||
playerEntryPoint:
|
||||
'玩家是被迫返乡的失职守灯人,首夜就有陌生船只闯入禁航区,动机是查清沉船夜里被谁改动了灯册。',
|
||||
coreConflict:
|
||||
'守灯会与航运公会争夺旧航路控制权,沉船夜的航灯与灯册被人动过手脚,玩家开局会撞上新的封航命令。',
|
||||
keyRelationships:
|
||||
'玩家与沈砺是旧友兼潜在背叛者,沈砺暗地里在替沉船商盟引路。',
|
||||
hiddenLines:
|
||||
'沉船夜的真实失误并不是单纯天灾;所有人都会先把问题推给潮雾本身;第一章露出痕迹,第二章才让玩家摸到灯册线。',
|
||||
iconicElements:
|
||||
'会移动的海雾、回潮旧灯塔、封灯令、旧潮图;禁航信号一旦点亮,任何船都必须退航。',
|
||||
} satisfies RpgCreationAnchorContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 共享 foundation draft fixture。
|
||||
* 这份样本同时服务 session 草稿、preview 适配回归测试和 works 聚合测试。
|
||||
*/
|
||||
export function createRpgAgentFoundationDraftProfileFixture(): RpgAgentFoundationDraftProfile {
|
||||
return cloneFixture({
|
||||
name: '潮雾列岛',
|
||||
subtitle: '旧灯塔与失控航路',
|
||||
summary: '第一版世界底稿已经整理完成,玩家将从回潮旧灯塔切入沉船旧案。',
|
||||
tone: '压抑、潮湿、悬疑',
|
||||
playerGoal: '查清沉船与禁航区异动的真相。',
|
||||
majorFactions: ['守灯会', '航运公会'],
|
||||
coreConflicts: ['守灯会与航运公会争夺旧航路控制权'],
|
||||
playableNpcs: [
|
||||
{
|
||||
id: 'playable-1',
|
||||
name: '沈砺',
|
||||
title: '旧航路引路人',
|
||||
role: '关键同行者',
|
||||
publicIdentity: '最熟悉旧航路的人。',
|
||||
publicMask: '看上去像可靠旧友。',
|
||||
currentPressure: '他必须在两股势力间站队。',
|
||||
hiddenHook: '暗中替沉船商盟引路。',
|
||||
relationToPlayer: '旧友兼潜在背叛者',
|
||||
threadIds: ['thread-1'],
|
||||
summary: '他像旧友,但也像一把始终没收回鞘的刀。',
|
||||
skills: [
|
||||
{
|
||||
id: 'skill-playable-1',
|
||||
name: '潮行引路',
|
||||
actionPreviewConfig: {
|
||||
basePath:
|
||||
'/generated-characters/playable-1/animations/skills/skill-playable-1',
|
||||
},
|
||||
},
|
||||
],
|
||||
imageSrc:
|
||||
'/generated-characters/playable-1/visual/asset-runtime/master.png',
|
||||
generatedVisualAssetId: 'asset-runtime-playable',
|
||||
generatedAnimationSetId: 'animation-set-playable-1',
|
||||
animationMap: {
|
||||
idle: {
|
||||
basePath: '/generated-characters/playable-1/animations/idle',
|
||||
},
|
||||
run: {
|
||||
basePath: '/generated-characters/playable-1/animations/run',
|
||||
},
|
||||
attack: {
|
||||
basePath: '/generated-characters/playable-1/animations/attack',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
storyNpcs: [
|
||||
{
|
||||
id: 'story-1',
|
||||
name: '顾潮音',
|
||||
title: '守灯会值夜人',
|
||||
role: '场景关键角色',
|
||||
publicIdentity: '负责夜间巡灯与封锁。',
|
||||
publicMask: '对外一直冷静克制。',
|
||||
currentPressure: '她知道更多禁航区真相。',
|
||||
hiddenHook: '曾亲眼见过失控海雾吞船。',
|
||||
relationToPlayer: '最早愿意交换线索的人',
|
||||
threadIds: ['thread-1'],
|
||||
summary: '她总像比所有人更早知道海雾会往哪一侧压下来。',
|
||||
skills: [
|
||||
{
|
||||
id: 'skill-story-1',
|
||||
name: '夜潮灯语',
|
||||
actionPreviewConfig: {
|
||||
basePath:
|
||||
'/generated-characters/story-1/animations/skills/skill-story-1',
|
||||
},
|
||||
},
|
||||
],
|
||||
imageSrc:
|
||||
'/generated-characters/story-1/visual/asset-runtime/master.png',
|
||||
generatedVisualAssetId: 'asset-runtime-story',
|
||||
generatedAnimationSetId: 'animation-set-story-1',
|
||||
animationMap: {
|
||||
run: {
|
||||
basePath: '/generated-characters/story-1/animations/run',
|
||||
},
|
||||
attack: {
|
||||
basePath: '/generated-characters/story-1/animations/attack',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
landmarks: [
|
||||
{
|
||||
id: 'landmark-1',
|
||||
name: '回潮旧灯塔',
|
||||
description: '被海雾啃旧的石塔仍在夜里维持着微弱灯火。',
|
||||
purpose: '观察雾潮与往来船只',
|
||||
mood: '潮湿、压抑、风声不止',
|
||||
importance: '开局核心场景',
|
||||
secret: '高处潮痕说明海面异常抬升过。',
|
||||
imageSrc: '/generated-custom-world-scenes/landmark-1/latest-scene.png',
|
||||
generatedSceneAssetId: 'scene-asset-landmark-1',
|
||||
characterIds: ['story-1'],
|
||||
threadIds: ['thread-1'],
|
||||
summary: '旧灯塔是整片群岛最先看见异动的地方。',
|
||||
},
|
||||
],
|
||||
camp: {
|
||||
id: 'camp-1',
|
||||
name: '回潮暂栖所',
|
||||
description: '能暂时收拢队伍、整理灯册与潮路线索的落脚点。',
|
||||
mood: '克制、紧绷,但还能暂时收拢局势',
|
||||
imageSrc: '/custom/camp/huichao.png',
|
||||
generatedSceneAssetId: 'scene-asset-camp-1',
|
||||
summary: '玩家能在这里整理情报、回看旧灯册和沉船名单。',
|
||||
},
|
||||
themePack: {
|
||||
id: 'theme-pack:tide',
|
||||
displayName: '潮雾悬疑',
|
||||
},
|
||||
storyGraph: {
|
||||
visibleThreads: [
|
||||
{
|
||||
id: 'thread-visible-1',
|
||||
title: '封航争夺',
|
||||
},
|
||||
],
|
||||
},
|
||||
attributeSchema: {
|
||||
id: 'schema:rpg-agent:tide-fixture',
|
||||
worldId: 'custom:潮雾列岛',
|
||||
schemaVersion: 1,
|
||||
schemaName: '潮雾六脉',
|
||||
generatedFrom: {
|
||||
worldType: 'CUSTOM',
|
||||
worldName: '潮雾列岛',
|
||||
settingSummary: '旧灯塔与失控航路',
|
||||
tone: '压抑、潮湿、悬疑',
|
||||
conflictCore: '沉船夜的航灯与灯册被人动过手脚。',
|
||||
},
|
||||
slots: [
|
||||
{
|
||||
slotId: 'axis_a',
|
||||
name: '潮骨',
|
||||
definition: '承受潮压、封航令与正面冲击的底子。',
|
||||
positiveSignals: ['承压', '稳阵'],
|
||||
negativeSignals: ['散乱', '畏压'],
|
||||
combatUseText: '顶住正面压迫并守住行动空间。',
|
||||
socialUseText: '在封锁与质问中保持可信姿态。',
|
||||
explorationUseText: '穿过潮湿险境时维持身体与装备状态。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_b',
|
||||
name: '浪步',
|
||||
definition: '顺潮借势、换线穿行与抢占位置的能力。',
|
||||
positiveSignals: ['借势', '轻快'],
|
||||
negativeSignals: ['迟滞', '失位'],
|
||||
combatUseText: '借地形切线、拉开距离或抢先手。',
|
||||
socialUseText: '顺着对方语气调整节奏。',
|
||||
explorationUseText: '穿越港口、水路、雾区与复杂地形。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_c',
|
||||
name: '灯识',
|
||||
definition: '看懂灯号、潮痕、档案错页与人心遮掩的能力。',
|
||||
positiveSignals: ['辨伪', '识局'],
|
||||
negativeSignals: ['误读', '迟钝'],
|
||||
combatUseText: '识破破绽并判断局势变化。',
|
||||
socialUseText: '听出隐瞒、试探与交换空间。',
|
||||
explorationUseText: '辨认潮痕、灯册和沉船遗留线索。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_d',
|
||||
name: '雾魄',
|
||||
definition: '在海雾、旧案与封锁压力中推进真相的胆气。',
|
||||
positiveSignals: ['果断', '压前'],
|
||||
negativeSignals: ['犹疑', '退缩'],
|
||||
combatUseText: '顶着高压窗口推进突破口。',
|
||||
socialUseText: '在谈判或对峙中定调。',
|
||||
explorationUseText: '面对陌生雾区与异状仍敢继续前探。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_e',
|
||||
name: '旧约',
|
||||
definition: '与旧友、信物、灯令和地方关系建立牵引的能力。',
|
||||
positiveSignals: ['守诺', '通人情'],
|
||||
negativeSignals: ['疏离', '失信'],
|
||||
combatUseText: '借同伴协同与旧约牵制形成连锁。',
|
||||
socialUseText: '安抚、结盟、交换与维系信任。',
|
||||
explorationUseText: '从人情、传闻和旧物中打开线索。',
|
||||
},
|
||||
{
|
||||
slotId: 'axis_f',
|
||||
name: '回澜',
|
||||
definition: '在长线消耗中回稳节奏并维持判断的能力。',
|
||||
positiveSignals: ['回稳', '续航'],
|
||||
negativeSignals: ['紊乱', '断流'],
|
||||
combatUseText: '久战不乱,把节奏重新拉回手里。',
|
||||
socialUseText: '情绪稳定,不轻易被带偏。',
|
||||
explorationUseText: '在漫长远行与恶劣天气里保有余力。',
|
||||
},
|
||||
],
|
||||
},
|
||||
factions: [
|
||||
{
|
||||
id: 'faction-1',
|
||||
name: '守灯会',
|
||||
title: '守灯会',
|
||||
subtitle: '把控禁航灯令的人',
|
||||
publicGoal: '维持封航秩序并压住灯册流出。',
|
||||
relatedConflict: '想把旧案继续压在禁航记录之下。',
|
||||
tension: '他们越强调规矩,越像在遮掩灯册。',
|
||||
playerRelation: '玩家迟早要与他们正面冲突。',
|
||||
summary: '掌握灯塔与封航令的势力,也是最怕旧案被翻出来的一方。',
|
||||
},
|
||||
],
|
||||
threads: [
|
||||
{
|
||||
id: 'thread-1',
|
||||
title: '沉船旧案',
|
||||
type: 'main',
|
||||
conflictType: '真相遮蔽',
|
||||
conflict: '沉船夜的航灯与灯册被人动过手脚。',
|
||||
stakes: '真相一旦坐实,群岛秩序会先崩。',
|
||||
characterIds: ['playable-1', 'story-1'],
|
||||
landmarkIds: ['landmark-1'],
|
||||
summary: '玩家会从灯塔高处潮痕一路追到沉船夜的真相。',
|
||||
},
|
||||
],
|
||||
chapters: [
|
||||
{
|
||||
id: 'chapter-1',
|
||||
title: '灯塔回潮',
|
||||
openingEvent: '禁航区闯入了一艘不该出现的陌生船。',
|
||||
playerGoal: '先稳住局势,再拿到第一份灯册线索。',
|
||||
characterIds: ['playable-1', 'story-1'],
|
||||
landmarkIds: ['landmark-1'],
|
||||
understandingShift: '玩家会意识到沉船旧案至今仍在操控群岛秩序。',
|
||||
summary: '第一章聚焦灯塔与封航令,给玩家一条可追的旧案线索。',
|
||||
},
|
||||
],
|
||||
sceneChapters: [
|
||||
{
|
||||
id: 'scene-chapter-1',
|
||||
sceneId: 'landmark-1',
|
||||
sceneName: '回潮旧灯塔',
|
||||
title: '灯塔初章',
|
||||
summary: '围绕灯塔推进的首个场景章节。',
|
||||
sceneTaskDescription: '首次进入回潮旧灯塔时,追查禁航灯册为何被人改写。',
|
||||
linkedThreadIds: ['thread-1'],
|
||||
linkedLandmarkIds: ['landmark-1'],
|
||||
acts: [
|
||||
{
|
||||
id: 'scene-act-1',
|
||||
title: '第一幕',
|
||||
summary: '先接住回潮灯塔的入口压力。',
|
||||
stageCoverage: ['opening'],
|
||||
backgroundImageSrc:
|
||||
'/generated-custom-world-scenes/landmark-1/scene-act-1/scene.png',
|
||||
backgroundAssetId: 'scene-asset-runtime',
|
||||
encounterNpcIds: ['story-1'],
|
||||
primaryNpcId: 'story-1',
|
||||
oppositeNpcId: 'story-1',
|
||||
eventDescription: '顾潮音在旧灯塔门前拦住玩家,交出第一段灯册疑点。',
|
||||
linkedThreadIds: ['thread-1'],
|
||||
actGoal: '接住首幕入口',
|
||||
transitionHook: '向第二幕推进。',
|
||||
advanceRule: 'after_primary_contact',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
worldHook: '被海雾吞没的旧航路群岛',
|
||||
playerPremise: '玩家回到群岛调查沉船真相。',
|
||||
openingSituation: '首夜就有陌生船只闯入禁航区。',
|
||||
iconicElements: ['会移动的海雾', '回潮旧灯塔'],
|
||||
sourceAnchorSummary: '海雾、旧灯塔、失控航路。',
|
||||
} satisfies RpgAgentFoundationDraftProfile);
|
||||
}
|
||||
|
||||
function createRpgAgentDraftCardsFixture(): RpgAgentDraftCardSummary[] {
|
||||
return cloneFixture([
|
||||
{
|
||||
id: 'world-foundation',
|
||||
kind: 'world',
|
||||
title: '潮雾列岛',
|
||||
subtitle: '旧灯塔与失控航路',
|
||||
summary: '第一版世界底稿已经整理完成。',
|
||||
status: 'suggested',
|
||||
linkedIds: ['playable-1', 'story-1', 'landmark-1'],
|
||||
warningCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'playable-1',
|
||||
kind: 'character',
|
||||
title: '沈砺',
|
||||
subtitle: '旧航路引路人 / 动作已齐',
|
||||
summary: '最熟悉旧航路的人,也可能是最危险的旧友。',
|
||||
status: 'suggested',
|
||||
linkedIds: ['thread-1', 'landmark-1'],
|
||||
warningCount: 0,
|
||||
assetStatus: 'complete',
|
||||
assetStatusLabel: '动作已齐',
|
||||
},
|
||||
{
|
||||
id: 'landmark-1',
|
||||
kind: 'landmark',
|
||||
title: '回潮旧灯塔',
|
||||
subtitle: '观察雾潮与往来船只',
|
||||
summary: '旧灯塔是整片群岛最先看见异动的地方。',
|
||||
status: 'suggested',
|
||||
linkedIds: ['story-1', 'thread-1'],
|
||||
warningCount: 0,
|
||||
},
|
||||
] satisfies RpgAgentDraftCardSummary[]);
|
||||
}
|
||||
|
||||
function createRpgAgentAssetCoverageFixture(): RpgAgentAssetCoverageSummary {
|
||||
return cloneFixture({
|
||||
roleAssets: [
|
||||
{
|
||||
roleId: 'playable-1',
|
||||
roleName: '沈砺',
|
||||
roleKind: 'playable',
|
||||
priorityTier: 'hero',
|
||||
portraitPath:
|
||||
'/generated-characters/playable-1/visual/asset-runtime/master.png',
|
||||
generatedVisualAssetId: 'asset-runtime-playable',
|
||||
generatedAnimationSetId: 'animation-set-playable-1',
|
||||
status: 'complete',
|
||||
missingAnimations: [],
|
||||
nextPointCost: 0,
|
||||
},
|
||||
{
|
||||
roleId: 'story-1',
|
||||
roleName: '顾潮音',
|
||||
roleKind: 'story',
|
||||
priorityTier: 'featured',
|
||||
portraitPath:
|
||||
'/generated-characters/story-1/visual/asset-runtime/master.png',
|
||||
generatedVisualAssetId: 'asset-runtime-story',
|
||||
generatedAnimationSetId: 'animation-set-story-1',
|
||||
status: 'complete',
|
||||
missingAnimations: [],
|
||||
nextPointCost: 0,
|
||||
},
|
||||
],
|
||||
sceneAssets: [
|
||||
{
|
||||
sceneId: 'landmark-1',
|
||||
sceneName: '回潮旧灯塔',
|
||||
actId: 'scene-act-1',
|
||||
actTitle: '第一幕',
|
||||
imageSrc:
|
||||
'/generated-custom-world-scenes/landmark-1/scene-act-1/scene.png',
|
||||
assetId: 'scene-asset-runtime',
|
||||
status: 'ready',
|
||||
nextPointCost: 0,
|
||||
},
|
||||
],
|
||||
allRoleAssetsReady: true,
|
||||
allSceneAssetsReady: true,
|
||||
} satisfies RpgAgentAssetCoverageSummary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 已发布 profile fixture。
|
||||
* 用于 preview compiler、works 聚合和 library 元数据解析测试。
|
||||
*/
|
||||
export function createRpgCreationPublishedProfileFixture(): CustomWorldProfileRecord {
|
||||
const draft = createRpgAgentFoundationDraftProfileFixture();
|
||||
|
||||
return cloneFixture({
|
||||
id: RPG_CREATION_FIXTURE_PROFILE_ID,
|
||||
settingText: draft.worldHook,
|
||||
name: draft.name,
|
||||
subtitle: draft.subtitle,
|
||||
summary: draft.summary,
|
||||
tone: draft.tone,
|
||||
playerGoal: draft.playerGoal,
|
||||
templateWorldType: 'WUXIA',
|
||||
compatibilityTemplateWorldType: 'WUXIA',
|
||||
majorFactions: draft.majorFactions,
|
||||
coreConflicts: draft.coreConflicts,
|
||||
playableNpcs: draft.playableNpcs.map((role) => ({
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
title: role.title,
|
||||
role: role.role,
|
||||
description: role.publicIdentity,
|
||||
backstory: role.hiddenHook || role.summary,
|
||||
personality: role.publicMask || role.summary,
|
||||
motivation: role.currentPressure,
|
||||
combatStyle: '借地形和潮路换位,先拉扯再压近。',
|
||||
initialAffinity: 18,
|
||||
relationshipHooks: [role.relationToPlayer],
|
||||
tags: ['潮路', '旧案'],
|
||||
imageSrc: role.imageSrc,
|
||||
generatedVisualAssetId: role.generatedVisualAssetId,
|
||||
generatedAnimationSetId: role.generatedAnimationSetId,
|
||||
animationMap: role.animationMap,
|
||||
skills: [
|
||||
{
|
||||
id: 'skill-playable-1',
|
||||
name: '潮行引路',
|
||||
summary: '踩着旧潮阶切线前压,替队伍打开角度。',
|
||||
style: '机动周旋',
|
||||
},
|
||||
],
|
||||
})),
|
||||
storyNpcs: draft.storyNpcs.map((role) => ({
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
title: role.title,
|
||||
role: role.role,
|
||||
description: role.publicIdentity,
|
||||
backstory: role.hiddenHook || role.summary,
|
||||
personality: role.publicMask || role.summary,
|
||||
motivation: role.currentPressure,
|
||||
combatStyle: '借塔顶视角和风向压制,再用灯火错位扰乱。',
|
||||
initialAffinity: 8,
|
||||
relationshipHooks: [role.relationToPlayer],
|
||||
tags: ['守灯会', '灯塔'],
|
||||
imageSrc: role.imageSrc,
|
||||
generatedVisualAssetId: role.generatedVisualAssetId,
|
||||
skills: [
|
||||
{
|
||||
id: 'skill-story-1',
|
||||
name: '夜潮灯语',
|
||||
summary: '借灯语与潮声干扰对方判断。',
|
||||
style: '起手压制',
|
||||
},
|
||||
],
|
||||
})),
|
||||
camp: {
|
||||
name: draft.camp?.name,
|
||||
description: draft.camp?.description,
|
||||
imageSrc: draft.camp?.imageSrc,
|
||||
},
|
||||
landmarks: draft.landmarks.map((landmark) => ({
|
||||
id: landmark.id,
|
||||
name: landmark.name,
|
||||
description: landmark.description,
|
||||
imageSrc: landmark.imageSrc,
|
||||
sceneNpcIds: landmark.characterIds,
|
||||
connections: [
|
||||
{
|
||||
targetLandmarkId: 'landmark-1',
|
||||
relativePosition: 'forward',
|
||||
summary: '沿着旧潮阶继续前压到雾栈尽头。',
|
||||
},
|
||||
],
|
||||
})),
|
||||
cover: {
|
||||
sourceType: 'default',
|
||||
characterRoleIds: ['playable-1'],
|
||||
},
|
||||
sceneChapterBlueprints: draft.sceneChapters.map((chapter) => ({
|
||||
id: chapter.id,
|
||||
sceneId: chapter.sceneId,
|
||||
sceneName: chapter.sceneName,
|
||||
title: chapter.title,
|
||||
summary: chapter.summary,
|
||||
sceneTaskDescription: chapter.sceneTaskDescription,
|
||||
acts: chapter.acts.map((act) => ({
|
||||
id: act.id,
|
||||
title: act.title,
|
||||
summary: act.summary,
|
||||
backgroundImageSrc: act.backgroundImageSrc,
|
||||
backgroundAssetId: act.backgroundAssetId,
|
||||
encounterNpcIds: act.encounterNpcIds,
|
||||
primaryNpcId: act.primaryNpcId,
|
||||
oppositeNpcId: act.oppositeNpcId,
|
||||
eventDescription: act.eventDescription,
|
||||
actGoal: act.actGoal,
|
||||
transitionHook: act.transitionHook,
|
||||
})),
|
||||
})),
|
||||
themePack: draft.themePack,
|
||||
storyGraph: draft.storyGraph,
|
||||
scenarioPackId: 'scenario-pack:tide',
|
||||
campaignPackId: 'campaign-pack:tide',
|
||||
generationMode: 'fast',
|
||||
generationStatus: 'key_only',
|
||||
updatedAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
publishedAt: RPG_CREATION_FIXTURE_PUBLISHED_AT,
|
||||
} satisfies CustomWorldProfileRecord);
|
||||
}
|
||||
|
||||
export function createRpgCreationPreviewEnvelopeFixture(): RpgCreationPreviewEnvelope {
|
||||
return cloneFixture({
|
||||
preview: {
|
||||
...createRpgCreationPublishedProfileFixture(),
|
||||
previewId: 'preview-fixture-1',
|
||||
sessionId: RPG_CREATION_FIXTURE_SESSION_ID,
|
||||
profileId: RPG_CREATION_FIXTURE_PROFILE_ID,
|
||||
},
|
||||
source: 'session_preview',
|
||||
generatedAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
qualityFindings: [
|
||||
{
|
||||
id: 'finding-scene-asset-ready',
|
||||
severity: 'info',
|
||||
code: 'scene_asset_ready',
|
||||
targetId: 'scene-act-1',
|
||||
message: '首幕背景图已经就绪,可直接用于结果页预览。',
|
||||
},
|
||||
],
|
||||
blockers: [],
|
||||
publishReady: true,
|
||||
canEnterWorld: false,
|
||||
} satisfies RpgCreationPreviewEnvelope);
|
||||
}
|
||||
|
||||
export function createRpgAgentSupportedActionsFixture(): RpgAgentSupportedAction[] {
|
||||
return cloneFixture([
|
||||
{
|
||||
action: 'draft_foundation',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
action: 'generate_role_assets',
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
action: 'publish_world',
|
||||
enabled: true,
|
||||
},
|
||||
] satisfies RpgAgentSupportedAction[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 共享 session snapshot fixture。
|
||||
* 默认模拟“底稿、预览、资产都已准备好”的 ready_to_publish 状态。
|
||||
*/
|
||||
export function createRpgAgentSessionFixture(): RpgAgentSessionSnapshot {
|
||||
const draftProfile = createRpgAgentFoundationDraftProfileFixture();
|
||||
|
||||
return cloneFixture({
|
||||
sessionId: RPG_CREATION_FIXTURE_SESSION_ID,
|
||||
currentTurn: 6,
|
||||
anchorContent: createRpgCreationAnchorContentFixture(),
|
||||
progressPercent: 100,
|
||||
lastAssistantReply: '八锚点与底稿都已经齐备,可以进入结果页收口。',
|
||||
stage: 'ready_to_publish',
|
||||
focusCardId: null,
|
||||
creatorIntent: {
|
||||
sourceMode: 'card',
|
||||
rawSettingText: draftProfile.worldHook,
|
||||
worldHook: draftProfile.worldHook,
|
||||
playerPremise: draftProfile.playerPremise,
|
||||
themeKeywords: ['海雾', '旧航路'],
|
||||
toneDirectives: ['压抑', '悬疑'],
|
||||
openingSituation: draftProfile.openingSituation,
|
||||
coreConflicts: draftProfile.coreConflicts,
|
||||
keyFactions: ['守灯会'],
|
||||
keyCharacters: ['沈砺', '顾潮音'],
|
||||
keyLandmarks: ['回潮旧灯塔'],
|
||||
iconicElements: draftProfile.iconicElements,
|
||||
forbiddenDirectives: ['不要出现现代枪械'],
|
||||
},
|
||||
creatorIntentReadiness: {
|
||||
isReady: true,
|
||||
completedKeys: [
|
||||
'world_hook',
|
||||
'player_premise',
|
||||
'theme_and_tone',
|
||||
'core_conflict',
|
||||
'relationship_seed',
|
||||
'iconic_element',
|
||||
],
|
||||
missingKeys: [],
|
||||
},
|
||||
anchorPack: {
|
||||
summary: draftProfile.sourceAnchorSummary,
|
||||
},
|
||||
lockState: {
|
||||
lockedCardIds: ['world-foundation'],
|
||||
},
|
||||
draftProfile: draftProfile as unknown as Record<string, unknown>,
|
||||
messages: [
|
||||
{
|
||||
id: 'message-1',
|
||||
role: 'assistant',
|
||||
kind: 'summary',
|
||||
text: '世界底稿已整理完成,建议进入结果页确认资产与发布门槛。',
|
||||
createdAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
relatedOperationId: null,
|
||||
},
|
||||
],
|
||||
draftCards: createRpgAgentDraftCardsFixture(),
|
||||
pendingClarifications: [],
|
||||
suggestedActions: [
|
||||
{
|
||||
id: 'action-publish',
|
||||
type: 'publish_world',
|
||||
label: '发布世界',
|
||||
},
|
||||
],
|
||||
recommendedReplies: ['先看结果页', '继续精修角色关系'],
|
||||
qualityFindings: [
|
||||
{
|
||||
id: 'finding-scene-asset-ready',
|
||||
severity: 'info',
|
||||
code: 'scene_asset_ready',
|
||||
targetId: 'scene-act-1',
|
||||
message: '首幕背景图已经就绪,可直接用于结果页预览。',
|
||||
},
|
||||
],
|
||||
assetCoverage: createRpgAgentAssetCoverageFixture(),
|
||||
checkpoints: [
|
||||
{
|
||||
checkpointId: 'checkpoint-foundation-v1',
|
||||
createdAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
label: '世界底稿 V1',
|
||||
},
|
||||
],
|
||||
supportedActions: createRpgAgentSupportedActionsFixture(),
|
||||
resultPreview: createRpgCreationPreviewEnvelopeFixture(),
|
||||
updatedAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
} satisfies RpgAgentSessionSnapshot);
|
||||
}
|
||||
|
||||
export function createRpgWorldLibraryEntryFixture(): CustomWorldLibraryEntry<CustomWorldProfileRecord> {
|
||||
const profile = createRpgCreationPublishedProfileFixture();
|
||||
|
||||
return cloneFixture({
|
||||
ownerUserId: RPG_CREATION_FIXTURE_USER_ID,
|
||||
profileId: RPG_CREATION_FIXTURE_PROFILE_ID,
|
||||
publicWorkCode: 'cw-fixture-001',
|
||||
authorPublicUserCode: 'sy-fixture-user',
|
||||
profile,
|
||||
visibility: 'published',
|
||||
publishedAt: RPG_CREATION_FIXTURE_PUBLISHED_AT,
|
||||
updatedAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
authorDisplayName: '测试玩家',
|
||||
worldName: String(profile.name ?? '潮雾列岛'),
|
||||
subtitle: String(profile.subtitle ?? '旧灯塔与失控航路'),
|
||||
summaryText: String(profile.summary ?? '第一版世界底稿已经整理完成。'),
|
||||
coverImageSrc:
|
||||
'/generated-custom-world-scenes/landmark-1/scene-act-1/scene.png',
|
||||
themeMode: 'tide',
|
||||
playableNpcCount: Array.isArray(profile.playableNpcs)
|
||||
? profile.playableNpcs.length
|
||||
: 0,
|
||||
landmarkCount: Array.isArray(profile.landmarks)
|
||||
? profile.landmarks.length
|
||||
: 0,
|
||||
} satisfies CustomWorldLibraryEntry<CustomWorldProfileRecord>);
|
||||
}
|
||||
|
||||
export function createRpgCreationWorksResponseFixture(): ListRpgCreationWorksResponse {
|
||||
return cloneFixture({
|
||||
items: [
|
||||
{
|
||||
workId: `draft:${RPG_CREATION_FIXTURE_SESSION_ID}`,
|
||||
sourceType: 'agent_session',
|
||||
status: 'draft',
|
||||
title: '潮雾列岛',
|
||||
subtitle: '旧灯塔与失控航路',
|
||||
summary: '第一版世界底稿已经整理完成,玩家将从回潮旧灯塔切入沉船旧案。',
|
||||
coverImageSrc: '/custom/camp/huichao.png',
|
||||
coverRenderMode: 'scene_with_roles',
|
||||
coverCharacterImageSrcs: [
|
||||
'/generated-characters/playable-1/visual/asset-runtime/master.png',
|
||||
],
|
||||
updatedAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
publishedAt: null,
|
||||
stage: 'ready_to_publish',
|
||||
stageLabel: '准备发布',
|
||||
playableNpcCount: 2,
|
||||
landmarkCount: 1,
|
||||
roleVisualReadyCount: 2,
|
||||
roleAnimationReadyCount: 2,
|
||||
roleAssetSummaryLabel: '沈砺 · 动作已就绪',
|
||||
sessionId: RPG_CREATION_FIXTURE_SESSION_ID,
|
||||
profileId: null,
|
||||
canResume: true,
|
||||
canEnterWorld: false,
|
||||
blockerCount: 0,
|
||||
publishReady: true,
|
||||
},
|
||||
{
|
||||
workId: `published:${RPG_CREATION_FIXTURE_PROFILE_ID}`,
|
||||
sourceType: 'published_profile',
|
||||
status: 'published',
|
||||
title: '潮雾列岛',
|
||||
subtitle: '旧灯塔与失控航路',
|
||||
summary: '第一版世界底稿已经整理完成,玩家将从回潮旧灯塔切入沉船旧案。',
|
||||
coverImageSrc:
|
||||
'/generated-custom-world-scenes/landmark-1/scene-act-1/scene.png',
|
||||
coverRenderMode: 'scene_with_roles',
|
||||
coverCharacterImageSrcs: [
|
||||
'/generated-characters/playable-1/visual/asset-runtime/master.png',
|
||||
],
|
||||
updatedAt: RPG_CREATION_FIXTURE_UPDATED_AT,
|
||||
publishedAt: RPG_CREATION_FIXTURE_PUBLISHED_AT,
|
||||
stage: 'published',
|
||||
stageLabel: '已发布',
|
||||
playableNpcCount: 1,
|
||||
landmarkCount: 1,
|
||||
roleVisualReadyCount: 1,
|
||||
roleAnimationReadyCount: 1,
|
||||
roleAssetSummaryLabel: '动作已就绪 1',
|
||||
sessionId: null,
|
||||
profileId: RPG_CREATION_FIXTURE_PROFILE_ID,
|
||||
canResume: false,
|
||||
canEnterWorld: true,
|
||||
blockerCount: 0,
|
||||
publishReady: true,
|
||||
},
|
||||
] satisfies RpgCreationWorkSummary[],
|
||||
} satisfies ListRpgCreationWorksResponse);
|
||||
}
|
||||
Reference in New Issue
Block a user