fix: 修复日志持久化代码丢失,更新 README 补充属性保护和 AI 容错特性

This commit is contained in:
火焰库拉
2026-02-27 23:30:17 +08:00
parent c41c07477c
commit 42ab8d8ee2
2 changed files with 2550 additions and 2501 deletions

View File

@@ -30,6 +30,8 @@
- **特效管理**: 创建和修改粒子系统 - **特效管理**: 创建和修改粒子系统
- **并发安全**: 指令队列串行化执行,防止编辑器卡死 - **并发安全**: 指令队列串行化执行,防止编辑器卡死
- **超时保护**: IPC 通信和指令队列均有超时兜底机制 - **超时保护**: IPC 通信和指令队列均有超时兜底机制
- **属性保护**: 组件核心属性黑名单机制,防止 AI 篡改 `node`/`uuid` 等引用导致崩溃
- **AI 容错**: 参数别名映射(`operation``action``save``update`/`write`),兼容大模型幻觉
- **工具说明**: 测试面板提供详细的工具描述和参数说明 - **工具说明**: 测试面板提供详细的工具描述和参数说明
## 安装与使用 ## 安装与使用

57
main.js
View File

@@ -92,25 +92,72 @@ function callSceneScriptWithTimeout(pluginName, method, args, callback, timeout
} }
/** /**
* 封装日志函数,同时发送给面板、保存到内存并在编辑器控制台打印 * 日志文件路径(懒初始化,在项目 settings 目录下)
* @param {'info' | 'success' | 'warn' | 'error'} type 日志类型 * @type {string|null}
*/
let _logFilePath = null;
/**
* 获取日志文件路径
* @returns {string|null}
*/
function getLogFilePath() {
if (_logFilePath) return _logFilePath;
try {
const assetsPath = Editor.assetdb.urlToFspath("db://assets");
if (assetsPath) {
const projectRoot = pathModule.dirname(assetsPath);
const settingsDir = pathModule.join(projectRoot, "settings");
if (!fs.existsSync(settingsDir)) {
fs.mkdirSync(settingsDir, { recursive: true });
}
_logFilePath = pathModule.join(settingsDir, "mcp-bridge.log");
return _logFilePath;
}
} catch (e) {
// 静默失败,不影响主流程
}
return null;
}
/**
* 封装日志函数
* - 所有日志发送到 MCP 测试面板 + 内存缓存
* - 仅 error / warn 输出到编辑器控制台(防止刷屏)
* - 所有日志实时追加写入项目内 settings/mcp-bridge.log 文件(持久化)
* @param {'info' | 'success' | 'warn' | 'error' | 'mcp'} type 日志类型
* @param {string} message 日志内容 * @param {string} message 日志内容
*/ */
function addLog(type, message) { function addLog(type, message) {
const logEntry = { const logEntry = {
time: new Date().toLocaleTimeString(), time: new Date().toISOString().replace("T", " ").substring(0, 23),
type: type, type: type,
content: message, content: message,
}; };
logBuffer.push(logEntry); logBuffer.push(logEntry);
// 防止内存泄漏:限制日志缓存上限
if (logBuffer.length > 2000) {
logBuffer = logBuffer.slice(-1500);
}
// 发送到面板
Editor.Ipc.sendToPanel("mcp-bridge", "mcp-bridge:on-log", logEntry); Editor.Ipc.sendToPanel("mcp-bridge", "mcp-bridge:on-log", logEntry);
// 【修改】确保所有日志都输出到编辑器控制台,以便用户查看 // 仅关键信息输出到编辑器控制台error / warn
if (type === "error") { if (type === "error") {
Editor.error(`[MCP] ${message}`); Editor.error(`[MCP] ${message}`);
} else if (type === "warn") { } else if (type === "warn") {
Editor.warn(`[MCP] ${message}`); Editor.warn(`[MCP] ${message}`);
} else { }
// 持久化到日志文件(实时写入,确保闪退时不丢失)
try {
const logPath = getLogFilePath();
if (logPath) {
const line = `[${logEntry.time}] [${type}] ${message}\n`;
fs.appendFileSync(logPath, line, "utf8");
}
} catch (e) {
// 文件写入失败时静默,不影响主流程
} }
} }