Skip to content

无头编辑器使用指南 ​

无头编辑器通过 MCP 提供项目创建、数据和触发器编辑、保存生成、构建,以及连接服务端的调试和发布入口。宿主不启动 WinUI 或 WebView 窗口;调试游戏的独立客户端可以有窗口。配套新版原生辅助程序解除启动时的 WinUI 加载依赖,GUI 按需加载;托管 .NET 与可视化客户端的系统要求保持原有范围。安装时仍需保留完整配套文件。

本文适用于包含 SCE.HeadlessEditor 的 Windows 编辑器包。使用前先查看当前程序的 --help 和 tools/list,确认可用参数、工具及能力配置。

从尚未创建项目开始 ​

安装根包含 sce.cmd 时,可以先执行 sce.cmd init <新项目目录>,由程序准备资源、申请项目身份、绑定 SDK 并生成 AI 上下文。已有项目使用 sce.cmd prepare <项目目录> 继续准备;只读检查使用 sce.cmd doctor --project <项目目录>。完整首次使用流程见用 AI 创建第一个游戏。先核对当前安装的 sce.cmd init --help,确认该版本支持这些命令。

本期测试版以该安装已完成官方资源下载为前提;无需预先创建游戏项目。初始化保证默认 regular 字体与关键运行包就绪,场景、地形、模型等官方素材使用现有安装资源。

生成项目后,运行 ai/tools/Invoke-SceHeadlessMcp.ps1 -Project . -Action tools -Login 可发现、核对并复用正确的 Headless 宿主。用 -Action call -Tool <工具名> -ArgumentsFile <JSON文件> 调用实际 schema 中的工具。辅助入口不接管其它项目、GUI 占用或 TriggerMcpHost;停止游戏使用本轮调试操作的停止工具,辅助入口的 -Action stop 用于停止其管理的宿主。

开发前准备最新 SDK 和文档 ​

开始一轮无头开发时,已知实际编辑器安装路径,就先使用该安装根目录的 sce.cmd prepare 联网准备项目 SDK、文档和 AI 上下文,再编辑或构建。这里的“最新”以所选安装的渠道、API 和项目已有版本约束为准,保留显式固定的依赖版本。刚刚成功执行过 init 或本轮已完成准备的项目无需重复;切换安装或需要刷新 SDK 时重新准备。

powershell
$Sce = Join-Path 'D:/Apps/Spark Editor' 'sce.cmd'
& $Sce prepare 'D:/Games/MyGame'

将示例路径替换为实际安装和项目目录。可从项目 docs/.editor-root、快捷方式或安装记录核对安装;若路径未知,先定位,仍无法确定时明确说明尚未执行准备,可基于现有 SDK 继续,但不能声称文档和 SDK 已更新,也不要猜路径或按最高缓存版本选择安装。

prepare 需要独占项目。已有 GUI 或 Headless 占用时,先保存、结束活动并正常关闭项目宿主,再准备并重新打开;不要强制关闭用户未保存的工作。同一轮连续迭代可复用已准备好的宿主。

核对命令最终 success: true、ready: true,以及 environment_prepared、ai_context_generated 结果;失败或用户文件冲突按诊断处理,保留项目身份和自定义文件。准备会刷新 src/WasiCoreSDK.props、docs/.sdk-version、docs/.editor-root 等绑定,并生成 AI 上下文、Skill 和辅助工具;随后重新读取项目 AGENTS.md / CLAUDE.md 和 docs/sdk 中的相关指南。

--offline 只使用已安装资源,不能确认线上最新 SDK。serve 或 MCP helper 启动会读取既有绑定,二进制版本检查也不会替代这一步;编辑器二进制仍通过正常更新流程安装。

准备 AI 上下文时,优先使用本机已安装的 PowerShell 7;没有时回退至系统 Windows PowerShell 5.1,不额外下载运行环境。出现 AI_CONTEXT_FAILED 时查看 diagnostics.detail 中的实际 PowerShell 路径和脚本异常,修复后对原项目重试 prepare。

切换编辑器安装或 API 后,默认连服启动记录会跟随当前安装更新;serve 只在内存选择对应路径,不改写项目。prepare 才将结果保存到 docs/.client-debug.json。新记录以 launcherBinding 区分 installation 默认启动器和 custom 自定义配置;旧记录仅在符合原生成器默认结构时迁移。自定义路径和参数保持原值,命令行显式 --client-* 优先;如需固定一个具有默认结构的旧启动器,可将该记录设为 launcherBinding: "custom"。

功能与使用范围 ​

环节功能使用边界
宿主启动、MCP、项目读写与生命周期通过 MCP 打开、编辑、保存和关闭项目无项目也可启动;按 capability 判断实际可用功能
玩家队伍同步数编、INI 和 AI 提示联动保存成功后核对三处内容
保存、代码生成与双端构建保存源数据、生成代码并构建客户端与服务端构建成功尚不等于游戏可运行
资源统计与派生产物编译资源清单,生成 Humanoid 动画及模型预烘焙碰撞需配套原生辅助程序、SDK 资源分析器和源资源;无需登录
项目自定义 Shader 预编译通过 shader_* 工具管理清单并调用独立编译进程需配套 ShaderCompile.exe、DX11 环境及公共 Shader 源码;无需登录
设备授权与授权项目创建扫码或链接登录,由服务分配授权项目身份需配置对应环境的登录与项目服务
安装账号缓存与重启复用有效账号缓存可免扫码登录按精确 editor-* 服务器名共享安装目录中的账号缓存
主动重新授权与换号入口宿主空闲时申请设备授权并更新当前账号需用户确认;处理中复用同一操作,忙碌时拒绝换号
单客户端连接服务器调试双端构建、服务器开局、客户端连接及 Runtime MCP 观测需配套原生辅助程序、客户端、资源和 Host 分配服务
上传发布准备、上传、后台结果查询与持久化发布完成须同时核对最终结果、身份、落盘及清理,见下文
历史发布恢复与收口跨宿主只读核对、同 store 接管及幂等收口只读核对不会改写原记录;可写交接需要先确认旧 owner 和资源退出
多客户端调试支持的版本可先创建游戏局,再动态启动客户端接入按实际 schema 和项目开放真人槽位操作,分别核对每个客户端的 Runtime 连接

