Skip to content

Commit 987e0f2

Browse files
committed
Release v0.3.5
1 parent 12aa50f commit 987e0f2

8 files changed

Lines changed: 61 additions & 24 deletions

File tree

docs/ref/ai-quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Open (or restart) the Unity Editor after running this command. For contributor w
2323

2424
```bash
2525
unityctl init --project "/path/to/unity/project" --source /path/to/unityctl/src/Unityctl.Plugin
26-
unityctl init --project "/path/to/unity/project" --source "https://github.com/Jason-hub-star/unityctl.git?path=/src/Unityctl.Plugin#v0.3.4"
26+
unityctl init --project "/path/to/unity/project" --source "https://github.com/Jason-hub-star/unityctl.git?path=/src/Unityctl.Plugin#v0.3.5"
2727
```
2828

2929
### 3. Verify

docs/ref/getting-started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ If you need a contributor-style source install instead, you can still do one of
7979

8080
```bash
8181
unityctl init --project /path/to/unity/project --source /path/to/unityctl/src/Unityctl.Plugin
82-
unityctl init --project /path/to/unity/project --source "https://github.com/Jason-hub-star/unityctl.git?path=/src/Unityctl.Plugin#v0.3.4"
82+
unityctl init --project /path/to/unity/project --source "https://github.com/Jason-hub-star/unityctl.git?path=/src/Unityctl.Plugin#v0.3.5"
8383
```
8484

8585
When switching away from an older `file:` install, first run:

src/Unityctl.Mcp/Prompts/GameWorkflowPrompts.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ 2. Confirm Unity Editor is open with the target project
155155
## Step 2: Install Plugin
156156
3. unityctl_run(command="init") with parameters:
157157
- project: "/path/to/unity/project"
158-
- source: "https://github.com/Jason-hub-star/unityctl.git?path=/src/Unityctl.Plugin#v0.3.4"
158+
- source: "https://github.com/Jason-hub-star/unityctl.git?path=/src/Unityctl.Plugin#v0.3.5"
159159
4. Restart Unity Editor (or wait for domain reload)
160160
161161
## Step 3: Verify

