UnityCtl.Protocol 0.1.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package UnityCtl.Protocol --version 0.1.0
                    
NuGet\Install-Package UnityCtl.Protocol -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="UnityCtl.Protocol" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="UnityCtl.Protocol" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="UnityCtl.Protocol" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add UnityCtl.Protocol --version 0.1.0
                    
#r "nuget: UnityCtl.Protocol, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package UnityCtl.Protocol@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=UnityCtl.Protocol&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=UnityCtl.Protocol&version=0.1.0
                    
Install as a Cake Tool

UnityCtl

Remote control system for Unity Editor via CLI. Control a running Unity Editor without batch mode or interruption.

Overview

UnityCtl consists of three components:

  1. unityctl (CLI) - Command-line tool for sending commands
  2. unityctl-bridge (Daemon) - Bridge daemon that coordinates between CLI and Unity
  3. Unity Editor Plugin (UPM Package) - Editor plugin that receives commands
┌─────────┐        ┌────────┐        ┌──────────────┐
│ unityctl│──HTTP──│ bridge │──WS────│ Unity Editor │
│  (CLI)  │        │(daemon)│        │   (plugin)   │
└─────────┘        └────────┘        └──────────────┘

Installation

1. Install the CLI and Bridge Tools

NuGet - UnityCtl.Cli NuGet - UnityCtl.Bridge

Install from NuGet (Recommended):

dotnet tool install -g UnityCtl.Cli
dotnet tool install -g UnityCtl.Bridge

Update existing installation:

dotnet tool update -g UnityCtl.Cli
dotnet tool update -g UnityCtl.Bridge

Uninstall:

dotnet tool uninstall -g UnityCtl.Cli
dotnet tool uninstall -g UnityCtl.Bridge

<details> <summary><b>Development Installation (from source)</b></summary>

Quick Install:

From the repository root, run the install script:

# Bash/Git Bash
./dev-install.sh

# PowerShell
.\dev-install.ps1

Manual Install:

From the repository root:

# Pack all tool projects to ./artifacts
dotnet pack

# Install as global dotnet tools
dotnet tool install -g UnityCtl.Cli --add-source ./artifacts
dotnet tool install -g UnityCtl.Bridge --add-source ./artifacts

Run Without Installing:

# Run bridge locally
dotnet run --project UnityCtl.Bridge/UnityCtl.Bridge.csproj -- --project ./unity-project

# Run CLI locally
dotnet run --project UnityCtl.Cli/UnityCtl.Cli.csproj -- --help

</details>

2. Add Unity Package

The Unity package is already added to the test project in unity-project/. For other projects:

Option A: Local Path (for development) Add to Packages/manifest.json:

{
  "dependencies": {
    "com.dirtybit.unityctl": "file:../path/to/UnityCtl.UnityPackage",
    ...
  }
}

Option B: Git URL (for production)

{
  "dependencies": {
    "com.dirtybit.unityctl": "https://github.com/DirtybitGames/unityctl.git?path=UnityCtl.UnityPackage#v0.1.0",
    ...
  }
}

Quick Start

1. Start the Bridge

From your Unity project directory:

cd unity-project
unityctl bridge start

Or if you're not in the project directory:

unityctl bridge start --project ./unity-project

Output:

Starting bridge for project: C:\Users\...\unity-project
Bridge started successfully (PID: 12345, Port: 49521)

2. Open Unity Editor

Open the Unity project in Unity Editor. The plugin will automatically connect to the bridge on startup.

Look for Unity console logs:

[UnityCtl] Connected to bridge at port 49521
[UnityCtl] Handshake complete

3. Use the CLI

Check bridge status:

unityctl bridge status

Enter play mode:

unityctl play enter

List scenes:

unityctl scene list

Load a scene:

unityctl scene load Assets/Scenes/SampleScene.unity

View console logs:

unityctl console tail --lines 20

Trigger compilation:

unityctl compile scripts

CLI Commands

Bridge Management

# Check bridge status
unityctl bridge status

# Start bridge daemon
unityctl bridge start [--project <path>]

Play Mode

# Enter play mode
unityctl play enter

# Exit play mode
unityctl play exit

# Toggle play mode
unityctl play toggle

# Get play mode status
unityctl play status

Scene Management

# List scenes in build settings
unityctl scene list

# List all scenes in project
unityctl scene list --source all

# Load a scene (single mode)
unityctl scene load Assets/Scenes/Main.unity

# Load a scene (additive mode)
unityctl scene load Assets/Scenes/Level1.unity --mode additive

Console Logs

# Show recent console logs
unityctl console tail --lines 50

# Clear the console log buffer
unityctl console clear

Asset Management

# Import a specific asset
unityctl asset import Assets/Textures/logo.png

Compilation

# Trigger script compilation
unityctl compile scripts

Global Options

# Specify project path
unityctl --project ./my-unity-project play enter