宿主选择见开发入口规则:用户已打开目标项目的可视化编辑器时优先复用,除非用户主动要求隔离;没有已打开的 GUI 或用户要求隔离时,AI 独立开发优先 Headless,图形交互使用 GUI,客户端局部表现可用纯客户端预览。GUI 和 Headless 不要同时写同一项目;交接前先保存并结束当前活动。

多个 AI 会话共用项目 ​

支持多会话的 Headless 版本允许多个 AI 客户端连接同一个宿主、共同编辑当前项目。先查询实际安装的 headless_get_capabilities,确认 mcp.multi_session 和 mcp.operation_ownership;旧版的 WebSocket 单连接和 HTTP 请求 ID 路由不能据此视为支持多会话。

同一个项目目录只启动一个 Headless 宿主,各 AI 会话使用它返回的同一个 Editor MCP 端点。不要通过多开宿主、删除项目占用记录或更换端口来绕过项目所有权。GUI 与 Headless 的项目交接规则仍适用;GUI 多会话编辑的协调能力需单独确认。

  • HTTP 客户端从 initialize 响应头取得 Mcp-Session-Id,后续请求、初始化通知和取消通知携带该值。每个 AI 会话分别初始化,不能复制另一个会话的标识。收到未知或过期会话的 HTTP 404 后重新初始化。
  • WebSocket 每条连接分别建立会话,多条连接可并存。请求 ID 和请求取消仅在所属会话内匹配;一个客户端断开不会替换其它连接。
  • 旧版 PowerShell helper 不携带会话头时,单次 HTTP 调用使用独立的临时上下文,继续通过操作 ID 查询结果;跨请求的 JSON-RPC 取消不适用于这种调用方式。
  • 数据、触发器操作及 resources/read 由宿主统一串行执行。排队期间发生项目切换时,旧请求会被拒绝,应重新读取当前项目后再操作。
  • 调试或其它模型操作占用宿主时,资源读取也可能返回 editor_busy;待当前操作结束后重试。收到 project_context_changed 时先确认当前项目,再重新发起读取。HTTP 请求超时或会话失效都不能作为任务已停止的依据。
  • 会话断开不表示构建、调试或发布已停止。保留原操作 ID,查询其状态和清理结果;不能因响应丢失就重复启动任务。

支持操作归属的版本在项目状态和相关操作回执中返回 owner_session_id。持久会话启动的任务由该会话控制;其它会话可以查询,但直接停止或取消会返回 operation_owned_by_other_session。无会话头的旧 helper 不能停止持久会话拥有的任务,会返回 session_required_for_owned_operation;由旧 helper 启动的任务保持原有控制方式。

需要交接或断线重连后恢复控制时,先读取当前归属,再由新的持久会话显式调用:

json
{
  "operation_id": "<原操作 ID>",
  "expected_owner_session_id": "<查询得到的当前 owner_session_id>",
  "reason": "原会话已结束,接续本轮调试清理"
}

对应工具为 headless_takeover_operation,以当前安装的 schema 为准。接管只转移控制归属,不会自动停止、重启或重复上传;成功后仍使用正常的停止、取消及状态查询工具。归属已变化时返回 owner_session_mismatch,重新查询后再决定是否交接。会话归属用于协调同一宿主内的工作,不替代账号、项目和发布恢复的权限校验。

接管父操作会同时转移现有后代,之后新建的子操作继承父操作的当前归属。只接管某个子操作时,其原父操作的所属会话仍可控制该子操作;需要整条任务链统一交接时,应接管父操作并再次查询各任务状态。

这种模式共用项目数据、选择状态和 Undo/Redo 历史。各会话仍需按功能或文件分工,尤其是直接修改磁盘中的 C# 源码时;宿主的操作队列不会自动合并外部文件修改,也不会为“先读取、稍后覆盖整个对象”的操作解决内容冲突。保存生成、构建、调试和发布应约定统一负责人。

关闭宿主与更新编辑器 ​

支持二进制版本检测的版本通过 sce.cmd serve(包括 MCP helper 启动)在启动时查询当前安装渠道、API 版本和发布标签的编辑器版本。查询只读取小型版本元数据,不下载程序、不登录;有更新或查询失败均不阻断宿主启动,查询最多等待约 5 秒。启动 JSONL 的 binary_update_status 以及 headless_get_capabilities.binary_update 会记录当前版本、发布版本和检查时间。复用已有宿主时返回的是它启动时的检查结果,不会自动重复联网。

可独立执行以下命令,只查版本,不启动宿主、不安装更新:

powershell
& 'E:\WasmSCE\sce.cmd' check-update

update_available 表示需要更新;current 表示与所选渠道发布版本一致;ahead 表示本机版本较高,不执行降级。check_failed、local_version_unknown 或 not_checked 均不能当作已是最新。check-update 无法确认版本时返回退出码 2;--offline 跳过联网并返回 offline,不影响离线使用。旧版仅参数形式直接启动宿主不会进行这项检查,应改用 sce.cmd serve 或显式执行 check-update。

当前只检测和提示,尚不支持自动安装二进制;按下面的关闭步骤退出后,通过正常编辑器更新流程更新整套配套程序。SDK、模板及项目依赖的资源准备与二进制更新是不同步骤。旧包若无 check-update 命令,先正常更新编辑器。

安装根 Launcher 与版本目录中的程序均需保持配套。若客户端启动日志进入旧版残留进程清理分支并停在确认提示,核对根目录 Launcher 是否实际更新;编辑器版本号变化不代表根启动器已替换。根启动器自动更新要求有效签名,测试渠道的未签名包可能无法替换它,应使用正式签名的配套更新。

