主题
SCE Client-Only Debug Skill
Use this skill to run a WasiCore map in pure client mode from an AI agent or shell. This starts the client runtime directly with -client_only; it does not start the editor UI, server, host connection, matchmaking, or CloudData.
Prefer the user's already-open target-project GUI Editor unless the user explicitly requests isolation. Diagnose its MCP connection before starting another host or client. With no open GUI, reuse a suitable Headless session; direct client launch is for explicitly client-local presentation or behavior. If server logic must run and no suitable session exists, prefer Headless single-client connected-server debug through debug-tools; lack of a GUI session alone does not select client-only mode. Follow the shared host selection rules. Client-only screenshots do not establish server-authoritative, multiplayer, or upload/start/connect behavior.
Preferred Tool
Prefer the project-local PowerShell helper when available. It is generated with this machine's launcher path and this project's client-only arguments:
powershell
$ProjectRoot = "D:\Maps\MyMap"
$Script = Join-Path $ProjectRoot 'ai\tools\Start-SceClientOnlyDebug.ps1'
if (-not (Test-Path -LiteralPath $Script)) {
$Script = Join-Path $ProjectRoot '.cursor\tools\Start-SceClientOnlyDebug.ps1'
}
if (-not (Test-Path -LiteralPath $Script)) {
$Script = Join-Path "<WasiCoreSDK>" 'docs\ai\tools\Start-SceClientOnlyDebug.ps1'
}
$PowerShellExe = Get-Command pwsh -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty Source
if ([string]::IsNullOrWhiteSpace($PowerShellExe)) {
$PowerShellExe = Get-Command powershell -ErrorAction Stop | Select-Object -First 1 -ExpandProperty Source
}
& $PowerShellExe -NoLogo -NoProfile -ExecutionPolicy Bypass -File $Script -ProjectRoot $ProjectRoot -ResolveOnly
& $PowerShellExe -NoLogo -NoProfile -ExecutionPolicy Bypass -File $Script -ProjectRoot $ProjectRootIf a project-local helper exists, prefer it. When using the SDK copy, always pass -ProjectRoot; the SDK copy only reads docs\.client-only-debug.json. Replace <WasiCoreSDK> with the local SDK path before running the fallback command.
Use -ResolveOnly first when diagnosing path issues. It prints the selected executable, working directory, arguments, and log root without starting the game. After launch, current helpers print the actual Runtime MCP bridge endpoint as runtimeMcp.endpoint, together with runtimeMcp.instanceId and runtimeMcp.discoveryPath. -ResolveOnly returns a plan (state=planned, automatic port 0), not a usable endpoint. They also report DLL freshness under appBundleDeployment.*.needsDeploy, comparing SHA256 when both build and deployed files exist. The endpoint is a local SCE runtime TCP bridge, not a standalone standard MCP host. After launch, prefer clientProcessId / clientProcess over processId when the fields are present. processId is kept for compatibility and may be the launcher process; the real game runtime is often a child sce process with -client_only, -map_path=<ProjectRoot>, and -runtime_mcp_port=0 in its command line.
Launch Rules
For a single screenshot/UI evidence pass, current helpers accept -Preview. Add -DeployClientDll to copy a previously built Client-Debug GameEntry DLL with SHA256 verification, or -ClientDllPath for another output path. The preview waits for ping, validates the live project and client-only mode, captures a unique complete PNG and UI snapshot, writes a summary plus current log tails, then closes only its own launcher/client PIDs in finally. It never builds the editor, refreshes dependency DLLs, or starts a server. See sce-preview-verify for the command and evidence checks.
-EvidenceDirectory defaults to a unique directory below the project's artifacts/preview/. -ReadyTimeoutSec defaults to 60, -CaptureTimeoutSec to 30, and -SettleMs to 1000. Screenshot size defaults to 1280x720 maximum; set -MaxWidth 0 -MaxHeight 0 for native resolution. Extra window arguments still use -ExtraArgs.
Without -Preview, the helper preserves the interactive launch behavior and leaves the client open. Track its returned client/launcher PIDs and creation times, then stop those exact processes in finally after testing. Never stop processes by name. An occupied Runtime MCP port or a running SCE process for the same project causes an actionable failure; reuse the existing session instead of killing or silently adopting it. Rebuild/copy requires stopping an owned old client before a new run, because GameEntry DLLs are not hot-reloaded.
Do not hard-code local install paths from another machine.
- Prefer
<ProjectRoot>\ai\tools\Start-SceClientOnlyDebug.ps1. It should already contain the launcher path and arguments. <ProjectRoot>\.cursor\tools\Start-SceClientOnlyDebug.ps1is a compatibility mirror for Cursor-style workspaces; use it only whenai\toolsis absent.- If using the SDK helper, it reads
<ProjectRoot>\docs\.client-only-debug.json; it does not search the editor installation. - Treat
<ProjectRoot>\docs\.editor-root,.editor-api-version, and.editor-launcheras compatibility records for troubleshooting only. - If the project-local helper or launch config is missing or stale, ask the user to open the project once in SCE Editor. Do not scan entire disks.
Paths may contain spaces and non-ASCII names; pass executable paths and arguments as separate values, not by raw string concatenation. For example, a project under C:\Users\<user>\Documents\SCE Projects\my_game must preserve the path as one argument. When constructing a raw ProcessStartInfo.Arguments string, quote the value: -map_path="C:\Users\<user>\Documents\SCE Projects\my_game". The generated helper already performs this quoting; do not bypass it with an unquoted -map_path=$ProjectRoot string.
Required Arguments
The client-only command must include:
text
-env=game
-editor_server_debug
-client_only
-editor_api_version=<api version, usually 2000>
-game=<ProjectName from project/map_settings.json>
-map_kind=0
-map_path=<ProjectRoot>
-runtime_mcp_port=0-editor_server_debug is intentionally required even though the mode is client-only. It marks the process as editor debug mode, makes Game.IsDebugTestMode true, and opens write permission for the main project user_files.
-runtime_mcp_port=0 requests an OS-assigned port. Keep fixed ports only when explicitly needed. Current helpers generate a unique Runtime instance ID and discovery path, then wait for the actual bound port. Use returned runtimeMcp.port and runtimeMcp.instanceId; direct TCP helpers must receive -Port <actual port> -RuntimeInstanceId <instance ID>. See the multi-instance connection guide.
Optional arguments:
-debug: show the client debug console/HUD if useful.-width=<pixels>and-height=<pixels>: set the startup client window client-area size, for example-ExtraArgs @('-width=1280', '-height=720')when using the helper. Use these when the user wants to preview a specific aspect ratio or simulate a mobile screen. For portrait phone checks, pass a height larger than the width, for example-ExtraArgs @('-width=390', '-height=844')for a compact device-like window or-ExtraArgs @('-width=1080', '-height=1920')for a full portrait design-resolution preview.- Extra engine arguments can be appended with the helper's
-ExtraArgs.
Build And AppBundle Deployment
The helper only starts the client process. It does not build the C# project and does not copy the latest GameEntry.dll into the runtime AppBundle.
When launching from SCE Editor's normal debug button, the editor build flow compiles both sides and copies DLLs into:
AppBundle/managed/GameEntry.dllfor server-side runtime code.ui/AppBundle/managed/GameEntry.dllfor client-side runtime code.
When launching directly from an AI agent or shell after dotnet build, do the deploy step yourself before starting the client:
powershell
$ProjectRoot = "D:\Maps\MyMap"
dotnet build (Join-Path $ProjectRoot "src\GameEntry.csproj") -c Server-Debug
dotnet build (Join-Path $ProjectRoot "src\GameEntry.csproj") -c Client-Debug
Copy-Item -LiteralPath (Join-Path $ProjectRoot "src\bin\Server-Debug\net9.0\GameEntry.dll") -Destination (Join-Path $ProjectRoot "AppBundle\managed\GameEntry.dll") -Force
Copy-Item -LiteralPath (Join-Path $ProjectRoot "src\bin\Client-Debug\net9.0\GameEntry.dll") -Destination (Join-Path $ProjectRoot "ui\AppBundle\managed\GameEntry.dll") -ForceIf this copy step is skipped, the standalone client may run an older DLL even though dotnet build succeeded. This can produce misleading runtime symptoms, including Lua or UI initialization errors that do not match the code just compiled.
Runtime Behavior
In C# client code:
csharp
if (Game.IsClientOnly)
{
// UI fake data, GameGraph preview, model/scene tests, local editor tools.
}Client-only mode cannot use Entity, Unit, CloudData, server triggers, server AI, or client-to-server gameplay messages. Pure presentation Actor types such as ActorSound, ActorModel, and ActorParticle, plus GameGraph and UI, can be used for local preview flows.
For picture-in-picture, multi-Viewport, minimap-camera, or RenderToTexture work, client-only debug is also the preferred final rendering check. Editor-embedded debug commonly uses EditorMapSSAOBloomHDR.xml, whose current default presentation does not include scene fog, while standalone clients commonly use CEMapSSAO.xml, which does. If an additional Viewport omitted SetRenderPath(...), the editor can look correct while the standalone or battle-platform client becomes fogged out. Before accepting a screenshot, require every additional/RTT Viewport to set its RenderPath explicitly and confirm the result in this standalone process.
When a client-only preview needs a game-data scene asset, call Scene.GetOrCreate(ScopeData.GameDataScene.xxx).LoadClientOnly() from a #if CLIENT and Game.IsClientOnly branch. If the preview should use the active GameMode's DefaultScene, prefer Scene.LoadDefaultClientOnly(). Projects that always need the default scene in client-only debug can set AutoLoadDefaultSceneInClientOnly = true on GameDataGameMode; it is off by default so UI-only and low-level GameGraph tests stay lightweight.
The main project user_files directory is writable in this mode because the launch includes -editor_server_debug. Dependency deps/<lib>/user_files directories and the AppBundle root remain read-only.
Runtime MCP Inspection
When the editor MCP exposes runtime_call_tool, use it after the client-only process has started to inspect the live client instead of guessing from code or user descriptions.
Useful runtime tools:
debug.ping: verify that the client runtime bridge is reachable and thatclient_onlyis true.debug.list_tools: list runtime tools registered inside the client, including project-specific tools.debug.capture_screenshot: save a live client screenshot to an explicit path for visual inspection. PassmaxWidthandmaxHeightwhen a 1080p or 720p downscaled image is enough; omit them when inspecting fine text or pixel-level details.scenegraph.materials: listStaticMeshComponentmaterials in session-owned and replicatedSceneGraphs. Pure client-only GameGraph previews usually rely on session-owned local graphs, so leaveincludeSessionenabled.material.probe: inspect one matching mesh material byquery,nodeId, and optionalmaterialIndex. UsepassNameslike["base","alpha","depth","singlelayerwater"]when comparing material techniques with RenderPath passes.ui.snapshot: read the current GameUI control tree, including text, visibility, and pixel rects.ui.find: locate controls by text, name, type, or id.ui.get_rect: get one control's screen pixel position and size for layout adjustment.
If runtime_call_tool is not visible in the current AI tool list, use ai/tools/Invoke-SceRuntimeMcp.ps1 as the direct TCP fallback. For example, run ai/tools/Invoke-SceRuntimeMcp.ps1 -Ping -Wait, then ai/tools/Invoke-SceRuntimeMcp.ps1 -ListTools, then call the needed runtime tool with -Tool and -ArgumentsJson. Add -Wait to screenshot calls so the shared fallback client waits for the fresh file; do not hand-roll file polling.
The native screenshot response normally returns pending: true before the writer finishes. A new file can already exist while incomplete. Current shared -Wait validates PNG signature, chunk boundaries, and terminal IEND before returning completion. Use a unique output path per capture, keep the runtime alive through completion, and inspect the actual image; ping success and an existing file alone do not prove a working scene.
For UI or local preview tasks, prefer this loop: build, deploy DLLs to AppBundle, launch client-only debug, call debug.ping, call debug.capture_screenshot, call debug.list_tools, call ui.snapshot or ui.find, adjust the UI code, then repeat. When 3D GameGraph content is invisible or RenderDoc suggests a material issue, call material.probe or scenegraph.materials before changing gameplay code.
Example material probe for a local SceneGraph preview:
powershell
ai/tools/Invoke-SceRuntimeMcp.ps1 -Tool material.probe -ArgumentsJson '{"query":"BlackHole","includeSession":true,"passNames":["base","alpha","depth","singlelayerwater"]}'Canvas-only rendering may not appear in the GameUI control tree. In that case, use debug.capture_screenshot as the primary signal and only use UI tools for the surrounding GameUI controls.
Verification
After launch, inspect logs under the selected executable's working directory:
text
<WorkingDirectory>/logs/client
<WorkingDirectory>/logs/lua
<WorkingDirectory>/logs/gameThe helper's JSON output includes workingDirectory and logsRoot; inspect logs from that location instead of guessing an install path.
Useful log keywords:
Client-only modeRunMode=ClientOnlyWASI user_files main preopenwritable[1]
If the window is closed, the client process should exit. If a residual SCE/sce process remains, inspect the newest client/lua logs before killing it. If an older helper reports a processId that exits quickly, do not conclude the client is gone until you have checked for a child or sibling sce process by command line. Use Get-CimInstance Win32_Process and filter on -client_only, -map_path=<ProjectRoot>, and the unique -runtime_mcp_instance=<instance ID> from this launch. Never identify ownership by port alone.