mirror of
https://github.com/HappyLifeOk/cc-3-8-x-mcp.git
synced 2026-06-10 17:56:47 +00:00
feat: fix-borders 升级为通用 meta 噪音清理 + 修中文路径 bug
- 新增「纯 key 顺序/格式变化(值没变)」检测:还原成 git 原文,消 git diff 噪音 (Cocos 重启会重排 userData 里 trimType/atlasUuid 等字段位置) - 修中文路径 bug:git 调用统一加 core.quotePath=false;之前中文名图(如 1公共资源/) 的 border meta 被 git 引号转义跳过、漏还原,现已覆盖 - border 还原后若整体已等于 git 则直接写 git 原文(连带消顺序噪音) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,10 +28,12 @@ function cmdFixBorders(argv) {
|
||||
project = argv[++i];
|
||||
} else if (a === '--help' || a === '-h') {
|
||||
process.stdout.write(
|
||||
'cocos-mcp-cli fix-borders — 修复 Cocos 重启把九宫格 border 重置成 0 的 meta\n\n' +
|
||||
'cocos-mcp-cli fix-borders — 清理 Cocos 重启造成的图片 meta 噪音\n\n' +
|
||||
' --project, -p <dir> 项目路径(git 仓库或其子目录,默认当前目录)\n' +
|
||||
' --dry-run 只预览将还原哪些,不写文件\n\n' +
|
||||
'原理:扫 git 改动的 .meta,把「git 有值、工作区被清 0」的 border 还原成 git 的值。\n');
|
||||
'处理两类噪音(都靠 git 对比,正确处理中文路径):\n' +
|
||||
' 1) 纯 key 顺序/格式变化(值没变)→ 还原成 git 原文\n' +
|
||||
' 2) 九宫格 border 被重置成 0 → 用 git 的值精准还原\n');
|
||||
return;
|
||||
} else {
|
||||
die('未知参数 "' + a + '"');
|
||||
@@ -47,8 +49,8 @@ function cmdFixBorders(argv) {
|
||||
|
||||
process.stdout.write(
|
||||
(dryRun ? '[dry-run] ' : '') +
|
||||
'扫描 ' + r.scanned + ' 个改动 meta,还原 border:' +
|
||||
r.fixedFiles + ' 个 meta / ' + r.fixedFrames + ' 个 sprite-frame\n');
|
||||
'扫描 ' + r.scanned + ' 个改动 meta:顺序噪音还原 ' + r.reorderFiles +
|
||||
' 个,border 还原 ' + r.borderFiles + ' 个 meta / ' + r.borderFrames + ' frame\n');
|
||||
|
||||
if (r.details.length) {
|
||||
process.stdout.write(r.details.slice(0, 50).join('\n') + '\n');
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
// ============================================================
|
||||
// editor/fix-borders.js — 修复 Cocos 重启把图片九宫格 border 重置成 0 的 meta
|
||||
// editor/fix-borders.js — 清理 Cocos 重启/重新导入造成的图片 meta 噪音
|
||||
//
|
||||
// 现象:Cocos 重启/重新导入有时把已设九宫格的图 meta 里
|
||||
// subMetas.<hash>.userData.{borderTop,borderBottom,borderLeft,borderRight}
|
||||
// 重置成 0(九宫格丢失)。
|
||||
// 现象(Cocos 重启/重新导入有时发生):
|
||||
// 1) 纯 key 顺序/格式变化:如 userData 里 trimType/atlasUuid 等字段被重排位置,
|
||||
// 值没变,只产生 git diff 噪音。
|
||||
// 2) 九宫格 border 被重置:subMetas.<hash>.userData.{borderTop,Bottom,Left,Right}
|
||||
// 被清成 0(九宫格丢失,数据真丢)。
|
||||
//
|
||||
// 修复:扫 git 工作区改动的 .meta,找出「git 版本 border 非 0、工作区被重置成 0」的,
|
||||
// 把 git 的 border 值还原回去。靠 git 对比拿正确值,只动 border 四个字段、
|
||||
// 保留 meta 其它内容;写回用 Cocos 标准格式(2 空格缩进 + 尾随换行)。
|
||||
// 修复:扫 git 工作区改动的 .meta,逐个对比 git 版本:
|
||||
// - 值深度相等(只 key 顺序/格式不同)→ 直接还原成 git 原文,消噪音;
|
||||
// - 值不等但只是九宫格 border 被重置成 0 → 用 git 的值精准还原 border;
|
||||
// 还原后若整体已等于 git(差异仅 border + 顺序)也直接写 git 原文,否则只改 border
|
||||
// 字段、保留 meta 其它真实改动。
|
||||
//
|
||||
// 靠 git 对比拿正确值;git 调用统一带 core.quotePath=false,正确处理中文路径。
|
||||
// 纯 Node + git,跨平台。供 CLI(fix-borders-cmd)和 MCP tool 共用。
|
||||
// ============================================================
|
||||
|
||||
@@ -20,39 +25,45 @@ const cp = require('child_process');
|
||||
|
||||
const BORDER_KEYS = ['borderTop', 'borderBottom', 'borderLeft', 'borderRight'];
|
||||
|
||||
function git(root, args) {
|
||||
return cp.execFileSync('git', ['-C', root].concat(args), {
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 64 * 1024 * 1024,
|
||||
});
|
||||
}
|
||||
|
||||
// 四个 border 都为 0 / 缺失(被重置的特征)
|
||||
function allZero(ud) { return BORDER_KEYS.every(function (b) { return !ud[b]; }); }
|
||||
// 至少一个 border 非 0(git 里有正确九宫格值的特征)
|
||||
function anyNonZero(ud) { return BORDER_KEYS.some(function (b) { return !!ud[b]; }); }
|
||||
|
||||
// 深度规范化(递归排序对象 key),用于「忽略 key 顺序」的值比较
|
||||
function norm(o) {
|
||||
if (Array.isArray(o)) return o.map(norm);
|
||||
if (o && typeof o === 'object') {
|
||||
var r = {};
|
||||
Object.keys(o).sort().forEach(function (k) { r[k] = norm(o[k]); });
|
||||
return r;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function valueEqual(a, b) { return JSON.stringify(norm(a)) === JSON.stringify(norm(b)); }
|
||||
|
||||
/**
|
||||
* 扫 git 改动的 .meta,还原被 Cocos 重置成 0 的九宫格 border。
|
||||
* 清理被 Cocos 重启搞乱的 .meta(顺序噪音 + 九宫格 border 重置)。
|
||||
* @param {string} projectOrRoot 项目路径(git 仓库或其子目录均可)
|
||||
* @param {{dryRun?:boolean}} [opts]
|
||||
* @returns {{gitRoot:string, scanned:number, fixedFiles:number, fixedFrames:number, details:string[]}}
|
||||
* @returns {{gitRoot, scanned, reorderFiles, borderFiles, borderFrames, details:string[]}}
|
||||
*/
|
||||
function fixResetBorders(projectOrRoot, opts) {
|
||||
opts = opts || {};
|
||||
var dryRun = !!opts.dryRun;
|
||||
|
||||
var gitRoot;
|
||||
try {
|
||||
gitRoot = git(projectOrRoot, ['rev-parse', '--show-toplevel']).trim();
|
||||
} catch (e) {
|
||||
throw new Error('不是 git 仓库(或 git 不可用): ' + projectOrRoot);
|
||||
// 统一带 core.quotePath=false:否则 git 把中文等非 ASCII 路径加引号转义,path.join 会失配
|
||||
function git(root, args) {
|
||||
return cp.execFileSync('git', ['-C', root, '-c', 'core.quotePath=false'].concat(args),
|
||||
{ encoding: 'utf8', maxBuffer: 128 * 1024 * 1024 });
|
||||
}
|
||||
|
||||
var gitRoot;
|
||||
try { gitRoot = git(projectOrRoot, ['rev-parse', '--show-toplevel']).trim(); }
|
||||
catch (e) { throw new Error('不是 git 仓库(或 git 不可用): ' + projectOrRoot); }
|
||||
|
||||
var changed = git(gitRoot, ['diff', '--name-only', '--', '*.meta'])
|
||||
.split('\n').map(function (s) { return s.trim(); }).filter(Boolean);
|
||||
|
||||
var fixedFiles = 0, fixedFrames = 0;
|
||||
var reorderFiles = 0, borderFiles = 0, borderFrames = 0;
|
||||
var details = [];
|
||||
|
||||
for (var i = 0; i < changed.length; i++) {
|
||||
@@ -60,10 +71,19 @@ function fixResetBorders(projectOrRoot, opts) {
|
||||
var abs = path.join(gitRoot, rel);
|
||||
if (!fs.existsSync(abs)) continue;
|
||||
|
||||
var work, head;
|
||||
try { work = JSON.parse(fs.readFileSync(abs, 'utf8')); } catch (e) { continue; }
|
||||
try { head = JSON.parse(git(gitRoot, ['show', 'HEAD:' + rel])); } catch (e) { continue; } // git 里没有(新文件)跳过
|
||||
var workStr, headStr, work, head;
|
||||
try { workStr = fs.readFileSync(abs, 'utf8'); work = JSON.parse(workStr); } catch (e) { continue; }
|
||||
try { headStr = git(gitRoot, ['show', 'HEAD:' + rel]); head = JSON.parse(headStr); } catch (e) { continue; } // git 里没有(新文件)跳过
|
||||
|
||||
// 1) 纯 key 顺序/格式噪音(值深度相等)→ 还原 git 原文
|
||||
if (valueEqual(work, head)) {
|
||||
if (!dryRun) fs.writeFileSync(abs, headStr, 'utf8');
|
||||
reorderFiles++;
|
||||
details.push('[顺序] ' + rel);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2) 值不等 → 检查九宫格 border 是否被重置成 0,精准还原
|
||||
var wSubs = work && work.subMetas;
|
||||
var hSubs = head && head.subMetas;
|
||||
if (!wSubs || !hSubs || typeof wSubs !== 'object' || typeof hSubs !== 'object') continue;
|
||||
@@ -76,24 +96,31 @@ function fixResetBorders(projectOrRoot, opts) {
|
||||
var hud = hSubs[key] && hSubs[key].userData;
|
||||
if (!wud || !hud) continue;
|
||||
if (!BORDER_KEYS.some(function (b) { return b in wud; })) continue;
|
||||
|
||||
// 工作区 border 全 0、git 版本有非 0 → 被重置,还原 git 的值
|
||||
if (allZero(wud) && anyNonZero(hud)) {
|
||||
for (var b = 0; b < BORDER_KEYS.length; b++) wud[BORDER_KEYS[b]] = hud[BORDER_KEYS[b]];
|
||||
metaChanged = true;
|
||||
fixedFrames++;
|
||||
details.push(rel + ' [' + key + '] → T' + hud.borderTop + '/B' + hud.borderBottom +
|
||||
borderFrames++;
|
||||
details.push('[border] ' + rel + ' [' + key + '] → T' + hud.borderTop + '/B' + hud.borderBottom +
|
||||
'/L' + hud.borderLeft + '/R' + hud.borderRight);
|
||||
}
|
||||
}
|
||||
|
||||
if (metaChanged) {
|
||||
fixedFiles++;
|
||||
if (!dryRun) fs.writeFileSync(abs, JSON.stringify(work, null, 2) + '\n', 'utf8');
|
||||
borderFiles++;
|
||||
if (!dryRun) {
|
||||
// 还原 border 后若整体已等于 git(差异仅 border + 顺序)→ 直接写 git 原文,最干净;
|
||||
// 否则只改了 border 字段、保留其它真实改动 → 按 work 写回(Cocos 标准格式)
|
||||
if (valueEqual(work, head)) fs.writeFileSync(abs, headStr, 'utf8');
|
||||
else fs.writeFileSync(abs, JSON.stringify(work, null, 2) + '\n', 'utf8');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { gitRoot: gitRoot, scanned: changed.length, fixedFiles: fixedFiles, fixedFrames: fixedFrames, details: details };
|
||||
return {
|
||||
gitRoot: gitRoot, scanned: changed.length,
|
||||
reorderFiles: reorderFiles, borderFiles: borderFiles, borderFrames: borderFrames,
|
||||
details: details,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { fixResetBorders: fixResetBorders };
|
||||
|
||||
+1
-1
@@ -310,7 +310,7 @@ function defineTools(ctx) {
|
||||
},
|
||||
{
|
||||
name: 'meta_fix_reset_border',
|
||||
description: '修复 Cocos 重启把图片九宫格 border(subMetas.*.userData.border*)重置成 0 的 meta:扫 git 改动的 .meta,把「git 有值、工作区被清 0」的 border 还原成 git 的正确值,只动 border 字段、保留 meta 其它改动。dryRun=true 只预览不写。',
|
||||
description: '清理 Cocos 重启造成的图片 meta 噪音:① 纯 key 顺序/格式变化(值没变只 git diff 噪音)还原成 git 原文;② 九宫格 border(subMetas.*.userData.border*)被重置成 0 的精准还原 git 的值。靠 git 对比、正确处理中文路径。dryRun=true 只预览不写。',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { dryRun: { type: 'boolean', description: 'true=只预览不写文件,列出将还原的 meta' } },
|
||||
|
||||
Reference in New Issue
Block a user