mirror of
https://github.com/HappyLifeOk/cc-3-8-x-mcp.git
synced 2026-06-10 09:46:47 +00:00
feat: 新增 fix-borders —— 修复 Cocos 重启把九宫格 border 重置成 0 的 meta
Cocos 重启/重新导入有时把已设九宫格的图 meta 里 subMetas.*.userData.border* 重置成 0(九宫格丢失)。新增功能扫 git 改动的 .meta,把「git 有值、工作区被 清 0」的 border 还原成 git 的正确值,只动 border 字段、保留 meta 其它改动。 - cli/src/editor/fix-borders.js: 核心(git 对比 + 精准还原) - cli fix-borders 命令(main.js 注册) - MCP tool meta_fix_reset_border(main.js wrapper + server/tools.js) - 跨平台纯 JS + git,带 dry-run Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// ============================================================
|
||||
// cli/fix-borders-cmd.js — fix-borders 子命令
|
||||
//
|
||||
// 用法:
|
||||
// cocos-mcp-cli fix-borders [--project <dir>] [--dry-run]
|
||||
//
|
||||
// 修复 Cocos 重启把图片九宫格 border(subMetas.*.userData.border*)重置成 0 的 meta:
|
||||
// 扫 git 改动的 .meta,把「git 里有值、工作区被清 0」的 border 还原成 git 的值。
|
||||
// 只动 border 字段、保留 meta 其它改动。
|
||||
// --dry-run 只预览不写;--project 指定项目路径(默认当前目录)。
|
||||
// ============================================================
|
||||
|
||||
'use strict';
|
||||
|
||||
const { fixResetBorders } = require('../editor/fix-borders.js');
|
||||
|
||||
function die(msg) { process.stderr.write('Error: ' + msg + '\n'); process.exit(1); }
|
||||
|
||||
function cmdFixBorders(argv) {
|
||||
let project = process.cwd();
|
||||
let dryRun = false;
|
||||
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const a = argv[i];
|
||||
if (a === '--dry-run') {
|
||||
dryRun = true;
|
||||
} else if (a === '--project' || a === '-p') {
|
||||
project = argv[++i];
|
||||
} else if (a === '--help' || a === '-h') {
|
||||
process.stdout.write(
|
||||
'cocos-mcp-cli fix-borders — 修复 Cocos 重启把九宫格 border 重置成 0 的 meta\n\n' +
|
||||
' --project, -p <dir> 项目路径(git 仓库或其子目录,默认当前目录)\n' +
|
||||
' --dry-run 只预览将还原哪些,不写文件\n\n' +
|
||||
'原理:扫 git 改动的 .meta,把「git 有值、工作区被清 0」的 border 还原成 git 的值。\n');
|
||||
return;
|
||||
} else {
|
||||
die('未知参数 "' + a + '"');
|
||||
}
|
||||
}
|
||||
|
||||
let r;
|
||||
try {
|
||||
r = fixResetBorders(project, { dryRun: dryRun });
|
||||
} catch (e) {
|
||||
die(e.message);
|
||||
}
|
||||
|
||||
process.stdout.write(
|
||||
(dryRun ? '[dry-run] ' : '') +
|
||||
'扫描 ' + r.scanned + ' 个改动 meta,还原 border:' +
|
||||
r.fixedFiles + ' 个 meta / ' + r.fixedFrames + ' 个 sprite-frame\n');
|
||||
|
||||
if (r.details.length) {
|
||||
process.stdout.write(r.details.slice(0, 50).join('\n') + '\n');
|
||||
if (r.details.length > 50) process.stdout.write('...(共 ' + r.details.length + ' 处,此处只列前 50)\n');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { cmdFixBorders };
|
||||
+4
-1
@@ -20,6 +20,7 @@ const { cmdExtractPrefab } = require('./extract-cmd.js');
|
||||
const { cmdCompactPrefab } = require('./compact-cmd.js');
|
||||
const { cmdEnsureMeta } = require('./ensure-meta-cmd.js');
|
||||
const { cmdBuild } = require('./build-cmd.js');
|
||||
const { cmdFixBorders } = require('./fix-borders-cmd.js');
|
||||
|
||||
function die(msg) {
|
||||
process.stderr.write('Error: ' + msg + '\n');
|
||||
@@ -55,8 +56,10 @@ function main(argv) {
|
||||
cmdEnsureMeta(rest);
|
||||
} else if (cmd === 'build') {
|
||||
cmdBuild(rest);
|
||||
} else if (cmd === 'fix-borders') {
|
||||
cmdFixBorders(rest);
|
||||
} else {
|
||||
die(`未知子命令 "${cmd}",可用: query / set / batch / anim / diff / create-prefab / extract-prefab / compact-prefab / ensure-meta / build`);
|
||||
die(`未知子命令 "${cmd}",可用: query / set / batch / anim / diff / create-prefab / extract-prefab / compact-prefab / ensure-meta / build / fix-borders`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
// ============================================================
|
||||
// editor/fix-borders.js — 修复 Cocos 重启把图片九宫格 border 重置成 0 的 meta
|
||||
//
|
||||
// 现象:Cocos 重启/重新导入有时把已设九宫格的图 meta 里
|
||||
// subMetas.<hash>.userData.{borderTop,borderBottom,borderLeft,borderRight}
|
||||
// 重置成 0(九宫格丢失)。
|
||||
//
|
||||
// 修复:扫 git 工作区改动的 .meta,找出「git 版本 border 非 0、工作区被重置成 0」的,
|
||||
// 把 git 的 border 值还原回去。靠 git 对比拿正确值,只动 border 四个字段、
|
||||
// 保留 meta 其它内容;写回用 Cocos 标准格式(2 空格缩进 + 尾随换行)。
|
||||
//
|
||||
// 纯 Node + git,跨平台。供 CLI(fix-borders-cmd)和 MCP tool 共用。
|
||||
// ============================================================
|
||||
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
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]; }); }
|
||||
|
||||
/**
|
||||
* 扫 git 改动的 .meta,还原被 Cocos 重置成 0 的九宫格 border。
|
||||
* @param {string} projectOrRoot 项目路径(git 仓库或其子目录均可)
|
||||
* @param {{dryRun?:boolean}} [opts]
|
||||
* @returns {{gitRoot:string, scanned:number, fixedFiles:number, fixedFrames:number, 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);
|
||||
}
|
||||
|
||||
var changed = git(gitRoot, ['diff', '--name-only', '--', '*.meta'])
|
||||
.split('\n').map(function (s) { return s.trim(); }).filter(Boolean);
|
||||
|
||||
var fixedFiles = 0, fixedFrames = 0;
|
||||
var details = [];
|
||||
|
||||
for (var i = 0; i < changed.length; i++) {
|
||||
var rel = changed[i];
|
||||
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 wSubs = work && work.subMetas;
|
||||
var hSubs = head && head.subMetas;
|
||||
if (!wSubs || !hSubs || typeof wSubs !== 'object' || typeof hSubs !== 'object') continue;
|
||||
|
||||
var metaChanged = false;
|
||||
var keys = Object.keys(wSubs);
|
||||
for (var k = 0; k < keys.length; k++) {
|
||||
var key = keys[k];
|
||||
var wud = wSubs[key] && wSubs[key].userData;
|
||||
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 +
|
||||
'/L' + hud.borderLeft + '/R' + hud.borderRight);
|
||||
}
|
||||
}
|
||||
|
||||
if (metaChanged) {
|
||||
fixedFiles++;
|
||||
if (!dryRun) fs.writeFileSync(abs, JSON.stringify(work, null, 2) + '\n', 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
return { gitRoot: gitRoot, scanned: changed.length, fixedFiles: fixedFiles, fixedFrames: fixedFrames, details: details };
|
||||
}
|
||||
|
||||
module.exports = { fixResetBorders: fixResetBorders };
|
||||
@@ -488,6 +488,10 @@ function buildToolCtx() {
|
||||
cleanDevDir: function () { return exports.methods.cleanDevDir(); },
|
||||
getStatus: function () { return exports.methods.getStatus(); },
|
||||
reloadPackage: doRestartSelf,
|
||||
fixResetBorders: function (opts) {
|
||||
var mod = require('./cli/src/editor/fix-borders.js');
|
||||
return mod.fixResetBorders(Editor.Project.path, opts || {});
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -308,6 +308,17 @@ function defineTools(ctx) {
|
||||
return local.cleanDevDir();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'meta_fix_reset_border',
|
||||
description: '修复 Cocos 重启把图片九宫格 border(subMetas.*.userData.border*)重置成 0 的 meta:扫 git 改动的 .meta,把「git 有值、工作区被清 0」的 border 还原成 git 的正确值,只动 border 字段、保留 meta 其它改动。dryRun=true 只预览不写。',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: { dryRun: { type: 'boolean', description: 'true=只预览不写文件,列出将还原的 meta' } },
|
||||
},
|
||||
handler: async function (args) {
|
||||
return local.fixResetBorders({ dryRun: !!(args && args.dryRun) });
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user