# Set agent ID (for multi-agent scenarios)
unityctl --agent-id agent-1 play enter

# Get JSON output (for scripting)
unityctl --json scene list

How It Works

Project Isolation

Each Unity project has its own bridge instance. The bridge writes a config file to .unityctl/bridge.json in the project root:

{
  "projectId": "proj-a1b2c3d4",
  "port": 49521,
  "pid": 12345
}
  • projectId: Stable hash of project path
  • port: Port the bridge is listening on
  • pid: Process ID of the bridge

The CLI auto-detects the project by walking up from the current directory to find ProjectSettings/ProjectVersion.txt.

Domain Reload Resilience

Unity's domain reload (triggered by script compilation) destroys all Editor objects. UnityCtl handles this gracefully:

  1. Bridge maintains connection and state
  2. Unity plugin reconnects after domain reload
  3. No commands are lost during reconnection

Architecture

Protocol Layer (UnityCtl.Protocol)

  • Shared message types (Hello, Request, Response, Event)
  • Config models and DTOs
  • JSON serialization helpers
  • Project detection logic

Bridge Daemon (unityctl-bridge)

  • HTTP server for CLI requests (/health, /rpc, /console/tail)
  • WebSocket server for Unity connection (/unity)
  • Log buffering (last 1000 entries)
  • Request/response matching

CLI Tool (unityctl)

  • Command-line interface using System.CommandLine
  • HTTP client for bridge communication
  • Human-readable and JSON output modes

Unity Plugin (com.dirtybit.unityctl)

  • WebSocket client for bridge connection
  • Command handlers (scenes, play mode, assets, etc.)
  • Event forwarding (logs, play mode changes, compilation)
  • Main thread action queue

Development

Quick Development Install

For local development, use the provided scripts to build and install all components:

Bash/Git Bash:

./dev-install.sh

PowerShell:

.\dev-install.ps1

These scripts will:

  1. Stop any running bridge processes
  2. Uninstall existing global tools
  3. Clean and build the solution
  4. Publish Protocol DLL to Unity package
  5. Pack all NuGet packages to ./artifacts
  6. Install the tools globally from artifacts
  7. Verify the installation

Manual Building

# Build all projects
dotnet build

# Publish Protocol DLL with dependencies for Unity (automatically copies to Unity package)
dotnet publish UnityCtl.Protocol/UnityCtl.Protocol.csproj -c Release

# Pack CLI and Bridge tools
dotnet pack

The dotnet publish command automatically copies UnityCtl.Protocol.dll to the Unity package's Plugins folder.

Project Structure

unityctl/
├── UnityCtl.Protocol/        # Shared protocol library (netstandard2.1)
├── UnityCtl.Bridge/          # Bridge daemon (net10.0)
├── UnityCtl.Cli/             # CLI tool (net10.0)
├── UnityCtl.UnityPackage/    # Unity UPM package
│   ├── package.json
│   ├── Editor/
│   │   ├── UnityCtl.asmdef
│   │   ├── UnityCtlBootstrap.cs
│   │   └── UnityCtlClient.cs
│   └── Plugins/
│       └── UnityCtl.Protocol.dll
└── unity-project/            # Test Unity project

Testing the Integration

  1. Start the bridge:

    dotnet run --project UnityCtl.Bridge/UnityCtl.Bridge.csproj -- --project ./unity-project
    
  2. Open unity-project/ in Unity Editor

  3. Run CLI commands:

    dotnet run --project UnityCtl.Cli/UnityCtl.Cli.csproj -- --project ./unity-project bridge status
    dotnet run --project UnityCtl.Cli/UnityCtl.Cli.csproj -- --project ./unity-project play enter
    

Troubleshooting

Bridge not starting

  • Check if port is already in use
  • Verify you're in a Unity project directory
  • Check bridge logs for errors

Unity not connecting

  • Ensure bridge is running (unityctl bridge status)
  • Check .unityctl/bridge.json exists in project root
  • Look for Unity console logs with [UnityCtl] prefix
  • Restart Unity Editor to trigger reconnection

Commands timing out

  • Ensure Unity Editor window has focus (some operations require it)
  • Check if Unity is responsive (not frozen)
  • Look for errors in Unity console

Domain reload issues

  • Plugin automatically reconnects after domain reload
  • Allow a few seconds after compilation before sending commands
  • Check Unity console for reconnection logs

License

MIT License - See LICENSE file for details

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.1 32 2/10/2026
0.4.0 29 2/10/2026
0.3.6 79 2/4/2026
0.3.5 81 2/3/2026
0.3.4 74 2/3/2026
0.3.3 88 1/11/2026
0.3.2 82 1/11/2026
0.3.1 87 1/9/2026
0.3.0 88 1/8/2026
0.2.2 360 11/30/2025
0.2.1 123 11/29/2025
0.2.0 180 11/27/2025
0.1.1 403 11/19/2025
0.1.0 404 11/19/2025