This commit is contained in:
2026-04-27 22:50:18 +08:00
parent ded6f6ee2a
commit b6c6640548
77 changed files with 5240 additions and 833 deletions

View File

@@ -13,6 +13,7 @@ import {
normalizeCustomWorldLockState,
} from '../services/customWorldCreatorIntent';
import { normalizeCustomWorldOwnedSettingLayers } from '../services/customWorldOwnedSettingLayers';
import { resolveCustomWorldRoleIdReference } from '../services/customWorldRoleReferences';
import {
AnimationState,
CharacterAnimationConfig,
@@ -971,18 +972,30 @@ function normalizeSceneActBlueprint(
value: unknown,
index: number,
sceneId: string,
profileRoles?: {
playableNpcs: CustomWorldPlayableNpc[];
storyNpcs: CustomWorldNpc[];
} | null,
): SceneActBlueprint | null {
if (!isRecord(value)) {
return null;
}
const encounterNpcIds = toStringArray(value.encounterNpcIds);
const encounterNpcIds = toStringArray(value.encounterNpcIds).map((npcId) =>
resolveCustomWorldRoleIdReference(profileRoles, npcId),
);
const stageCoverage = normalizeSceneActStageCoverage(value.stageCoverage);
const advanceRule = toText(value.advanceRule);
const title = toText(value.title);
const summary = toText(value.summary);
const primaryNpcId = toText(value.primaryNpcId, encounterNpcIds[0] ?? '');
const oppositeNpcId = toText(value.oppositeNpcId, primaryNpcId);
const primaryNpcId = resolveCustomWorldRoleIdReference(
profileRoles,
toText(value.primaryNpcId, encounterNpcIds[0] ?? ''),
);
const oppositeNpcId = resolveCustomWorldRoleIdReference(
profileRoles,
toText(value.oppositeNpcId, primaryNpcId),
);
if (!title && !summary && encounterNpcIds.length === 0) {
return null;
@@ -1020,7 +1033,13 @@ function normalizeSceneActBlueprint(
};
}
function normalizeSceneChapterBlueprints(value: unknown) {
function normalizeSceneChapterBlueprints(
value: unknown,
profileRoles?: {
playableNpcs: CustomWorldPlayableNpc[];
storyNpcs: CustomWorldNpc[];
} | null,
) {
if (!Array.isArray(value)) {
return null;
}
@@ -1036,7 +1055,12 @@ function normalizeSceneChapterBlueprints(value: unknown) {
const acts = Array.isArray(entry.acts)
? entry.acts
.map((act, actIndex) =>
normalizeSceneActBlueprint(act, actIndex, sceneId),
normalizeSceneActBlueprint(
act,
actIndex,
sceneId,
profileRoles,
),
)
.filter((act): act is SceneActBlueprint => Boolean(act))
: [];
@@ -1126,6 +1150,11 @@ function normalizeProfile(value: unknown): CustomWorldProfile | null {
.filter((entry): entry is CustomWorldLandmarkDraft => Boolean(entry))
: [];
const playableNpcs = Array.isArray(value.playableNpcs)
? value.playableNpcs
.map((entry, index) => normalizePlayableNpc(entry, index))
.filter((entry): entry is CustomWorldPlayableNpc => Boolean(entry))
: [];
const normalizedProfile = {
id: toText(value.id, `saved-custom-world-${Date.now().toString(36)}`),
settingText,
@@ -1144,11 +1173,7 @@ function normalizeProfile(value: unknown): CustomWorldProfile | null {
value.attributeSchema,
generatedAttributeSchema,
),
playableNpcs: Array.isArray(value.playableNpcs)
? value.playableNpcs
.map((entry, index) => normalizePlayableNpc(entry, index))
.filter((entry): entry is CustomWorldPlayableNpc => Boolean(entry))
: [],
playableNpcs,
storyNpcs,
items: Array.isArray(value.items)
? value.items
@@ -1168,6 +1193,10 @@ function normalizeProfile(value: unknown): CustomWorldProfile | null {
preserveStructuredRecordArray<ThreadContract>(value.threadContracts),
sceneChapterBlueprints: normalizeSceneChapterBlueprints(
value.sceneChapterBlueprints,
{
playableNpcs,
storyNpcs,
},
),
anchorContent: preserveStructuredRecord<EightAnchorContent>(
value.anchorContent,