6f09bf3a00
- 契约层新增 PROJECT_RESOURCE_CANVAS_SECTIONS:6 类资产分类加末尾独立的项目版本栏目,并补齐分区类型 - 契约层新增旧四 / 五栏目取值白名单、Persisted 联合类型与两个类型守卫 - Rust 契约 ProjectResourceCanvasSection 增补 7 个现行 variant 并保留 Code / Art 旧值,新增同名分区常量 - Rust 契约不升 game-creator-resource-layout.v1 版本、不给未知 section 加兜底,损坏 payload 继续失败关闭 - 新增 resourceCanvasSectionMapping.ts:旧栏目到现行分区的映射表、回落栏目与读时归一化 - 读时归一化只改写 section,x / y / manuallyPlaced 原样保留,无法归并时沿用既有丢弃行为 - resourceProjectionModel 把扩展名分类器更名为 projectedResourceKind 并收敛为准入与显示类型 - resourceProjectionModel 新增 projectResourceCanvasCategory:项目版本独立成栏、Agent 回执归文档、其余按资产分类 - Rust resource_layout 测试夹具改用现行分区值,并新增既有旧 section sidecar 仍可读取的用例 - 新增 resourceCanvasSectionMapping 测试:旧值乘目标栏目矩阵覆盖坐标保留、section 改写、changed 判定与回落列不变量 - projectResourceProjectionModel 测试新增 7 栏分区投影、项目版本独立成栏与只登记游戏代码项目落在待归类 - 同步 PRD、GameAgent 资源自由画板技术方案、AGC 实施计划与共享记忆决策记录的分区口径
120 lines
3.9 KiB
TypeScript
120 lines
3.9 KiB
TypeScript
import {
|
|
isLegacyProjectResourceCanvasSection,
|
|
isProjectResourceCanvasCategory,
|
|
type LegacyProjectResourceCanvasSection,
|
|
type PersistedProjectResourceCanvasSection,
|
|
type ProjectResourceCanvasCategory,
|
|
} from '../../../../../packages/shared/src/contracts/gameCreationApp';
|
|
|
|
/**
|
|
* 旧栏目值 → 现行分区集合。旧四 / 五栏目是「扩展名 + mediaType」口径,无法 1:1 归并到
|
|
* 6 类资产分类,因此按资源当前分区做保守归并:
|
|
*
|
|
* - `document` / `audio` / `version` 在新旧口径下同名,1:1 保留;
|
|
* - 旧 `art` 混合了 UI 交互、角色与对象、场景与环境与待归类,按资源当前分区落入其中之一;
|
|
* - 旧 `code` 在 6 类资产分类里没有对应栏目,统一落入「待归类」。
|
|
*/
|
|
export const LEGACY_RESOURCE_CANVAS_SECTION_TARGETS: Record<
|
|
LegacyProjectResourceCanvasSection,
|
|
readonly ProjectResourceCanvasCategory[]
|
|
> = {
|
|
document: ['document'],
|
|
audio: ['audio'],
|
|
version: ['version'],
|
|
art: ['ui-interaction', 'character', 'scene', 'unclassified'],
|
|
code: ['unclassified'],
|
|
};
|
|
|
|
/**
|
|
* 无法精确归并时回落到的栏目。当前分区不在目标集合内(例如资产后来被重新分类)时,
|
|
* 该坐标按今天「资源分区已变化」的既有行为丢弃,不做坐标迁移、不重置其余坐标。
|
|
*/
|
|
export const LEGACY_RESOURCE_CANVAS_SECTION_FALLBACK: Record<
|
|
LegacyProjectResourceCanvasSection,
|
|
ProjectResourceCanvasCategory
|
|
> = {
|
|
document: 'document',
|
|
audio: 'audio',
|
|
version: 'version',
|
|
art: 'unclassified',
|
|
code: 'unclassified',
|
|
};
|
|
|
|
/**
|
|
* 把磁盘上的 `section` 值归一到现行分区。
|
|
*
|
|
* 返回 `null` 表示该坐标既不属于资源的现行分区、也不在旧栏目白名单内(含无法识别的取值),
|
|
* 与今天「持久化坐标分区与资源分区不一致」的处理一致:丢弃该条坐标,不臆造新位置。
|
|
*/
|
|
export function resolveResourceCanvasSection(
|
|
section: unknown,
|
|
resourceCategory: ProjectResourceCanvasCategory,
|
|
): ProjectResourceCanvasCategory | null {
|
|
if (isProjectResourceCanvasCategory(section)) {
|
|
return section === resourceCategory ? section : null;
|
|
}
|
|
if (!isLegacyProjectResourceCanvasSection(section)) {
|
|
return null;
|
|
}
|
|
return LEGACY_RESOURCE_CANVAS_SECTION_TARGETS[section].includes(
|
|
resourceCategory,
|
|
)
|
|
? resourceCategory
|
|
: null;
|
|
}
|
|
|
|
export type NormalizedResourceCanvasPosition = {
|
|
resourceId: string;
|
|
section: ProjectResourceCanvasCategory;
|
|
x: number;
|
|
y: number;
|
|
manuallyPlaced: boolean;
|
|
};
|
|
|
|
export type NormalizedResourceCanvasPositionResult = {
|
|
position: NormalizedResourceCanvasPosition;
|
|
/**
|
|
* 该坐标的 `section` 是否被读时改写。改写后的布局与原布局逐项不同,
|
|
* 既有协调路径据此判定 `changed` 并写入一次新分区的 sidecar。
|
|
*/
|
|
changed: boolean;
|
|
};
|
|
|
|
/**
|
|
* 读时兼容映射:把一条持久化坐标归一到现行分区,原样保留 `x / y / manuallyPlaced`。
|
|
*
|
|
* 返回 `null` 表示资源不存在或该坐标无法归并,调用方不应把它放进任何分区。
|
|
*/
|
|
export function normalizeResourceCanvasPosition(
|
|
position: {
|
|
resourceId: string;
|
|
section: PersistedProjectResourceCanvasSection;
|
|
x: number;
|
|
y: number;
|
|
manuallyPlaced: boolean;
|
|
},
|
|
categoryByResourceId: ReadonlyMap<string, ProjectResourceCanvasCategory>,
|
|
): NormalizedResourceCanvasPositionResult | null {
|
|
const resourceCategory = categoryByResourceId.get(position.resourceId);
|
|
if (resourceCategory === undefined) {
|
|
return null;
|
|
}
|
|
const section = resolveResourceCanvasSection(
|
|
position.section,
|
|
resourceCategory,
|
|
);
|
|
if (section === null) {
|
|
return null;
|
|
}
|
|
return {
|
|
position: {
|
|
resourceId: position.resourceId,
|
|
section,
|
|
x: position.x,
|
|
y: position.y,
|
|
manuallyPlaced: position.manuallyPlaced,
|
|
},
|
|
changed: section !== position.section,
|
|
};
|
|
}
|