src/Unityctl.Plugin/Editor/Commands/PingHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public CommandResponse Execute(CommandRequest request)
1111
{
1212
var data = new JObject
1313
{
14-
["version"] = "0.3.4",
14+
["version"] = "0.3.5",
1515
#if UNITY_EDITOR
1616
["unityVersion"] = UnityEngine.Application.unityVersion
1717
#endif

src/Unityctl.Plugin/Editor/Ipc/IpcServer.cs

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ namespace Unityctl.Plugin.Editor.Ipc
2222
/// </summary>
2323
public sealed class IpcServer
2424
{
25+
private enum ShutdownMode
26+
{
27+
Graceful,
28+
EditorQuit
29+
}
30+
2531
private const int MaxServerInstances = 4;
2632
private const int PipeBusyRetryDelayMs = 250;
2733
private const int ErrorPipeBusy = 231;
@@ -78,7 +84,7 @@ public void Start(string projectPath)
7884
if (IsRunning && _pipeName == pipeName) return;
7985

8086
// Different project or not running — stop existing, start new
81-
if (IsRunning) StopInternal();
87+
if (IsRunning) StopInternal(ShutdownMode.Graceful);
8288

8389
_projectPath = projectPath;
8490
_pipeName = pipeName;
@@ -111,58 +117,79 @@ public void Stop()
111117
{
112118
lock (_lock)
113119
{
114-
StopInternal();
120+
StopInternal(ShutdownMode.Graceful);
115121
}
116122
}
117123

118-
private void StopInternal()
124+
private void StopForEditorQuit()
125+
{
126+
lock (_lock)
127+
{
128+
StopInternal(ShutdownMode.EditorQuit);
129+
}
130+
}
131+
132+
private void StopInternal(ShutdownMode shutdownMode)
119133
{
120134
if (!IsRunning) return;
121135

136+
var fastExit = shutdownMode == ShutdownMode.EditorQuit;
122137
_stopping = true;
123138
_shutdownCompletion.TrySetResult(true);
124139

140+
EditorApplication.update -= PumpMainThreadQueue;
141+
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
142+
EditorApplication.quitting -= OnQuitting;
143+
125144
// Signal watch session to stop
126145
if (_watchActive)
127146
{
128-
try
147+
if (!fastExit)
129148
{
130-
var closeEnvelope = EventEnvelope.Create("_close", "Shutdown");
131-
_watchQueue.Enqueue(closeEnvelope);
149+
try
150+
{
151+
var closeEnvelope = EventEnvelope.Create("_close", "Shutdown");
152+
_watchQueue.Enqueue(closeEnvelope);
153+
}
154+
catch { }
132155
}
133-
catch { }
134156
_watchActive = false;
135157
_watchEventSource?.Unsubscribe();
136158
_watchEventSource = null;
137159
}
138160

139161
// Dispose current pipe to unblock WaitForConnection
140162
try { _listenPipe?.Dispose(); } catch { }
163+
try { _watchPipe?.Dispose(); } catch { }
141164

142165
foreach (var activePipe in _activePipes.Values)
143166
{
144167
try { activePipe.Dispose(); } catch { }
145168
}
146169

147-
if (_listenThread != null && _listenThread.IsAlive)
148-
_listenThread.Join(3000);
149-
150-
// Wait for watch writer thread to finish
151-
if (_watchThread != null && _watchThread.IsAlive)
152-
_watchThread.Join(2000);
170+
if (!fastExit)
171+
{
172+
if (_listenThread != null && _listenThread.IsAlive)
173+
_listenThread.Join(3000);
153174

154-
EditorApplication.update -= PumpMainThreadQueue;
155-
AssemblyReloadEvents.beforeAssemblyReload -= OnBeforeAssemblyReload;
156-
EditorApplication.quitting -= OnQuitting;
175+
// Wait for watch writer thread to finish
176+
if (_watchThread != null && _watchThread.IsAlive)
177+
_watchThread.Join(2000);
178+
}
157179

158180
// Cancel and drain remaining queued requests so listener threads do not block.
159181
while (_mainThreadQueue.TryDequeue(out var pending))
160182
{
161183
pending.WorkItem.Cancel();
162184
}
163185

186+
_listenPipe = null;
187+
_watchPipe = null;
188+
_listenThread = null;
189+
_watchThread = null;
164190
IsRunning = false;
165-
Debug.Log("[unityctl] IPC server stopped");
191+
if (!fastExit)
192+
Debug.Log("[unityctl] IPC server stopped");
166193
}
167194

168195
private void OnBeforeAssemblyReload()
@@ -172,7 +199,7 @@ private void OnBeforeAssemblyReload()
172199

173200
private void OnQuitting()
174201
{
175-
Stop();
202+
StopForEditorQuit();
176203
}
177204

178205
/// <summary>

src/Unityctl.Plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.unityctl.bridge",
3-
"version": "0.3.4",
3+
"version": "0.3.5",
44
"displayName": "unityctl Bridge",
55
"description": "Unity Editor bridge for unityctl CLI — enables batchmode commands and IPC communication.",
66
"unity": "2021.3",

src/Unityctl.Shared/Constants.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public static class Constants
1010
private static readonly string? InformationalVersion =
1111
typeof(Constants).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
1212

13-
public static string Version => NormalizeVersion(InformationalVersion) ?? "0.3.4";
13+
public static string Version => NormalizeVersion(InformationalVersion) ?? "0.3.5";
1414
public const string PipePrefix = "unityctl_";
1515
public const int DefaultTimeoutMs = 120_000;
1616
public const int PingTimeoutMs = 10_000;

tests/Unityctl.Shared.Tests/CommandSyncGuardrailTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ public void WatchCommand_UsesDedicatedIpcPath_InPlugin()
4949
Assert.Contains("watch session started", source);
5050
}
5151

52+
[Fact]
53+
public void IpcServer_UsesFastQuitShutdownPath()
54+
{
55+
var source = ReadRepoFile(@"src\Unityctl.Plugin\Editor\Ipc\IpcServer.cs");
56+
57+
Assert.Contains("private void StopForEditorQuit()", source);
58+
Assert.Contains("StopInternal(ShutdownMode.EditorQuit)", source);
59+
Assert.Contains("if (!fastExit)", source);
60+
}
61+
5262
[Fact]
5363
public void ScriptCommands_AreRegisteredAcrossCliMcpAndPlugin()
5464
{

0 commit comments

Comments
 (0)