连续开发时可以复用宿主;任务结束且近期不再使用、旧版本验收结束,或需要更新编辑器二进制时,应关闭不再需要的宿主。运行中的 SCE.exe、SCE.HeadlessEditor.exe 可能占用安装目录内的程序和 DLL,阻止更新器替换文件;不要为保留登录而一直留着旧进程。

  1. 先保存项目,完成或通过原操作安全取消正在进行的任务,停止本轮调试并确认客户端、原生辅助进程及租约已清理。发布结果未知时保留恢复记录并按原流程核对。

  2. 正常关闭 GUI。由项目 helper 管理的无头宿主可在项目根执行:

    powershell
    & ./ai/tools/Invoke-SceHeadlessMcp.ps1 -Project . -Action stop

    直接从命令行启动的宿主使用原终端 Ctrl+C 或该宿主支持的协作关闭入口。helper 返回 not_owned_by_helper 表示拒绝代管关闭,不表示宿主已经退出。

  3. 按实际程序路径、PID 和启动时间核对待更新安装及其各 API 版本目录下的进程,确认宿主和属于它的辅助进程、客户端均已退出,MCP 端口也已关闭。仅连接失败不能证明进程退出;不要按模糊名称批量结束其它编辑器或强制关闭用户未保存的工作。

  4. 确认退出后再走正常编辑器更新流程,完成后从新版本重新启动。不要在旧宿主运行时覆盖已加载的 DLL。

正常关闭不会删除安装账号缓存;支持缓存复用的宿主会在下次启动时验证并复用仍有效的账号。关闭后报告实际清理结果;需要保留宿主时说明保留的是哪一个及用途。

安装与启动 ​

使用对应环境、API 版本的正式编辑器更新流程安装。完整包内应有:

text
version-<api>/
  SCE.HeadlessEditor.exe
  SCE.HeadlessEditor.dll
  SCE.HeadlessEditor.deps.json
  SCE.HeadlessEditor.runtimeconfig.json
  ...与图形编辑器共用的运行时及依赖文件
  HeadlessNativeHost.exe
  CommandTool.exe
  ShaderCompile.exe

无头程序与图形编辑器位于同一版本目录,共用运行时与依赖 DLL;保留完整版本目录,不能只复制一个 exe。旧版完整包仍可能使用 version-<api>/headless/ 布局,sce.cmd 兼容该布局,使用时应保留完整子目录。先从项目的 docs/.editor-root 或实际安装信息确认版本目录;尚未打开过的项目可以直接指定安装目录。

Headless MCP helper 1.0.1 起同样优先检查 version-<api>/SCE.HeadlessEditor.exe,仅在该文件不存在时回退到旧子目录。helper 1.0.0 若在新布局误报 headless_host_missing,需更新项目引用的 SDK helper;只更新编辑器二进制不会替换旧 SDK 工具。不要为绕过检查复制或移动程序。安装根下的 User/headless/ 保存日志、操作和宿主发现记录,是工作目录,仍会正常使用。

以下 PowerShell 示例仅启动编辑和构建宿主,不启动游戏或发起发布。将路径替换为本机已有目录;端口应与现有编辑器区分。

