@mflrevan/ucp 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +1 -11
  2. package/package.json +8 -2
  3. package/bridge/com.ucp.bridge/CHANGELOG.md +0 -128
  4. package/bridge/com.ucp.bridge/CHANGELOG.md.meta +0 -7
  5. package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +0 -576
  6. package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs.meta +0 -2
  7. package/bridge/com.ucp.bridge/Editor/Bridge.meta +0 -8
  8. package/bridge/com.ucp.bridge/Editor/Controllers/AssetController.cs +0 -530
  9. package/bridge/com.ucp.bridge/Editor/Controllers/AssetController.cs.meta +0 -2
  10. package/bridge/com.ucp.bridge/Editor/Controllers/BuildController.cs +0 -230
  11. package/bridge/com.ucp.bridge/Editor/Controllers/BuildController.cs.meta +0 -2
  12. package/bridge/com.ucp.bridge/Editor/Controllers/CompilationController.cs +0 -26
  13. package/bridge/com.ucp.bridge/Editor/Controllers/CompilationController.cs.meta +0 -2
  14. package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs +0 -18
  15. package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs.meta +0 -2
  16. package/bridge/com.ucp.bridge/Editor/Controllers/EditorSettingsController.cs +0 -438
  17. package/bridge/com.ucp.bridge/Editor/Controllers/EditorSettingsController.cs.meta +0 -2
  18. package/bridge/com.ucp.bridge/Editor/Controllers/FileController.cs +0 -145
  19. package/bridge/com.ucp.bridge/Editor/Controllers/FileController.cs.meta +0 -2
  20. package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs +0 -319
  21. package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs.meta +0 -2
  22. package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs +0 -288
  23. package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs.meta +0 -2
  24. package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs +0 -295
  25. package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs.meta +0 -2
  26. package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs +0 -93
  27. package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs.meta +0 -2
  28. package/bridge/com.ucp.bridge/Editor/Controllers/PlayModeController.cs +0 -84
  29. package/bridge/com.ucp.bridge/Editor/Controllers/PlayModeController.cs.meta +0 -2
  30. package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs +0 -242
  31. package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs.meta +0 -2
  32. package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs +0 -533
  33. package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs.meta +0 -2
  34. package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +0 -269
  35. package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs.meta +0 -2
  36. package/bridge/com.ucp.bridge/Editor/Controllers/ScreenshotController.cs +0 -125
  37. package/bridge/com.ucp.bridge/Editor/Controllers/ScreenshotController.cs.meta +0 -2
  38. package/bridge/com.ucp.bridge/Editor/Controllers/ScriptController.cs +0 -104
  39. package/bridge/com.ucp.bridge/Editor/Controllers/ScriptController.cs.meta +0 -2
  40. package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs +0 -227
  41. package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs.meta +0 -2
  42. package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +0 -240
  43. package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs.meta +0 -2
  44. package/bridge/com.ucp.bridge/Editor/Controllers/VcsController.cs +0 -611
  45. package/bridge/com.ucp.bridge/Editor/Controllers/VcsController.cs.meta +0 -2
  46. package/bridge/com.ucp.bridge/Editor/Controllers.meta +0 -8
  47. package/bridge/com.ucp.bridge/Editor/Protocol/CommandRouter.cs +0 -53
  48. package/bridge/com.ucp.bridge/Editor/Protocol/CommandRouter.cs.meta +0 -2
  49. package/bridge/com.ucp.bridge/Editor/Protocol/MessageTypes.cs +0 -80
  50. package/bridge/com.ucp.bridge/Editor/Protocol/MessageTypes.cs.meta +0 -2
  51. package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +0 -358
  52. package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs.meta +0 -2
  53. package/bridge/com.ucp.bridge/Editor/Protocol.meta +0 -8
  54. package/bridge/com.ucp.bridge/Editor/Scripts/IUCPScript.cs +0 -37
  55. package/bridge/com.ucp.bridge/Editor/Scripts/IUCPScript.cs.meta +0 -2
  56. package/bridge/com.ucp.bridge/Editor/Scripts.meta +0 -8
  57. package/bridge/com.ucp.bridge/Editor/UCP.Bridge.Editor.asmdef +0 -16
  58. package/bridge/com.ucp.bridge/Editor/UCP.Bridge.Editor.asmdef.meta +0 -7
  59. package/bridge/com.ucp.bridge/Editor.meta +0 -8
  60. package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef +0 -14
  61. package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef.meta +0 -7
  62. package/bridge/com.ucp.bridge/Runtime.meta +0 -8
  63. package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +0 -670
  64. package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs.meta +0 -2
  65. package/bridge/com.ucp.bridge/Tests/Editor/UCP.Bridge.Editor.Tests.asmdef +0 -12
  66. package/bridge/com.ucp.bridge/Tests/Editor/UCP.Bridge.Editor.Tests.asmdef.meta +0 -7
  67. package/bridge/com.ucp.bridge/Tests/Editor.meta +0 -8
  68. package/bridge/com.ucp.bridge/Tests.meta +0 -8
  69. package/bridge/com.ucp.bridge/package.json +0 -27
  70. package/bridge/com.ucp.bridge/package.json.meta +0 -7
