feat: 增加 SpriteFrame 智能识别与自动转换容错机制,当传入 Texture2D UUID 时自动读取 meta 转为对应的子资源 SpriteFrame
This commit is contained in:
@@ -295,3 +295,13 @@
|
||||
|
||||
- **问题**: `instantiate-prefab` 中查找父节点直接调用 `cc.engine.getInstanceById(parentId)`,绕过了 `findNode` 函数的压缩 UUID 解压与兼容逻辑。
|
||||
- **修复**: 统一改用 `findNode(parentId)`,确保所有场景操作对压缩和非压缩 UUID 格式的兼容性一致。
|
||||
|
||||
---
|
||||
|
||||
## 编辑器体验与容错增强 (2026-02-28)
|
||||
|
||||
### 1. SpriteFrame 智能识别与自动转换
|
||||
|
||||
- **问题**: 当 AI 大模型尝试给 `cc.Sprite` 等组件的 `spriteFrame` 属性赋值时,常常会错误传递为其父级 `Texture2D` (原图) 的 UUID。Cocos 引擎由于类型不匹配会导致赋值无效,且静默失败(或陷入 IPC 死锁导致编辑器卡死)。
|
||||
- **优化**: 在 `scene-script.js` 中的 `applyProperties` 环节新增了类型容错机制。当识别到传入的 UUID 对应 `Texture2D` 但该属性(例如含 `sprite` 关键字)需要 `SpriteFrame` 时,脚本会利用 Node.js `fs` 直接读取对应的 `.meta` 文件,提取出实际子资源 (`SpriteFrame`) 的正确 UUID,从而实现自动转换与安全赋值。
|
||||
- **降级**: 若自动转换失败(如 `meta` 结构改变或读取失败),则会通过 `Editor.warn` 在控制台明确提示类型错误,拦截强制赋值操作,彻底消除潜在的隐性崩溃。
|
||||
|
||||
@@ -437,43 +437,68 @@ module.exports = {
|
||||
return;
|
||||
}
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
uuids.forEach((uuid, idx) => {
|
||||
if (typeof uuid !== "string" || uuid.length < 10) {
|
||||
loadedCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
// 从主进程查询是否这个 UUID 其实是一个纹理,而我们真正需要的是它的 SpriteFrame 子资源
|
||||
if (propertyType === cc.SpriteFrame || key.toLowerCase().includes("sprite")) {
|
||||
// 尝试进行自动转换:如果这是原图,且需要 SpriteFrame,自动读取其 meta 获取子 UUID
|
||||
const needsSpriteFrame =
|
||||
propertyType === cc.SpriteFrame || key.toLowerCase().includes("sprite");
|
||||
|
||||
let targetUuid = uuid;
|
||||
|
||||
if (needsSpriteFrame && Editor && Editor.assetdb && Editor.assetdb.remote) {
|
||||
try {
|
||||
const sfUuid = Editor.Ipc.sendToMainSync(
|
||||
"mcp-bridge:query-spriteframe-uuid",
|
||||
uuid,
|
||||
);
|
||||
if (sfUuid && sfUuid !== uuid) {
|
||||
uuid = sfUuid;
|
||||
Editor.log(
|
||||
`[scene-script] 识别到材质类型为 SpriteFrame,已将纹理 UUID 自动纠正为 SpriteFrame UUID: ${uuid}`,
|
||||
);
|
||||
const fspath = Editor.assetdb.remote.uuidToFspath(uuid);
|
||||
if (fspath) {
|
||||
const metaPath = fspath + ".meta";
|
||||
if (fs.existsSync(metaPath)) {
|
||||
const metaContent = fs.readFileSync(metaPath, "utf-8");
|
||||
const metaObj = JSON.parse(metaContent);
|
||||
// Creator 2.x 图片的 subMetas 里通常存储着以图片名命名的 spriteFrame
|
||||
if (metaObj && metaObj.subMetas) {
|
||||
const subKeys = Object.keys(metaObj.subMetas);
|
||||
// 如果有子 spriteFrame,提取它的 uuid
|
||||
for (const subKey of subKeys) {
|
||||
const subMeta = metaObj.subMetas[subKey];
|
||||
if (subMeta && (subMeta.uuid || subMeta.rawTextureUuid)) {
|
||||
targetUuid = subMeta.uuid;
|
||||
Editor.log(
|
||||
`[scene-script] 自动转换 UUID: ${uuid} (Texture2D) -> ${targetUuid} (SpriteFrame)`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略
|
||||
} catch (err) {
|
||||
Editor.log(`[scene-script] 读取 meta 失败: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
cc.AssetLibrary.loadAsset(uuid, (err, asset) => {
|
||||
cc.AssetLibrary.loadAsset(targetUuid, (err, asset) => {
|
||||
loadedCount++;
|
||||
if (!err && asset) {
|
||||
// 自动处理 Texture2D 到 SpriteFrame 的转换,防止由于传错了图片 UUID 导致赋值失效
|
||||
if (
|
||||
asset instanceof cc.Texture2D &&
|
||||
(propertyType === cc.SpriteFrame || key.toLowerCase().includes("sprite"))
|
||||
) {
|
||||
asset = new cc.SpriteFrame(asset);
|
||||
// 判断是否依然是 Texture2D,并且需要 SpriteFrame
|
||||
const stillIsTexture = asset instanceof cc.Texture2D && needsSpriteFrame;
|
||||
|
||||
if (stillIsTexture) {
|
||||
Editor.warn(
|
||||
`[scene-script] 拒绝为 ${key}[${idx}] 赋值:给 SpriteFrame 属性传递了 Texture2D (原图) 的 UUID ${targetUuid}。自动转换失败,请使用正确的 SpriteFrame UUID。`,
|
||||
);
|
||||
} else {
|
||||
loadedAssets[idx] = asset;
|
||||
}
|
||||
loadedAssets[idx] = asset;
|
||||
} else {
|
||||
Editor.warn(`[scene-script] 未能为 ${key}[${idx}] 加载资源 ${uuid}: ${err}`);
|
||||
Editor.warn(
|
||||
`[scene-script] 未能为 ${key}[${idx}] 加载资源 ${targetUuid}: ${err}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (loadedCount === uuids.length) {
|
||||
|
||||
Reference in New Issue
Block a user