Files
AIGame/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scripts.md
T

112 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Script commands
Commands for creating C# script files, attaching MonoBehaviours to GameObjects, reading/writing serialized fields, and running compiled project entry points in memory. Writing a `.cs` file does not make its type available — Unity must import and compile it (a domain reload) first. The flow is: `create_script` → `recompile` → poll `recompile_status` (until completed/up_to_date) → `attach_script`. For bulk construction that does **not** need a new persistent project type, skip the recompile entirely: [`run_script`](#run_script) compiles a file in memory and runs it with no asset import and no domain reload.
### `create_script`
Create a new C# script (default base class MonoBehaviour) from a template under the authoring root. NOTE: the type does not exist until a recompile completes — to attach it, call recompile, poll recompile_status, then attach_script.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `name` | yes | – | Class/file name without extension, e.g. PlayerController. Must be a valid C# identifier. |
| `path` | no | `–` | Folder (relative to the authoring root; the Assets/ prefix is optional) to write the .cs into. Defaults to the authoring root. |
| `namespace` | no | `–` | Optional namespace to wrap the class in. Omit for the global namespace. |
| `base_class` | no | `MonoBehaviour` | Base class to derive from. Defaults to MonoBehaviour. |
| `overwrite` | no | `false` | Overwrite the file if it already exists. Defaults to false (an existing file is an error). |
**Returns:** `AuthoringResult`
**Notes:** Does not trigger a recompile; the created type is not usable until a recompile completes (poll `recompile_status`).
### `attach_script`
Add a MonoBehaviour to a GameObject by its (compiled) type name OR by its script asset path. Provide exactly one of 'type' or 'script'. If the type isn't compiled yet, returns a recoverable error: recompile, poll recompile_status, then retry.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | – | Reference to the GameObject to add the component to (globalId/path/guid/instanceId/hierarchyPath). |
| `type` | no | `–` | Component type name to add, e.g. PlayerController or Game.Player.PlayerController. Must already be compiled. Mutually exclusive with 'script'. |
| `script` | no | `–` | Script asset path, e.g. 'Assets/Pool/Scripts/CueShooter.cs'. The backing class is resolved via MonoScript.GetClass(), so the class name may differ from the filename. Mutually exclusive with 'type'. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able. Provide exactly one of `type` or `script`. A not-yet-compiled type returns a recoverable error (recompile, poll `recompile_status`, then retry).
### `set_serialized_field`
Set a serialized field on a component/asset. Supports primitives, enums, Vector/Color/Rect/Bounds, object references (value = an ObjectRef: asset by guid/fileId/path or scene object by instanceId/hierarchyPath), and array elements via 'name.Array.data[i]' (or 'name.Array.size' to resize).
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | – | Reference to the component or asset to modify (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given. |
| `field` | yes | – | SerializedProperty path, e.g. 'speed', 'settings.speed', or 'waypoints.Array.data[0]'. |
| `value` | yes | – | JSON value to assign. For object references pass an ObjectRef object (or null to clear). For enums pass the value name. |
| `component` | no | `–` | Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle. |
**Returns:** `AuthoringResult`
**Notes:** Undo-able.
### `get_serialized_fields`
Read serialized fields of a component/asset. Returns each top-level field's name, type and value (object references are returned as re-usable handles). Pass 'field' to read a single SerializedProperty path.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `target` | yes | – | Reference to the component or asset to read (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given. |
| `field` | no | `–` | Optional single SerializedProperty path to read (e.g. 'speed' or 'items.Array.data[0]'). Omit to read all top-level fields. |
| `component` | no | `–` | Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle. |
**Returns:** `object`
### `run_script`
Compile a single project `.cs` file in memory (no domain reload, no code carried through the
protocol) and execute a named `static` entry point. This is the **builder-pattern** path for bulk
construction — see the note below. Editor command; still arbitrary code execution, so it is grouped
under the same `scripts/eval` tag as `eval` and is disabled wherever the eval family is disabled.
| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `file` | yes | `–` | Path to a `.cs` file. Relative paths resolve against the **project root** (the parent of `Assets/`), not the process working directory. May live **outside `Assets/`** (e.g. `AgentScripts/`) so writing it never triggers an asset import or domain reload. |
| `entry` | no | `–` | Entry point as `Namespace.Type.Method` (or `Type.Method`, or a bare `Method`). Nested types may be written with dots (`Outer.Inner.Method`). Default: the single public static method if unambiguous, else a method named `Main`. Static, non-generic methods only in v1. Ephemeral mode only — rejected with `mode=hotpatch`. |
| `args` | no | `–` | JSON array of arguments, coerced to the entry's parameter types: primitives, enum names, `string[]`, and a string/object handle (`ObjectRef`) for `UnityEngine.Object` parameters. JSON `null` is only valid for reference-type and nullable parameters (never a silent `default(T)`). Ephemeral mode only — rejected with `mode=hotpatch`. |
| `mode` | no | `ephemeral` | `ephemeral`: compile to an in-memory assembly, run the entry, discard. `hotpatch`: apply in-place `[CodeReload]` method replacements to already-loaded types (delegates to `reload_file`). |
| `references` | no | `–` | Extra assembly name prefixes to reference. In the Editor all loaded assemblies are already referenced, so this is effectively a no-op there. Ephemeral mode only; **not applied** by hotpatch (the compile is `reload_file`'s). |
| `defines` | no | `–` | Extra scripting define symbols, **appended to the project's active editor defines** (`EditorUserBuildSettings.activeScriptCompilationDefines`) — so `UNITY_EDITOR`, version and platform symbols are already set and sources behave like project code; your defines extend that set rather than replace it. Ephemeral mode only; **not applied** by hotpatch. |
| `pdb` | no | `false` | Emit a portable PDB mapped to the source file so breakpoints bind. Ephemeral runs always emit source-mapped symbols so exception stack traces carry `file:line`. Compiles unoptimized. |
| `timeout_ms` | no | `30000` | Timeout in milliseconds (governs the main-thread wait budget end-to-end, like `eval`). |
| `dry_run` | no | `false` | Compile only: return diagnostics; the emitted assembly is **not loaded** into the domain and nothing executes (the response carries no `assemblyName`). Rejected with `mode=hotpatch` — a hotpatch "dry run" would still apply live method replacements. |
**Returns:** `RunScriptResponse` — `{ result, diagnostics, compileMs, executeMs, assemblyName }` on top
of the standard envelope. The result carries no echo of the source (path + diagnostics only). Compile
errors return full Roslyn diagnostics (with line/column) and execute nothing; runtime exceptions
surface as structured errors with `file:line` mapped to the source file.
**Notes:** `MainThreadRequired = true`. Editor command.
- Executing runs always compile **unoptimized (Debug codegen)** so the emitted symbols keep full
sequence points for `file:line` mapping — expect the generated code to run somewhat slower than
regular project assemblies.
- **Async entry points** (`async Task` / `Task<T>`) are awaited to completion; `Task<T>.Result`
becomes the command result and exceptions in the async work surface as runtime errors. The await
is **asynchronous** — the Editor main thread keeps pumping, so awaits that resume on Unity's
main-thread context (`Task.Yield()`, `Task.Delay()`, Awaitable, …) work naturally; no
`ConfigureAwait(false)` contortions are required. The wait is bounded by what remains of
`timeout_ms`; on expiry the command returns a `Timeout` error and the task keeps running
detached (its effects may still land), like an abandoned `eval`.
- **hotpatch specifics:** `entry`, `args` and `dry_run` are rejected (Bad Request); `references` and
`defines` are not applied. Path resolution follows `reload_file`, which probes under `Assets/`
for bare filenames (unlike ephemeral's project-root resolution). Timing: `executeMs` carries the
whole reload duration (compile + apply, not split by `reload_file`); `compileMs` is `0`. Advisory
reload diagnostics are surfaced as severity-`warning` entries on success.
- Under Unity's Mono runtime the in-memory assembly emitted by an executing `ephemeral` run is
**not** collectible/unloadable, so each run retains one small assembly (the same behavior as
`eval`); prefer a single builder entry over many tiny runs. `dry_run` loads nothing.
#### The builder pattern (bulk construction)
For bulk construction — creating many objects, wiring private fields, generating content — put the
logic in a **versioned project script** and invoke it with `run_script`. Write the file with
`write_text_file` (ideally under a non-`Assets/` folder such as `AgentScripts/` so the write triggers
no asset import), then call `run_script --file AgentScripts/Build.cs --entry Build.All`. Iterating the
script and re-running it costs an in-memory compile (< ~2s), **not** a 15–20s domain reload.
The anti-patterns this replaces: carrying construction code as escaped C# strings through `eval`
(verbose, unreviewable, shell-escaping hazards), and editing a builder under `Assets/` in a loop
(each edit pays a full domain reload). Hold the line: code goes in files on disk via `run_script`;
`eval` stays for genuinely ad-hoc one-liners.
See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md).