powershell
$versionRoot = 'C:/SCE/version-2000'
$headlessExe = Join-Path $versionRoot 'SCE.HeadlessEditor.exe'
if (-not (Test-Path -LiteralPath $headlessExe)) {
  $headlessExe = Join-Path $versionRoot 'headless/SCE.HeadlessEditor.exe'
}
& $headlessExe `
  --editor-root "$versionRoot" --mcp-mode http --mcp-port 18703

启动时通过 --project 'C:/Projects/MyGame' 打开项目。需要显式依赖位置时添加 --res-root、--sdk-version 或重复的 --lib name=path;参数含义以同一版本程序的 --help 为准。

标准输出的 mcp_ready 事件给出实际端点、进程 ID 和项目加载状态。宿主支持 http、ws、both,默认 both;此宿主不提供 --mcp-stdio。HTTP/WebSocket 接入方式见 MCP 接入指南,其中图形编辑器的 stdio 启动命令不适用于本程序。

连接后先查询 headless_get_capabilities 和 headless_get_project_state,再读取实际 tools/list schema。mcp_ready 表示服务已就绪,具体编辑、调试和发布能力仍取决于项目与依赖配置。项目为 degraded 时,应先解决依赖缺失并重开项目。

项目自定义 Shader ​

打开项目并加载依赖后,使用 shader_list_sources、shader_get_plan 和 shader_save_plan 管理 editor/shaders.precompile.json;先调用 shader_compile_project 查看 dry-run 任务,再传 apply: true 执行。宿主通过独立 ShaderCompile.exe 生成 Windows/Editor DX11、Android ESSL、iOS Metal 字节码,成功后替换项目 res/Shaders/BLGL/Compiled。失败、取消和超时保留原产物,操作不会自动上传或发布。

编译无需登录,仍要求 Windows DX11 环境。配套工具默认从宿主目录或其上一级版本目录查找,也可用 --shader-compile-executable 指定;用可重复的 --shader-include-root 指定本安装实际使用的公共 BLGL 资源根。该路径独立于日志和工作目录,宿主不会猜测公共包版本。编译期间项目切换、构建、发布准备和换号等占用操作会被拒绝。完整示例及源码约定见项目自定义 Shader 指南。

资源统计、动画与模型碰撞 ​

在包含此功能的完整编辑器包中,调用 resource_statistics_generate_animations,保存并生成当前项目代码,再编译 Client-Resource,刷新 ref/objref.txt、ref/model_animation.json 和 ref/model_collision.json。数编生成的 ref/dataref.txt 与 ref/model_animation_data.json 同样参与资源和动画清单合并。

该操作异步返回 operation_id;用 resource_statistics_status 查询,或用 resource_statistics_wait 等待同一操作。等待超时后继续查询原编号,取消使用 resource_statistics_cancel。成功须同时满足 state: succeeded 与 cleanup_pending: false;结果包含 build_id、日志目录及生成文件列表。

宿主合并项目与已加载依赖库的动画清单,通过独立 HeadlessNativeHost.exe 生成适配模型的 Humanoid 动画,写入项目 res/anim/<模型名>/...;按项目模型碰撞配置生成 block/model_collision/*.bin 和配套 .roles.dat。需要本安装的源模型、动画及参考骨架,缺失时会返回失败。此流程不要求登录,也不会启动游戏或上传项目。

准备过程独占当前项目,期间不能同时保存、切换项目、构建、调试、发布或换号。生成结果先在临时目录校验,成功后提交到项目;编译或生成失败、提交前取消不会替换现有动画和碰撞产物。cleanup_pending: true 表示辅助进程或文件清理尚未完成,应继续跟进原操作。

需要统计完直接调试时使用 debug_start_with_resource_statistics,随后通过 debug_status / debug_wait 跟进。skip_compile: true 只跳过后续双端脚本编译,资源统计和派生产物生成仍执行;必须已有可用的双端 AppBundle。启动游戏仍需调试账号与配套客户端。

依赖库可以保存、生成和构建;资源统计需使用配套 SDK 资源分析器。GUI 和 Headless 新建依赖库时,src/<项目ID>.csproj 及其程序集/DLL 名与库项目 ID 对齐,供引用项目按名称加载;普通游戏保持 GameEntry。库的运行行为应在引用它的游戏项目中调试。“发布/上传预制功能”通过 GUI 完成商店元数据及审核流程,Headless 的 project_publish_* 用于游戏项目发布。

引用带代码的库时,同时维护 libs.json 与 csproj 编译引用。本地 GUI/客户端使用 local_libs.json 覆盖库来源,Headless 的托管数据/触发器加载还需显式 --lib;编译引用路径不会作为运行时库路径。配置示例与解析规则见依赖库项目指南。

自定义库模板或 MSBuild 导入时,保持 AssemblyName 和 TargetName 与库项目 ID 一致,并核对客户端、服务端两种配置的实际输出。仅修改 DLL 文件名不能改变程序集身份。资源生成完成后,发布仍会独立校验本次源文件与派生产物;缺少所需信息时会停止准备并返回具体原因。

账号授权 ​

在普通启动参数后添加:

text
--login --publish-environment <本次目标部署环境>

部署环境必须与编辑器、项目和配套服务一致。登录在 MCP 启动之前完成,进程依次输出 JSONL login_status 事件:

state调用方应如何处理
waiting_scan优先展示完整授权链接(verification_uri_complete;TapTap 仅有基础 URL + user_code 时按下方规则拼接),并提示 expires_utc
waiting_confirmation等待用户在手机端确认
exchanging等待账号凭据交换
authenticated登录完成;继续等待 mcp_ready
failed / cancelled显示安全错误码或取消结果

二维码和链接由调用客户端展示,授权核心不要求 WinUI。登录期间 Ctrl+C 可取消;过期或拒绝后需重新运行。用户无需在聊天、命令参数或项目文件里填写 token/secret。

TapTap 设备页没有 user_code 输入框。 优先打开回执中的完整授权链接;若回执只有 verification_url(基础 /device 页)和 user_code,把当前短码做 URL 编码后拼成 verification_url?qrcode=1&user_code=<短码>(已有查询参数时用 & 合并,不重复 qrcode/user_code 键),或直接展示返回的 qrcode_url。不要打开裸 https://accounts.taptap.cn/device 让用户手填短码,也不要把示例或旧短码当成当前码。其他设备登录提供商按自己的完整链接/页面处理,不套用 TapTap 的 qrcode=1。授权链接过期后重新走一次正常登录/换号流程获取新的公开链接,不提示用户提供凭据。完成授权后继续复用已登录宿主执行编辑、调试和发布。

一次授权,多轮测试 ​

授权属于正在运行的宿主。在账号凭据仍有效、能力检查通过时,可以在同一 MCP 端点连续执行多轮编辑、构建、调试和发布查询;打开或切换项目也会保留这个宿主的登录身份。每轮调试结束后使用 debug_stop 并确认本轮客户端、helper 和租约已释放;近期还要继续开发且无需更新二进制时,可以保留托管宿主继续下一轮。需要更新或不再使用时,按关闭宿主与更新编辑器退出。已完成的发布操作可重复查询或收口,新的发布仍需有本次发布意图。

使用 --login 时,宿主先读取同一编辑器安装目录下的账号缓存并向登录服务验证,缺少有效账号或明确失效时才申请二维码/设备授权链接。隔离项目或测试不要求新建账号或默认重新登录;只有缓存缺失/明确失效或用户主动换号才申请设备授权。不要跨部署环境或账号复制 token。Headless 完成登录后也保存到 GUI 使用的同一位置,因此两个入口和后续宿主可复用有效账号。网络故障或异常服务响应会报告错误,不会据此要求重新扫码。

图形编辑器与无头宿主使用同一套 TapTap 登录凭据类型和星火账号签名机制。共享文件只由 Headless 新写平台 MAC 凭据和刷新所需信息;星火 HTTP 签名 token/token_secret 仍由每个 Headless 宿主正常交换并保留在内存中。既有 GUI 字段保留。按实际编辑器服务器名读写 User/user_info-<服务器名>.json,例如 editor-alpha.spark.xd.com、editor-xd.spark.xd.com 各自独立;不合并服务器身份,不读取或迁移 e.* 文件。

正式目录布局从程序位置推导安装根,账号文件位于其 User 目录。--editor-root 的日志和发布记录目录不改变账号位置。分离安装、本地编译或测试时可用 --account-root <安装根绝对路径> 显式选择同一安装;自定义登录服务默认不读取现有安装账号,确需共用时显式配置 --account-server <账号服务器名>。不要将账号缓存放入项目或提交到仓库。

保留已登录宿主时记下端点、PID、实际程序版本和自己的日志/操作目录。由程序通过正规账号缓存复用登录,不手工复制凭据、不从旧进程读取 token、secret 或环境,也不替换运行中已加载的 DLL。授权链接过期不表示已登录账号会话过期。

主动切换账号 ​

宿主空闲时,可通过 MCP 主动重新授权或切换账号。先检查实际宿主的 tools/list 是否包含以下入口:

工具用法
headless_account_status无参数,查看当前账号 ID、环境和最近换号状态;不读取缓存或申请授权
headless_account_switch_start无参数,宿主空闲时主动申请一次新的设备授权
headless_account_switch_status传返回的 operation_id,读取公开授权链接、二维码、有效期及终态
headless_account_switch_cancel传同一 operation_id,取消尚未进入最终提交的换号
json
{"name":"headless_account_switch_start","arguments":{}}
json
{"name":"headless_account_switch_status","arguments":{"operation_id":"<start 返回的 operation_id>"}}

发起后查询同一操作,优先展示其完整授权链接(TapTap 基础 URL + 当前 user_code 按上方规则拼接)或 qrcode_url,并提示 expires_utc,等待用户确认。处理中重复 start 返回同一操作,不重复申请;不要把 start 的 success=true 当作已换号。只有终态 state=succeeded,且 user_id 与 switch_user_id 符合用户选择时才完成。随后该宿主及项目切换继续使用新身份,创建、调试和发布查询也使用新账号;无需重启宿主。工具不接收 token、secret、登录服务地址或部署环境。

构建、创建、调试、发布准备或尚待核对/清理的发布占用期间,start 返回 account_switch_busy。先完成原操作及清理,不通过换号绕过 unknown 发布。等待授权时也不能启动新的占用操作;已有只读查询可使用其捕获的完整账号身份完成。拒绝、过期、失败或在提交前取消均保留当前宿主身份;缓存只在授权成功并通过一致性检查后更新。GUI 同时换号或注销会报并发变更,不强行覆盖或回滚 GUI 文件。最终提交开始后取消会被拒绝,应继续查询终态。若启动时指定 --user-id,新账号仍须符合该绑定。

未带 --login 启动时,注册工具和查看状态不会读取账号文件或联网;显式调用 switch_start 才发起授权。GUI 的账号文件与已经运行的 Headless 会话分别保有状态:在一个入口注销不会主动撤销另一个已认证会话。

登录服务需提供 GET/POST /api/v1/editor-device-login。宿主会先检查 GET 是否声明:

json
{"protocol":"sce-editor-device-login-v1","login_from":"editor","login_type":11}

返回 404 或协议不匹配时,会在扫码前报告 login_service_upgrade_required。请由服务管理员更新对应部署的登录服务后再试;登录成功后,项目创建和发布仍会独立检查账号权限。

常见错误:

错误码下一步
login_service_upgrade_required核对部署环境,请管理员更新配套登录服务
login_service_unavailable检查该部署登录服务的可达性
login_environment_unconfigured核对环境;自建部署需显式配置公开应用 ID 与服务地址
login_expired / login_denied用户确认后重新发起登录
login_user_id_mismatch核对显式 --user-id 与本次登录账号
login_account_cache_concurrent_changeGUI 在登录期间更改了缓存;确认当前账号后重新操作
login_account_cache_write_failed检查所选安装根的 User 目录是否可写

新建项目与玩家配置 ​

  1. 调用 project_list_templates 获取实际模板,再调用 project_create。local 模式需显式 package_name,用于本地创作;authorized 模式由已授权服务分配项目身份。自行起名的本地 ID 不能作为发布权限依据。
  2. 保存返回的 operation_id,用 project_create_status 或 project_create_wait 查询。accepted 仅表示已受理,created 才表示目录提交完成。
  3. 使用 open_after_create 时,还要等待返回的 open.operation_id 对应生命周期操作。创建成功与打开成功分别判断。
  4. 通过 data_* 工具读取本项目 GameDataPlayerSettings.PlayerSettings,编辑规范源数据 PlayerTeamData。字段和 patch 参数以当前工具 schema 和现有数据为准。
  5. 调用 data_save 或 data_save_and_generate,再核对以下三份结果。
结果应核对的内容
数编 PlayerSettings.PlayerTeamData队伍、玩家 Id、控制者与本地调试选项
config.ini[player_setting] 的玩家和队伍;[debug_setting] 的开放槽位、AI 槽位
.cursor/rules/project-info.mdcAI 可见的玩家队伍信息、队伍描述和场景上下文

Controller 使用 User / Computer;LocalTestOpen 和 LocalTestUseAI 控制本地调试投影。单客户端调试应配置本次需要的用户槽位,其余槽位按玩法保留电脑或中立设置。

图形化玩家队伍面板与上述保存路径使用同一同步实现。不要只改 config.ini,也不要只改生成的 C#。保存失败时按错误修复并重试;单个文件采用原子替换,多份文件之间尚无整体事务保证,重试后仍需核对三处结果。

配置项目横竖屏 ​

GUI 项目设置中的“横竖屏模式”保存到项目根目录的 config.ini:

ini
[map]
is_landscape = 0

0 为竖屏,1 为横屏;未配置时默认横屏。无头模式目前没有专门修改该字段的 MCP 工具,AI 可在当前项目空闲、没有调试/发布准备占用时,读取文件并只修改现有 [map] 节的 is_landscape;缺少该字段时在该节补入,避免重复节或重复键。保留文件编码、其它配置及玩家/调试 ID 集合;GUI 正在管理该项目时,通过 GUI 设置并保存。

配套新版 GUI 编辑器另提供 project_get_orientation / project_set_orientation,通过 GUI MCP 修改并保存同一字段;Headless 不实现这两个 GUI 工具。GUI 已管理项目时,优先使用其 MCP 或设置面板,详见GUI 横竖屏配置。

正常保存、生成和双端编译会保留 [map] 节,发布准备也从这里读取 is_landscape。修改后先回读确认,再通过普通编译调试流程验证;不要为配置横竖屏跳过编译、修改生成的 C#,或更改 project/map_settings.json 中的项目身份。玩家队伍应编辑数编源数据,不能据此改为只维护 INI。

项目横竖屏与桌面调试窗口尺寸分别设置。当前无头原生桥接默认请求 1280×720 的客户端窗口,本配置不等于窗口宽高自动互换;实际预览还需通过 Runtime 屏幕尺寸或截图确认。这里说明的是项目配置与发布字段,不承诺未验收的无头竖屏窗口行为。

单客户端连接服务器调试 ​

需要配套原生辅助程序、实际客户端启动记录、资源目录、账号与 Host 分配服务。--native-executable、--native-working-directory 与客户端的 --client-executable、--client-working-directory 分别配置;若客户端由 launcher 启动,应保留其真实工作目录和结构化参数,不能猜测无后缀启动记录可直接执行。

同账号调试多个项目 ​

配套新版 2.0 GUI、无头编辑器与 Host 分配服务支持按“登录账号 + 项目 ID”分配远程调试 Host。同账号不同项目可以保留各自的调试局;同账号同项目重新调试会复用 Host 并结束上一局,重新登录不会为该项目另开一台 Host。每个远程 Host 仍服务一个项目,资源不足时需等待可用 Host。

项目身份取自 project/map_settings.json 的 ProjectName。复制项目目录或改目录名不会产生新的项目身份;不要为了多开手改已授权的项目 ID。不同项目并行开发需各自的本地宿主,复用有效账号即可;同一项目仍不能由 GUI 和 Headless 同时写入。一个项目内接入多个玩家客户端,请使用下文动态客户端流程。

新版请求会核验分配服务确认的项目范围。遇到 host_lease_scope_unsupported 时,需确认服务与编辑器版本匹配,不能退回旧分配方式继续开局;host_lease_project_invalid 表示缺少有效项目身份,应先修复项目设置。旧客户端保持原分配方式,迁移前先停止旧调试局。每个项目分别保留 operation_id、游戏局 ID、客户端 PID 与 Runtime 连接信息,停止时核对目标并确认清理。

三种连接的区别 ​

连接谁使用端口安排
Editor MCPAI 连接无头编辑器,执行数据、构建和调试工具按宿主启动参数和实际就绪回执连接
Native Control无头编辑器内部控制自己的原生调试或发布辅助进程新版默认自动分配,AI 无需配置连接
Runtime MCPAI 检查或操作游戏客户端按当前工具 schema、启动参数和每个客户端的实际回执连接

配套新版无头编辑器和原生辅助程序中,--native-service-port、--publish-service-port 默认均为 0。辅助进程直接绑定操作系统分配的空闲端口,并保持监听,再通过启动回执将实际端口告知父进程。父进程核对进程 PID、服务类型和端口后,再验证项目等健康信息;日志记录最终控制端口。这些内部端口无需注册为 AI 的 MCP 服务。

需要固定端口时仍可设置正数,例如 --native-service-port 19766 --publish-service-port 19767。占用时明确失败,不会连接占用者或自动换号。启动回执缺失、无效、超时或取消时,宿主清理自己启动的辅助进程;清理未完成时按原操作继续查询。旧版默认使用 18766 / 18767,需更新完整配套编辑器包才支持自动模式,只更新 SDK helper 不会改变原生行为。

Native Control 自动分配与 --mcp-port、--runtime-mcp-port 相互独立。Headless 的 Runtime 默认值仍以安装版本为准;当前默认 18765,多个客户端应按实际 schema 显式指定各自 Runtime 端口。先检查 capability 的具体缺项,再决定启动参数。

单客户端流程 ​

准备就绪后调用 debug_start,记录 operation_id,通过 debug_status / debug_wait 跟进。正常路径复用保存、生成和双端构建;debug_start_no_compile 只适用于已经确认部署到两个 AppBundle 的当前产物。

调试时同时核对:

  • 同一 launch_id 的 Host 游戏局、客户端 PID 与已验证 Runtime target。
  • 客户端已进入游戏并有预期画面/操作,服务端日志符合本次玩法。
  • Runtime MCP 观测与同一局关联,按实际工具清单读取状态或截图。

动态启动多个客户端 ​

提供 debug_create_game、debug_attach_client、debug_clients、debug_client_stop 的版本可先创建不带客户端的游戏局,再按创建时固定的开放真人槽位启动客户端。debug_attach_client 会启动新客户端并连接已有游戏局,其 runtime_mcp_port 是该客户端的启动配置,不会动态修改已运行客户端的监听端口。

自定义调试用户 ID 写在项目 config.ini 的 [debug_setting].user_ids 中,按开放真人槽位的顺序对应,需在 debug_create_game 前设置。正常生成和编译会保留该表;没有配置时使用从 100 开始的默认 ID。这是游戏内的调试身份,与 --user-id 或登录账号不同。每个 ID 必须在 1~2147483647 内,同局不能重复;例如 1111、2222 均可使用。

例如,项目已通过玩家设置开放两个真人槽位时,在现有 [debug_setting] 内编辑该表,保留同节其它配置:

ini
user_ids = {
    1 = 1111,
    2 = 2222,
}

表中的 1、2 表示开放真人槽位的顺序。配置后正常调用 debug_create_game {"no_compile":false},保存、生成和双端编译完成后再接入客户端;无需跳过编译或在编译后重写 ID。master 下载版 7270 已验证这一完整流程。

创建游戏局后,Host 会冻结槽位与用户 ID 的对应关系。接入时可省略 user_id,使用冻结值;显式传入时必须一致。不同值返回 roster_user_id_mismatch,不会启动客户端或悄悄改用另一个 ID。需要更换 ID 时先 debug_stop,修改配置后创建新局。debug_clients 返回的 roster、requested_user_id、confirmed_user_id 可用于核对,最终还应确认 Runtime 与 Host 登录回包中的实际身份。

保留创建返回的 match_id,按工具实际 schema 传入接入和查询请求。分别核对客户端 PID、玩家身份、Runtime 端口与游戏局;不要从一个客户端的端口推断另一个客户端。单个客户端退出后可复用的游戏局仍然保留,结束整轮测试时使用 debug_stop 并确认全部自有资源清理完成。

  • debug_stop 后确认本次拥有的进程与租约已清理;cleanup_pending 需继续处理。

debug_start 启动单客户端;动态接入工具用于多客户端。启动完成后,还需按项目玩法检查实际运行结果。

双项目与固定端口组合示例 ​

为两个已有且项目 ID 不同的项目分别启动宿主。以下端口仅为示例,应先确认可用;两个宿主可复用该安装的有效登录账号。为两个项目各自配置 user_ids,再在两个终端分别运行:

powershell
& 'D:/Apps/Spark Editor/sce.cmd' serve --project 'D:/Games/ProjectA' --login --api-version 2000 --mcp-mode http --mcp-port 19731 --runtime-mcp-port 19831
& 'D:/Apps/Spark Editor/sce.cmd' serve --project 'D:/Games/ProjectB' --login --api-version 2000 --mcp-mode http --mcp-port 19732 --runtime-mcp-port 19833

等待各自 MCP 就绪并核对项目与实例 ID。先分别调用 debug_create_game {"no_compile":false},跟踪各自返回的 operation_id 至构建成功、游戏局就绪。项目 A 已开放两个真人槽位、ID 为 1111/2222,项目 B 已开放一个真人槽位、ID 为 3333 时,按各自实际 schema 调用:

目标宿主工具参数
A,19731debug_attach_client{"test_identity":"slot:1","user_id":1111,"runtime_mcp_port":19831}
A,19731debug_attach_client{"test_identity":"slot:2","runtime_mcp_port":19832},省略 ID 使用冻结的 2222
B,19732debug_attach_client{"test_identity":"slot:1","user_id":3333,"runtime_mcp_port":19833}

从 debug_clients 取得每个客户端实际的进程、连接与身份。向某个客户端转发 Runtime 工具时,用本次回执中的 port、runtime_instance_id 和 target_id 定位,再以 debug.ping 确认项目、用户 ID、game_session_id、game_started 与 host_connected;不要复用另一客户端或上一局的实例 ID。还需查看实际画面、服务端日志或快照,不能仅凭端口可连接认定调试成功。

master 下载版 7270 已完成两项目三客户端同时连服、Runtime 直连/转发及独立停止重开的组合验收:重开一个项目复用其远程 Host 并取得新局,另一项目的原局和两个客户端保持连接。结束时分别对原调试操作调用 debug_stop,等待 state=stopped、cleanup_verified=true、cleanup_pending=false,再按需关闭宿主并核对自有进程与端口退出。

上传发布与成功标准 ​

先确认目标账号、项目身份、部署环境和发布意图,再按实际 schema 调用 project_publish_start。其中 publish_environment 选择服务部署,upload_environment 选择项目运行环境,二者含义见部署环境指南。

发布环境与安装渠道 ​

  • publish_environment 必须与本机安装的部署环境一致,不能用它把项目发布到另一套后台。线上安装对应 pd;历史安装清单里可能出现 production,宿主会把它归一为 pd,不存在可以单独选择的 production 发布后端。
  • 宿主启动时先确定自己的发布环境:显式传入 --publish-environment 时直接使用;否则从 --install-root 或程序所在目录解析安装根,读取安装清单里的 env(历史值 production 归一为 pd)。能解析时自动采用该值,不再要求额外参数;只有解析不到清单环境时,project_publish_start 才返回 publish_environment_required,需要按该安装的实际渠道重启,例如 --publish-environment pd。
  • project_publish_start 里显式请求的 publish_environment 会与宿主已配置的发布环境比较,不一致时返回 publish_environment_mismatch,不会再次独立读取安装清单。后台仍按自身存储桶推导 publish_identity.environment,跨环境发布会得到无法核验的身份,宿主在开始上传前就拒绝。

宿主会独占准备过程,保存与生成项目,执行 Server-Release、Client-Release、Client-Resource,核对源文件和产物后才交给原生发布程序。准备期间避免同时修改项目。

按同一个 operation_id 使用 project_publish_status / project_publish_wait 跟进;wait 超时不代表取消,也不应再次 start。发布成功需核对以下结果:

结果成功标准
操作关联operation_id、request_id、项目与部署环境精确匹配本次操作
后台结果backend_final_result.message_type=final_result,且 finish=true、result=true
产物身份publish_identity 的项目、环境、正整数版本与实际 platform_variants 对应这次请求
持久状态state=succeeded、publish_completed=true,后续查询及磁盘记录一致
收口与清理使用下文 finalize 时,persistence_applied=true、finalization_completed=true,且 cleanup_pending=false

accepted、排队、HTTP 成功、上传完成以及单独的 finish=true 都属于不足以确认成功的证据。界面曾显示超时,也不能据此否定后台已经接收或成功的历史请求。

结果未知时,已观测到的上传受理会保留为 upload_accepted=true,且一旦为 true 不会回退。它只表示上传可能已被服务受理,不能当作成功,也不能据此清除 unknown 或恢复再次发布;反过来,字段缺失或为 false 同样不能证明没有上传。

图集、模型碰撞、场景碰撞和人形动画要求按项目真实需要处理。请求 manifest、空文件或任意 DLL 不能代替烘焙证据。服务返回 Unresolved 时保留具体原因;不能关闭实际需要的要求来强行通过。

连接中断或结果不明确时,保留 operation_id、request_id、日志及任务关联,通过状态查询核对。只有配置了后台查询能力时才能尝试相应远端补查;结果未知时不要自动重发。project_publish_cancel 的结果同样需要查询确认。

超时、历史恢复与终态收口 ​

查询当前宿主拥有的操作 ​

继续使用原 operation_id 调用 project_publish_status / project_publish_wait。正规登录宿主使用自己的账号对后台查询签名,成功证据可恢复到其自己的持久操作记录。unknown、reconciliation_required、持久化失败或 cleanup_pending 时应继续核对或清理同一操作;不要再次调用 start,也不要清空 registry 来解除阻塞。

后台恢复按原 request 精确关联任务,要求所有相关任务完成且版本有效一致、成功 final 无歧义,并有该精确版本产物的成功上传记录。缺少关联或证据时保留 unknown;公开包存在、最新版本号或时间接近都不能替代请求关联。

只读核对另一个宿主的历史记录 ​

旧宿主仍在运行时,新宿主使用自己的 --editor-root 和日志目录,额外通过 --publish-recovery-store <已存在的操作目录绝对路径> 指向旧记录目录。使用新宿主自己的正规登录,不打开项目、不启动 helper 或游戏。将下列调用中的四个占位值替换为原记录的精确值:

json
{
  "tool": "project_publish_reconcile",
  "arguments": {
    "operation_id": "<原 operation_id>",
    "project_id": "<原 project_id>",
    "request_id": "<原 request_id>",
    "environment": "<原 environment>"
  }
}

此工具至少要求 operation_id;提供其余三个字段可同时校验预期上下文。检查 backend_state=succeeded、backend_correlated=true、backend_verified=true,并核对其 final_result 与 publish_identity。返回的 source_state 是原快照状态;source_store_readonly=true、persistence_applied=false 表示仅完成后台核对,原 registry 仍可能是 unknown。该工具不导入或改写旧记录。

纯托管的 reconcile/finalize 访问登录和发布查询服务,不需要启动原生程序或额外传 GUI 的 -Server。实际调试/发布准备则需配置正式安装的资源根及对应原生能力。

将成功写回本宿主的操作记录 ​

调用 project_publish_finalize,四个字段全部必填,只能使用本宿主 registry 中已有操作:

json
{
  "tool": "project_publish_finalize",
  "arguments": {
    "operation_id": "<原 operation_id>",
    "project_id": "<原 project_id>",
    "request_id": "<原 request_id>",
    "environment": "<原 environment>"
  }
}

宿主自行从后台核验成功和产物身份,原子写入成功终态,再完成自己拥有的资源清理。参数不接受调用方提供的 final 或 identity。只有 persistence_applied=true、finalization_completed=true 且 cleanup_pending=false 才算收口完成;成功后重复调用保持终态,不会重新上传。随后再查 status,并核对原磁盘记录的 succeeded、publish_completed=true 和关联身份。

如果上传尚未发出,finalize 会先释放该宿主自己的原生侧车与租约,再重试清理;释放只结束本宿主占用的资源,操作仍保持 unknown,不会因为清理成功就允许重新发布。

对另一个宿主的只读记录调用 finalize 会被拒绝。需要接管旧 store 时,先取得交接授权,让实际旧 owner 正常退出,确认其 helper、准备 lease、子进程和相关端口已释放,再由新版用原 --editor-root 加载同一 store,并正常登录后执行 finalize。新程序可以从新完整包运行,不需要覆盖旧目录中的程序;此时不要将同一 store 同时设为自己的只读 recovery root。交接不需要复制、导入或手改操作 JSON。

新宿主在 store 生命周期持有 .publish-writer.lock。正常退出后释放句柄并保留锁文件;清理未完成时继续持有。旧版本可能没有该锁,因此“锁可打开”不能证明旧 owner 已退出,也不能据此并发启动第二个 writer。

错误或结果下一步
recovery_auth_unavailable / publish_finalization_auth_unavailable先让当前宿主正规登录;未发送后台查询
backend_permission_denied核对当前账号、目标部署和签名查询支持,保留原操作,不重发
publish_finalization_not_owned当前 registry 不拥有该操作;使用只读核对或完成正式 owner 交接
publish_finalization_context_mismatch使用原记录的精确项目、request 和环境
publish_finalization_unconfirmed核对后台证据或持久化错误,再重试同一操作
publish_cleanup_pending / cleanup_pending=true完成本操作资源清理,再重试同一操作

日志与退出 ​

配套新版默认将宿主诊断写到安装根 logs/headless。serve 的 JSONL 启动事件 diagnostics_status 给出实际 log_file、native_log_directory 和 themis_initialized;指定 --log-file 可改变托管日志位置,安装目录不可写时使用本机用户目录的日志回退路径。以启动回执为准,不要只在项目文件夹查找。

原生辅助进程的 process-*.log 保留 stdout/stderr、PID 和十六进制退出码;startup-*.log 记录早期初始化阶段,随后还有引擎日志。管道日志单文件约 2 MiB 后停止保存并继续读取。排查客户端未进入 Runtime 时,先区分托管宿主、HeadlessNativeHost.exe 与可视化客户端,再按同一 PID 和时间收集相应日志。0xC0000409 不能单独确定根因,也不能据此归因于多项目并行。

配套新版按 UTF-8 处理中文安装目录、启动器文件名与客户端日志路径。客户端快照的 log_discovery_error 单独记录日志查找失败的步骤及系统错误码,原生日志同时保留诊断;该字段不代表客户端已退出或 Runtime 不可用,应继续结合客户端状态及 Runtime 探测结果判断。启动早期尚未创建日志目录属于正常情况。

新版宿主接入 Themis 并标记进程角色、编辑器版本、API 和渠道;themis_initialized: true 只表示 SDK 初始化成功,不能当作报告已收到的证据。上报不可用时仍保留本地日志。此功能需要更新完整配套编辑器二进制;旧包不会因更新 SDK 文档而自动获得诊断能力。

构建日志位于 --editor-root 下的 logs/build,持久发布操作位于 logs/publish/operations。玩法日志位置按实际客户端与服务器会话核对,见Runtime MCP 调试指南。排查时记录版本、阶段、操作 ID 和安全错误码,避免收集原始凭据响应。

使用 Ctrl+C 请求宿主正常退出,等待其清理构建、调试与发布工作。清理失败或非零退出时检查具体残留与 cleanup_pending,不要通过重启或删除发布状态文件绕过尚未确认的操作。