Integrate role asset studio into custom world agent flow
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import type { CustomWorldRoleAssetSummary } from '../../../packages/shared/src/contracts/customWorldAgent.js';
|
||||
import {
|
||||
getRoleAssetSummaryById,
|
||||
mergeRoleAssetIntoDraftProfile,
|
||||
} from './customWorldAgentRoleAssetStateService.js';
|
||||
|
||||
function toText(value: unknown) {
|
||||
return typeof value === 'string' ? value.trim() : '';
|
||||
}
|
||||
|
||||
function toRecord(value: unknown) {
|
||||
return value && typeof value === 'object' && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: null;
|
||||
}
|
||||
|
||||
function toRecordArray(value: unknown) {
|
||||
return Array.isArray(value)
|
||||
? value.filter(
|
||||
(item): item is Record<string, unknown> =>
|
||||
Boolean(item) && typeof item === 'object' && !Array.isArray(item),
|
||||
)
|
||||
: [];
|
||||
}
|
||||
|
||||
type SyncRoleAssetsPayload = {
|
||||
roleId: string;
|
||||
portraitPath: string;
|
||||
generatedVisualAssetId: string;
|
||||
generatedAnimationSetId?: string | null;
|
||||
animationMap?: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
export type SyncRoleAssetsResult = {
|
||||
roleId: string;
|
||||
updatedRole: Record<string, unknown>;
|
||||
updatedAssetSummary: CustomWorldRoleAssetSummary;
|
||||
draftProfile: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export class CustomWorldAgentAssetBridgeService {
|
||||
buildRoleAssetStudioContext(snapshot: unknown, roleId: string) {
|
||||
const profile = toRecord(snapshot);
|
||||
if (!profile) {
|
||||
throw new Error('当前世界草稿为空,无法打开角色资产工坊。');
|
||||
}
|
||||
|
||||
const playableRole = toRecordArray(profile.playableNpcs).find(
|
||||
(item) => toText(item.id) === roleId,
|
||||
);
|
||||
const storyRole = toRecordArray(profile.storyNpcs).find(
|
||||
(item) => toText(item.id) === roleId,
|
||||
);
|
||||
const role = playableRole ?? storyRole;
|
||||
if (!role) {
|
||||
throw new Error('未找到目标角色,无法进入角色资产工坊。');
|
||||
}
|
||||
|
||||
const assetSummary = getRoleAssetSummaryById(profile, roleId);
|
||||
if (!assetSummary) {
|
||||
throw new Error('未找到目标角色的资产摘要。');
|
||||
}
|
||||
|
||||
return {
|
||||
roleId,
|
||||
roleName: toText(role.name) || assetSummary.roleName,
|
||||
roleKind: playableRole ? ('playable' as const) : ('story' as const),
|
||||
startFrom:
|
||||
assetSummary.status === 'missing' ? ('visual' as const) : ('animation' as const),
|
||||
assetSummary,
|
||||
};
|
||||
}
|
||||
|
||||
applyRoleAssetPublishResult(
|
||||
snapshot: unknown,
|
||||
payload: SyncRoleAssetsPayload,
|
||||
): SyncRoleAssetsResult {
|
||||
const profile = toRecord(snapshot);
|
||||
if (!profile) {
|
||||
throw new Error('当前世界草稿为空,无法同步角色资产。');
|
||||
}
|
||||
|
||||
const { draftProfile, updatedRole } = mergeRoleAssetIntoDraftProfile(
|
||||
profile,
|
||||
payload,
|
||||
);
|
||||
const assetSummary = getRoleAssetSummaryById(draftProfile, payload.roleId);
|
||||
if (!assetSummary) {
|
||||
throw new Error('角色资产同步后未能生成新的资产摘要。');
|
||||
}
|
||||
|
||||
return {
|
||||
roleId: payload.roleId,
|
||||
updatedRole,
|
||||
updatedAssetSummary: assetSummary,
|
||||
draftProfile,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user