@@ -1,576 +0,0 @@
1
- using System;
2
- using System.Collections.Concurrent;
3
- using System.Collections.Generic;
4
- using System.IO;
5
- using System.Net;
6
- using System.Net.Sockets;
7
- using System.Net.WebSockets;
8
- using System.Security.Cryptography;
9
- using System.Text;
10
- using System.Text.RegularExpressions;
11
- using System.Threading;
12
- using System.Threading.Tasks;
13
- using UnityEditor;
14
- using UnityEngine;
15
-
16
- namespace UCP.Bridge
17
- {
18
- /// <summary>
19
- /// WebSocket server that runs inside the Unity Editor.
20
- /// Uses raw TcpListener + manual WebSocket upgrade for maximum compatibility.
21
- /// Starts automatically via [InitializeOnLoad] and handles JSON-RPC commands.
22
- /// </summary>
23
- [InitializeOnLoad]
24
- public static class BridgeServer
25
- {
26
- private const int DefaultPort = 21342;
27
- private const int MaxPort = 21352;
28
- private const int MaxConnections = 4;
29
- private const string ProtocolVersion = "0.4.0";
30
-
31
- private static TcpListener s_listener;
32
- private static CancellationTokenSource s_cts;
33
- private static readonly List<WebSocket> s_clients = new();
34
- private static readonly object s_clientLock = new();
35
- private static int s_port;
36
- private static string s_token;
37
- private static bool s_running;
38
-
39
- // Main-thread action queue
40
- private static readonly ConcurrentQueue<Action> s_mainThreadQueue = new();
41
-
42
- // Command router
43
- private static readonly CommandRouter s_router = new();
44
-
45
- // Log subscribers
46
- private static readonly HashSet<WebSocket> s_logSubscribers = new();
47
-
48
- static BridgeServer()
49
- {
50
- // Use delayCall + update fallback to ensure reliable startup after domain reload
51
- EditorApplication.delayCall += Initialize;
52
- EditorApplication.update += EnsureRunning;
53
- }
54
-
55
- private static void EnsureRunning()
56
- {
57
- if (!s_running)
58
- {
59
- EditorApplication.update -= EnsureRunning;
60
- Initialize();
61
- }
62
- else
63
- {
64
- EditorApplication.update -= EnsureRunning;
65
- }
66
- }
67
-
68
- private static void Initialize()
69
- {
70
- if (s_running) return;
71
-
72
- try
73
- {
74
- RegisterHandlers();
75
-
76
- EditorApplication.update += PumpMainThread;
77
- EditorApplication.quitting += Shutdown;
78
- AssemblyReloadEvents.beforeAssemblyReload += Shutdown;
79
- Application.logMessageReceived += OnLogMessage;
80
-
81
- s_token = Guid.NewGuid().ToString("N").Substring(0, 16);
82
- StartServer();
83
- }
84
- catch (Exception ex)
85
- {
86
- Debug.LogError($"[UCP] Failed to initialize bridge: {ex}");
87
- }
88
- }
89
-
90
- private static void RegisterHandlers()
91
- {
92
- // Handshake
93
- s_router.Register("handshake", (paramsJson) =>
94
- {
95
- return new
96
- {
97
- serverVersion = ProtocolVersion,
98
- protocolVersion = ProtocolVersion,
99
- unityVersion = Application.unityVersion,
100
- projectName = Application.productName,
101
- projectPath = Path.GetDirectoryName(Application.dataPath)
102
- };
103
- });
104
-
105
- // Play mode
106
- PlayModeController.Register(s_router);
107
-
108
- // Compilation
109
- CompilationController.Register(s_router);
110
-
111
- // Editor lifecycle
112
- EditorController.Register(s_router);
113
-
114
- // Scenes
115
- SceneController.Register(s_router);
116
-
117
- // Snapshots
118
- SnapshotController.Register(s_router);
119
-
120
- // Screenshots
121
- ScreenshotController.Register(s_router);
122
-
123
- // Logs
124
- LogsController.Register(s_router);
125
-
126
- // Tests
127
- TestRunnerController.Register(s_router);
128
-
129
- // Scripts (exec)
130
- ScriptController.Register(s_router);
131
-
132
- // Files
133
- FileController.Register(s_router);
134
-
135
- // Version Control (Unity VCS / Plastic SCM)
136
- VcsController.Register(s_router);
137
-
138
- // Object Properties
139
- PropertyController.Register(s_router);
140
-
141
- // Hierarchy Operations
142
- HierarchyController.Register(s_router);
143
-
144
- // Asset Management
145
- AssetController.Register(s_router);
146
-
147
- // Editor Settings (Player, Quality, Physics, Lighting, Tags/Layers)
148
- EditorSettingsController.Register(s_router);
149
-
150
- // Material Properties
151
- MaterialController.Register(s_router);
152
-
153
- // Prefab Operations
154
- PrefabController.Register(s_router);
155
-
156
- // Build Pipeline
157
- BuildController.Register(s_router);
158
- }
159
-
160
- private static void StartServer()
161
- {
162
- s_cts = new CancellationTokenSource();
163
-
164
- for (int port = DefaultPort; port <= MaxPort; port++)
165
- {
166
- try
167
- {
168
- s_listener = new TcpListener(IPAddress.Loopback, port);
169
- s_listener.Start();
170
- s_port = port;
171
- s_running = true;
172
- Debug.Log($"[UCP] Bridge server started on port {port}");
173
- break;
174
- }
175
- catch (Exception)
176
- {
177
- s_listener?.Stop();
178
- s_listener = null;
179
- }
180
- }
181
-
182
- if (!s_running)
183
- {
184
- Debug.LogError("[UCP] Failed to start bridge server — all ports in use");
185
- return;
186
- }
187
-
188
- WriteLockFile();
189
- Task.Run(() => AcceptLoop(s_cts.Token));
190
- }
191
-
192
- private static async Task AcceptLoop(CancellationToken ct)
193
- {
194
- while (!ct.IsCancellationRequested && s_running)
195
- {
196
- try
197
- {
198
- var tcp = await s_listener.AcceptTcpClientAsync();
199
- var stream = tcp.GetStream();
200
-
201
- // Read HTTP upgrade request (may arrive in multiple segments)
202
- var requestBuilder = new StringBuilder();
203
- var buffer = new byte[4096];
204
- do
205
- {
206
- int read = await stream.ReadAsync(buffer, 0, buffer.Length, ct);
207
- if (read == 0) { tcp.Close(); continue; }
208
- requestBuilder.Append(Encoding.UTF8.GetString(buffer, 0, read));
209
- }
210
- while (!requestBuilder.ToString().Contains("\r\n\r\n") && stream.DataAvailable);
211
-
212
- var request = requestBuilder.ToString();
213
-
214
- // Check if it's a WebSocket upgrade
215
- if (!request.Contains("Upgrade: websocket", StringComparison.OrdinalIgnoreCase))
216
- {
217
- var resp = "HTTP/1.1 426 Upgrade Required\r\nContent-Length: 0\r\n\r\n";
218
- var respBytes = Encoding.UTF8.GetBytes(resp);
219
- await stream.WriteAsync(respBytes, 0, respBytes.Length, ct);
220
- tcp.Close();
221
- continue;
222
- }
223
-
224
- // Extract Sec-WebSocket-Key
225
- var keyMatch = Regex.Match(request, @"Sec-WebSocket-Key:\s*(\S+)",
226
- RegexOptions.IgnoreCase);
227
- if (!keyMatch.Success)
228
- {
229
- Debug.LogError("[UCP] No Sec-WebSocket-Key found in request");
230
- tcp.Close();
231
- continue;
232
- }
233
-
234
- var wsKey = keyMatch.Groups[1].Value.Trim();
235
- var acceptKey = ComputeWebSocketAcceptKey(wsKey);
236
-
237
- // Send upgrade response
238
- var upgradeResponse =
239
- "HTTP/1.1 101 Switching Protocols\r\n" +
240
- "Upgrade: websocket\r\n" +
241
- "Connection: Upgrade\r\n" +
242
- $"Sec-WebSocket-Accept: {acceptKey}\r\n\r\n";
243
- var upgradeBytes = Encoding.UTF8.GetBytes(upgradeResponse);
244
- await stream.WriteAsync(upgradeBytes, 0, upgradeBytes.Length, ct);
245
-
246
- // Create WebSocket from stream
247
- var ws = WebSocket.CreateFromStream(stream, true, null, TimeSpan.FromSeconds(30));
248
-
249
- lock (s_clientLock)
250
- {
251
- if (s_clients.Count >= MaxConnections)
252
- {
253
- _ = ws.CloseAsync(WebSocketCloseStatus.PolicyViolation,
254
- "Max connections reached", CancellationToken.None);
255
- continue;
256
- }
257
- s_clients.Add(ws);
258
- }
259
-
260
- _ = Task.Run(() => HandleClient(ws, ct));
261
- }
262
- catch (ObjectDisposedException) { break; }
263
- catch (SocketException) { break; }
264
- catch (Exception ex)
265
- {
266
- if (!ct.IsCancellationRequested)
267
- Debug.LogError($"[UCP] Accept error: {ex.Message}");
268
- }
269
- }
270
- }
271
-
272
- private static string ComputeWebSocketAcceptKey(string key)
273
- {
274
- const string magic = "258EAFA5-E914-47DA-95CA-5AB5DC85B11B";
275
- var combined = key + magic;
276
- var hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(combined));
277
- return Convert.ToBase64String(hash);
278
- }
279
-
280
- private static async Task HandleClient(WebSocket ws, CancellationToken ct)
281
- {
282
- var buffer = new byte[64 * 1024]; // 64KB buffer
283
-
284
- try
285
- {
286
- while (ws.State == WebSocketState.Open && !ct.IsCancellationRequested)
287
- {
288
- var segment = new ArraySegment<byte>(buffer);
289
- WebSocketReceiveResult received;
290
- var messageBuilder = new StringBuilder();
291
-
292
- do
293
- {
294
- received = await ws.ReceiveAsync(segment, ct);
295
- if (received.MessageType == WebSocketMessageType.Close)
296
- {
297
- await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
298
- return;
299
- }
300
- messageBuilder.Append(Encoding.UTF8.GetString(buffer, 0, received.Count));
301
- }
302
- while (!received.EndOfMessage);
303
-
304
- var message = messageBuilder.ToString();
305
- ProcessMessage(ws, message);
306
- }
307
- }
308
- catch (OperationCanceledException) { }
309
- catch (WebSocketException) { }
310
- catch (Exception ex)
311
- {
312
- Debug.LogError($"[UCP] Client error: {ex.Message}");
313
- }
314
- finally
315
- {
316
- lock (s_clientLock)
317
- {
318
- s_clients.Remove(ws);
319
- s_logSubscribers.Remove(ws);
320
- }
321
- }
322
- }
323
-
324
- private static void ProcessMessage(WebSocket ws, string message)
325
- {
326
- // Parse JSON-RPC request
327
- long id = 0;
328
- string method = null;
329
- string paramsJson = "{}";
330
-
331
- try
332
- {
333
- // Minimal JSON parsing using Unity's JsonUtility won't work well for dynamic JSON.
334
- // Use a simple manual parse for the top-level fields.
335
- var json = MiniJson.Deserialize(message) as Dictionary<string, object>;
336
- if (json == null)
337
- {
338
- SendError(ws, 0, ErrorCodes.ParseError, "Invalid JSON");
339
- return;
340
- }
341
-
342
- if (json.TryGetValue("id", out var idVal))
343
- id = Convert.ToInt64(idVal);
344
-
345
- if (json.TryGetValue("method", out var methodVal))
346
- method = methodVal as string;
347
-
348
- if (json.TryGetValue("params", out var paramsVal))
349
- paramsJson = MiniJson.Serialize(paramsVal);
350
- }
351
- catch (Exception ex)
352
- {
353
- SendError(ws, 0, ErrorCodes.ParseError, $"Parse error: {ex.Message}");
354
- return;
355
- }
356
-
357
- if (string.IsNullOrEmpty(method))
358
- {
359
- SendError(ws, id, ErrorCodes.InvalidRequest, "Missing 'method' field");
360
- return;
361
- }
362
-
363
- // Handle log subscription specially
364
- if (method == "logs/subscribe")
365
- {
366
- lock (s_clientLock) { s_logSubscribers.Add(ws); }
367
- }
368
- else if (method == "logs/unsubscribe")
369
- {
370
- lock (s_clientLock) { s_logSubscribers.Remove(ws); }
371
- }
372
-
373
- // Dispatch on main thread
374
- var capturedId = id;
375
- var capturedMethod = method;
376
- var capturedParams = paramsJson;
377
- var capturedWs = ws;
378
-
379
- s_mainThreadQueue.Enqueue(() =>
380
- {
381
- var response = s_router.Dispatch(capturedMethod, capturedId, capturedParams);
382
- SendResponse(capturedWs, response);
383
- });
384
- }
385
-
386
- private static void SendResponse(WebSocket ws, JsonRpcResponse response)
387
- {
388
- try
389
- {
390
- var json = MiniJson.Serialize(ResponseToDict(response));
391
- var bytes = Encoding.UTF8.GetBytes(json);
392
- _ = ws.SendAsync(new ArraySegment<byte>(bytes),
393
- WebSocketMessageType.Text, true, CancellationToken.None);
394
- }
395
- catch (Exception ex)
396
- {
397
- Debug.LogError($"[UCP] Send error: {ex.Message}");
398
- }
399
- }
400
-
401
- private static void SendError(WebSocket ws, long id, int code, string message)
402
- {
403
- SendResponse(ws, JsonRpcResponse.Error(id, code, message));
404
- }
405
-
406
- /// <summary>
407
- /// Send a notification to log subscribers only.
408
- /// </summary>
409
- public static void SendNotification(string method, object data)
410
- {
411
- SendNotificationTo(method, data, false);
412
- }
413
-
414
- /// <summary>
415
- /// Broadcast a notification to ALL connected clients.
416
- /// Use for test results and other non-log notifications.
417
- /// </summary>
418
- public static void BroadcastNotification(string method, object data)
419
- {
420
- SendNotificationTo(method, data, true);
421
- }
422
-
423
- private static void SendNotificationTo(string method, object data, bool toAll)
424
- {
425
- var dict = new Dictionary<string, object>
426
- {
427
- ["jsonrpc"] = "2.0",
428
- ["method"] = method,
429
- ["params"] = data
430
- };
431
- var json = MiniJson.Serialize(dict);
432
- var bytes = Encoding.UTF8.GetBytes(json);
433
- var segment = new ArraySegment<byte>(bytes);
434
-
435
- List<WebSocket> targets;
436
- lock (s_clientLock)
437
- {
438
- targets = toAll
439
- ? new List<WebSocket>(s_clients)
440
- : new List<WebSocket>(s_logSubscribers);
441
- }
442
-
443
- foreach (var ws in targets)
444
- {
445
- try
446
- {
447
- if (ws.State == WebSocketState.Open)
448
- {
449
- _ = ws.SendAsync(segment, WebSocketMessageType.Text, true, CancellationToken.None);
450
- }
451
- }
452
- catch { /* ignore send failures for notifications */ }
453
- }
454
- }
455
-
456
- private static void OnLogMessage(string message, string stackTrace, LogType type)
457
- {
458
- // Don't forward our own log messages to avoid infinite recursion
459
- if (message.StartsWith("[UCP]")) return;
460
-
461
- SendNotification("log", LogsController.RecordLog(message, stackTrace, type));
462
- }
463
-
464
- private static void PumpMainThread()
465
- {
466
- int processed = 0;
467
- while (s_mainThreadQueue.TryDequeue(out var action) && processed < 50)
468
- {
469
- try { action(); }
470
- catch (Exception ex) { Debug.LogError($"[UCP] Main thread error: {ex}"); }
471
- processed++;
472
- }
473
- }
474
-
475
- private static void WriteLockFile()
476
- {
477
- try
478
- {
479
- var projectPath = Path.GetDirectoryName(Application.dataPath);
480
- var ucpDir = Path.Combine(projectPath, ".ucp");
481
- Directory.CreateDirectory(ucpDir);
482
-
483
- var lockData = new Dictionary<string, object>
484
- {
485
- ["pid"] = System.Diagnostics.Process.GetCurrentProcess().Id,
486
- ["port"] = s_port,
487
- ["protocolVersion"] = ProtocolVersion,
488
- ["unityVersion"] = Application.unityVersion,
489
- ["projectPath"] = projectPath,
490
- ["startedAt"] = DateTime.UtcNow.ToString("o"),
491
- ["token"] = s_token
492
- };
493
-
494
- File.WriteAllText(
495
- Path.Combine(ucpDir, "bridge.lock"),
496
- MiniJson.Serialize(lockData)
497
- );
498
- }
499
- catch (Exception ex)
500
- {
501
- Debug.LogError($"[UCP] Failed to write lock file: {ex.Message}");
502
- }
503
- }
504
-
505
- private static void CleanLockFile()
506
- {
507
- try
508
- {
509
- var projectPath = Path.GetDirectoryName(Application.dataPath);
510
- var lockPath = Path.Combine(projectPath, ".ucp", "bridge.lock");
511
- if (File.Exists(lockPath))
512
- File.Delete(lockPath);
513
- }
514
- catch { }
515
- }
516
-
517
- private static void Shutdown()
518
- {
519
- if (!s_running) return;
520
- s_running = false;
521
-
522
- Debug.Log("[UCP] Bridge server shutting down");
523
-
524
- s_cts?.Cancel();
525
-
526
- // Stop listener first to release port immediately
527
- try { s_listener?.Stop(); }
528
- catch { }
529
- s_listener = null;
530
-
531
- lock (s_clientLock)
532
- {
533
- foreach (var ws in s_clients)
534
- {
535
- try { ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "Shutting down", CancellationToken.None); }
536
- catch { }
537
- }
538
- s_clients.Clear();
539
- s_logSubscribers.Clear();
540
- }
541
-
542
- s_cts?.Dispose();
543
- s_cts = null;
544
-
545
- CleanLockFile();
546
-
547
- EditorApplication.update -= PumpMainThread;
548
- Application.logMessageReceived -= OnLogMessage;
549
- }
550
-
551
- private static Dictionary<string, object> ResponseToDict(JsonRpcResponse r)
552
- {
553
- var dict = new Dictionary<string, object>
554
- {
555
- ["jsonrpc"] = "2.0",
556
- ["id"] = r.id
557
- };
558
-
559
- if (r.error != null)
560
- {
561
- dict["error"] = new Dictionary<string, object>
562
- {
563
- ["code"] = r.error.code,
564
- ["message"] = r.error.message,
565
- ["data"] = r.error.data
566
- };
567
- }
568
- else
569
- {
570
- dict["result"] = r.result;
571
- }
572
-
573
- return dict;
574
- }
575
- }
576
- }
@@ -1,2 +0,0 @@
1
- fileFormatVersion: 2
2
- guid: b9a2c654603efd4489cde1f7449bdc4c
@@ -1,8 +0,0 @@
1
- fileFormatVersion: 2
2
- guid: f6c77174590222842b21f1d3b792cb65
3
- folderAsset: yes
4
- DefaultImporter:
5
- externalObjects: {}
6
- userData:
7
- assetBundleName:
8
- assetBundleVariant: