ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

GDevelop 嵌入式 Yarn 对话树编辑器:外部编辑器集成机制与源码实现解析

GDevelop 嵌入式 Yarn 对话树编辑器:外部编辑器集成机制与源码实现解析 GDevelop 嵌入式 Yarn 对话树编辑器外部编辑器集成机制与源码实现解析【免费下载链接】GDevelop Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop导读GDevelop 内置了 Yarn Spinner 编辑器YarnEditor让开发者无需离开 IDE 即可创建和编辑对话树Dialogue Tree。本文以 newIDE/app/public/external/yarn/README.md 为主线深入剖析该编辑器的嵌入架构、下载构建流程、浏览器/桌面双端桥接协议并结合 Extensions/DialogueTree 扩展的源码说明 Yarn JSON 对话数据如何在游戏运行时被解析与播放。读完本文你将掌握 GDevelop 外部编辑器External Editor机制的工作原理并能在自己的项目中正确使用Create with Yarn / Edit with Yarn流程。1. 概览Yarn 编辑器如何嵌入 GDevelopnewIDE/app/public/external/yarn/目录存放的是用于嵌入 Yarn Spinner 编辑器的全部宿主代码目标是让 Yarn 编辑器能直接从 GDevelop 中被打开用来编辑/创建对话树资源。目录结构如下README.md目录说明即本文依据的关联文档yarn-main.js运行编辑器的主要代码负责加载 Yarn、注入外部编辑器头部、处理消息通信yarn-index.html浏览器Web 版 GDevelop使用的入口页面yarn-electron-index.html桌面版Electron使用的入口页面yarn-style.css宿主页面的样式。从源码结构看这一模式并非 Yarn 独有GDevelop 采用统一的外部编辑器框架将 Piskel像素画、Jfxr音效和 Yarn对话树三类资源编辑器统一接入三者的宿主页面、消息协议与资源读写流程完全一致。2. 构建流程import-zipped-editor.js 下载与校验2.1 Yarn 源码的获取方式按 README 所述Yarn 编辑器的源码并非手工维护在仓库中而是由 newIDE/app/scripts/import-zipped-editor.js 脚本从 Yarn 编辑器官方构建产物中下载且保持原样、不做任何修改解压后存放在yarn-editor文件夹内即newIDE/app/public/external/yarn/yarn-editor/。该脚本的核心逻辑计算目标文件夹的 SHA256 哈希hashElement(basePath, { algo: sha256, encoding: hex })见import-zipped-editor.js#L24-L40若文件夹已存在且哈希与期望值一致则跳过下载already existing ... up-to-date否则从https://github.com/4ian/GDevelop/releases/download/vgitRelease/editor-editor.zip下载压缩包#L69-L77失败时自动重试最多 3 次retryIfFailed({ times: 3, backoff: { initialDelay: 400, factor: 2 } })使用AdmZip解压到public/external/editor/目录并删除压缩包解压后再计算一次哈希若与期望值不一致则打印警告提示第三方编辑器可能被篡改#L104-L113。2.2 命令行调用与校验值在 newIDE/app/package.json 中定义了import-zipped-external-editors脚本Yarn 相关的调用为cd scripts node import-zipped-editor.js yarn 5.0.134 ba8558cad00ec9b18cf3c6fd8647f8c1478ca67c894bca94a152a3740af209cc三个参数含义分别是参数值含义editoryarn编辑器标识同时决定目录名yarn-editor与压缩包名yarn-editor.zipgitRelease5.0.134编辑器在 GDevelop 仓库 Release 中发布的版本号用于拼接下载 URLexpectedFolderHashba8558cad00ec9b18cf3c6fd8647f8c1478ca67c894bca94a152a3740af209cc解压后yarn-editor文件夹期望的 SHA256 哈希用于完整性校验升级编辑器时的注意点若要升级第三方编辑器的 zip 包必须同时更新 package.json 中的版本号和哈希值否则脚本会因哈希不匹配而反复重新下载并给出篡改警告。这一机制既保证了构建可复现也降低了供应链被投毒的风险。3. 宿主页面与编辑器加载3.1 浏览器入口 yarn-index.htmlnewIDE/app/public/external/yarn/yarn-index.html 是一个极简页面div idexternal-editor-header/div iframe idyarn-frame/iframe script typemodule srcyarn-main.js/scriptexternal-editor-header用于渲染由 external-editor-header.js 生成的保存/取消头部yarn-frame承载 Yarn 编辑器本体指向yarn-editor/index.html的 iframeyarn-main.js以 ES Module 方式加载的主控逻辑。3.2 桌面版入口 yarn-electron-index.htmlnewIDE/app/public/external/yarn/yarn-electron-index.html 与浏览器版几乎一致区别在于所有静态资源通过gdide://自定义协议加载如gdide://external/yarn/yarn-main.js。该协议由 Electron 主进程注册用于在桌面应用中访问 IDE 的静态资源。其title为GDevelop Dialogue Tree Editor (Yarn)源码注释特别说明桌面应用会依据该标题判断用户当前焦点在主窗口IDE还是外部编辑器窗口若修改标题需同步修改 ElectronMainMenu.js 中的判断逻辑。4. 消息桥接GDevelop 与 Yarn 编辑器的通信协议4.1 三方协作架构整个外部编辑器链路由三部分协作完成对应 README 中提到的三个文件文件角色yarn-main.js运行在 Yarn 编辑器窗口中直接操作 Yarn 编辑器的内部数据 APIBrowserResourceExternalEditors.jsWeb 版的桥接层用window.openpostMessage与编辑器窗口通信LocalResourceExternalEditors.jsElectron 桌面版的桥接层通过 IPCipcRenderer.invoke与主进程通信LocalExternalEditorWindow.jsElectron 主进程侧负责真正创建承载编辑器的 BrowserWindow4.2 消息协议编辑器窗口与父窗口通过三类消息完成一次完整的打开-编辑-保存会话协议实现见yarn-main.js#L18-L97与BrowserResourceExternalEditors.js#L53-L97①external-editor-ready编辑器 → 父窗口Yarn 编辑器加载完毕后触发yarnReady事件宿主调用yarn.data.restoreFromLocalStorage(false)恢复编辑器状态然后向父窗口发送就绪信号。父窗口收到该信号后才认为编辑器真正可用BrowserResourceExternalEditors.js#L66-L86中注释说明Safari 可能不触发load事件因此以该消息作为加载完成的权威依据。②open-external-editor-input父窗口 → 编辑器父窗口通过postMessage把待编辑资源传给编辑器负载为一个ExternalEditorInput对象类型定义见 ResourceExternalEditor.js其中resources是ExternalEditorBase64Resource数组每个资源包含name资源名为空表示需要新建资源dataUrlbase64 编码的data:URL承载资源内容localFilePath本地文件路径桌面版用于覆盖已有文件而非新建extension新建文件时使用的扩展名。收到消息后yarn-main.js依次执行// 渲染头部保存/取消按钮 const externalEditorHeader createExternalEditorHeader({ ... }); // 克隆 Yarn 编辑器自带搜索框的结构注入一个自定义 Apply 按钮 const saveToGdButton yarn.document .getElementsByClassName(search-tags)[0] .cloneNode(true); saveToGdButton.onclick () saveAndClose(); saveToGdButton.childNodes[2].innerHTML Apply;这展示了嵌入式集成的常见技巧不改动第三方编辑器源码而是通过 DOM 操作在其界面上注入自己的入口按钮。// 切换编辑模式并装载数据 yarn.data.editingPath(); yarn.data.editingType(json); if (isOverwritingExistingResource) { const response await fetch(resource.dataUrl); const resourceData await response.json(); yarn.data.loadData(JSON.stringify(resourceData), json, true); externalEditorHeader.setOverwriteExistingResource(); }③save-external-editor-output编辑器 → 父窗口点击 Apply 或头部保存按钮时触发saveAndClose()const jsonString yarn.data.getSaveData(json); const dataUrl convertJsonStringToDataUrl(jsonString); // 文本 → base64 data URL sendMessageToParentEditor(save-external-editor-output, { resources: [{ name, localFilePath, extension: .json, dataUrl }], baseNameForNewResources: state.name, externalEditorData: null, }); closeWindow();同时还有一条close消息用于通知父窗口编辑器窗口已关闭。超时兜底Web 版若 10 秒内编辑器既未加载也未关闭会强制关闭窗口避免阻塞用户BrowserResourceExternalEditors.js#L135-L146。4.3 保存回写data URL → Blob URL → 项目资源父窗口收到输出后由 ResourceExternalEditor.js 中的saveBlobUrlsFromExternalEditorBase64Resources完成回写将 data URL 转成 Blob再创建blob:URL若资源名不存在则用newNameGenerator生成唯一名基于baseNameForNewResources默认Untitled创建新资源并写入扩展名等元数据若资源已存在则更新其文件内容随后调用resourceManagementProps.onFetchNewlyAddedResources()让项目持久化这些资源云端上传或本地写盘最后freeBlobsAndUpdateMetadata调用URL.revokeObjectURL释放临时 Blob URL防止内存泄漏并触发资源被外部修改事件刷新编辑器界面triggerOnResourceExternallyChanged。4.4 浏览器版与桌面版的差异浏览器版仅允许云项目使用BrowserResourceExternalEditors.js中 piskel/jfxr/yarn 三个编辑器在getStorageProvider().internalName ! Cloud时会弹出cloudProjectWarning提示并中止窗口打开必须在用户点击的同步时机内完成immediatelyOpenLoadingWindowForExternalEditor否则会被 Safari 等浏览器拦截弹窗。桌面版没有该限制本地文件直接通过fs.promises.readFile读取为data:text/plain;base64,...见LocalResourceExternalEditors.js#L128-L146并通过 IPC 的yarn-load通道ipcRenderer.invoke(yarn-load, externalEditorInput)把数据交给主进程。5. 对话树扩展运行时如何消费 Yarn JSON编辑器产出的是 Yarn JSON 格式的对话数据运行时的消费端是 Extensions/DialogueTree 扩展。其 JsExtension.js 将该扩展描述为Handle dialogue trees, made using Yarn Spinner. Useful to make complex dialogues with multiple choices. The Yarn Spinner editor is embedded in GDevelop so you can edit your dialogues without leaving GDevelop.扩展声明kind: json、元数据键yarn资源默认名为New dialogue tree见BrowserResourceExternalEditors.js#L444-L468。扩展提供的主要动作均依赖Extensions/DialogueTree/dialoguetools.js与Extensions/DialogueTree/bondage.js/dist/bondage.min.js两个运行时文件动作说明LoadDialogueFromSceneVariable从场景变量加载 Yarn JSON 对话数据通常在游戏开始时调用LoadDialogueFromJsonFile从 JSON 文件加载 Yarn JSON 对话数据StartDialogueFromBranch从指定分支branch开始对话StopRunningDialogue中断当前对话解析其中 bondage.js 是 Yarn 对话格式的解析引擎同一目录下还包含覆盖赋值、命令与函数、条件、链接、快捷键等场景的 tests 测试 JSONdialoguetools.ts则提供了运行时管理对话状态、推进节点、处理选项的辅助逻辑。由此形成的完整数据链路为Yarn 编辑器yarn-editor第三方源码 ↓ yarn-main.js 宿主注入 Apply 按钮 data API 读写 ↓ postMessage / IPC 消息协议 GDevelop 资源系统json 资源metadata 键 yarn ↓ 导出游戏时打包 dialoguetools.js bondage.min.js 游戏运行时 gdjs.dialogueTree.* 动作 ↓ 解析 Yarn JSON 分支对话、多选项、命令与变量6. 在 GDevelop 中使用与二次开发 Yarn 编辑器6.1 使用者视角在 GDevelop 资源列表中对 JSON 资源执行Create with Yarn或Edit with Yarn即可打开内置的 Yarn 编辑器编辑对话树保存后资源被回写为项目 JSON 资源随后在事件编辑器中通过 Dialogue Tree 扩展的动作加载、启动分支、停止驱动对话播放。桌面版Electron与 Web 版云项目均支持使用体验一致。6.2 二次开发者视角若要在此仓库中构建或更新 Yarn 编辑器只需执行cd newIDE/app npm run import-zipped-external-editors该命令会依次拉取并校验 piskel、jfxr、yarn 三个编辑器Yarn 版本 5.0.134见 package.json。升级 Yarn 编辑器时需把新的 zip 上传到 GDevelop 仓库的 Release 中更新脚本的gitRelease与expectedFolderHash参数并重新运行构建。6.3 关键源码索引关注点文件目录说明本文主体newIDE/app/public/external/yarn/README.md编辑器宿主主逻辑newIDE/app/public/external/yarn/yarn-main.js浏览器/桌面入口yarn-index.html、yarn-electron-index.html下载与校验脚本newIDE/app/scripts/import-zipped-editor.js资源类型与回写工具newIDE/app/src/ResourcesList/ResourceExternalEditor.jsWeb 桥接层newIDE/app/src/ResourcesList/BrowserResourceExternalEditors.js桌面桥接层newIDE/app/src/ResourcesList/LocalResourceExternalEditors.jsElectron 主进程窗口newIDE/electron-app/app/LocalExternalEditorWindow.js运行时对话扩展Extensions/DialogueTree/JsExtension.js、dialoguetools.tsYarn JSON 解析引擎Extensions/DialogueTree/bondage.js7. 小结从 newIDE/app/public/external/yarn/README.md 这份简短的目录说明出发可以看到 GDevelop 在集成第三方编辑器上的完整工程实践下载脚本 SHA256 校验保证第三方源码不被篡改统一的外部编辑器头部与消息协议ready / open-input / save-output / close让不同编辑器复用同一套宿主框架data URL 与 Blob URL 的转换链路确保资源在浏览器与桌面双端都能安全回写运行时的 Yarn 解析由 DialogueTree 扩展独立承担编辑器与运行时彻底解耦。理解这一机制无论是使用 Yarn 编辑对话树还是为 GDevelop 接入新的外部编辑器都能事半功倍。【免费下载链接】GDevelop Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.项目地址: https://gitcode.com/GitHub_Trending/gd/GDevelop创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表