@mflrevan/ucp 0.4.5 → 0.4.6

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @mflrevan/ucp
2
2
 
3
- Version `0.4.5` of the Unity Control Protocol CLI.
3
+ Version `0.4.6` of the Unity Control Protocol CLI.
4
4
 
5
5
  This package installs the `ucp` command, downloads the matching published binary for your platform during `postinstall`, and ships the matching Unity bridge payload inside the npm package.
6
6
 
@@ -26,7 +26,7 @@ namespace UCP.Bridge
26
26
  private const int DefaultPort = 21342;
27
27
  private const int MaxPort = 21352;
28
28
  private const int MaxConnections = 4;
29
- private const string ProtocolVersion = "0.4.5";
29
+ private const string ProtocolVersion = "0.4.6";
30
30
 
31
31
  private static TcpListener s_listener;
32
32
  private static CancellationTokenSource s_cts;
@@ -0,0 +1,18 @@
1
+ using UnityEditor;
2
+ using UnityEngine;
3
+
4
+ namespace UCP.Bridge
5
+ {
6
+ internal static class UnityObjectCompat
7
+ {
8
+ public static Object ResolveByInstanceId(int instanceId)
9
+ {
10
+ return EditorUtility.InstanceIDToObject(instanceId);
11
+ }
12
+
13
+ public static T ResolveByInstanceId<T>(int instanceId) where T : Object
14
+ {
15
+ return ResolveByInstanceId(instanceId) as T;
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 26985214c906f3945a01cd11320484e4
@@ -0,0 +1,8 @@
1
+ fileFormatVersion: 2
2
+ guid: 6e64b956356efe640939d405c9429117
3
+ folderAsset: yes
4
+ DefaultImporter:
5
+ externalObjects: {}
6
+ userData:
7
+ assetBundleName:
8
+ assetBundleVariant:
@@ -295,7 +295,7 @@ namespace UCP.Bridge
295
295
 
296
296
  private static GameObject FindGameObject(int instanceId)
297
297
  {
298
- var obj = EditorUtility.EntityIdToObject(instanceId) as GameObject;
298
+ var obj = UnityObjectCompat.ResolveByInstanceId<GameObject>(instanceId);
299
299
  if (obj != null) return obj;
300
300
 
301
301
  for (int i = 0; i < SceneManager.sceneCount; i++)
@@ -228,7 +228,7 @@ namespace UCP.Bridge
228
228
  if (p.TryGetValue("instanceId", out var idObj))
229
229
  {
230
230
  int instanceId = Convert.ToInt32(idObj);
231
- var obj = EditorUtility.EntityIdToObject(instanceId);
231
+ var obj = UnityObjectCompat.ResolveByInstanceId(instanceId);
232
232
 
233
233
  if (obj is Material directMat)
234
234
  return directMat;
@@ -330,7 +330,7 @@ namespace UCP.Bridge
330
330
  }
331
331
  else if (texDict.TryGetValue("instanceId", out var tid))
332
332
  {
333
- var tex = EditorUtility.EntityIdToObject(Convert.ToInt32(tid)) as Texture;
333
+ var tex = UnityObjectCompat.ResolveByInstanceId<Texture>(Convert.ToInt32(tid));
334
334
  mat.SetTexture(propName, tex);
335
335
  }
336
336
  }
@@ -65,7 +65,7 @@ namespace UCP.Bridge
65
65
 
66
66
  private static UnityEngine.Object ResolveByInstanceId(int instanceId, string propertyName)
67
67
  {
68
- var resolved = EditorUtility.EntityIdToObject(instanceId);
68
+ var resolved = UnityObjectCompat.ResolveByInstanceId(instanceId);
69
69
  if (resolved == null)
70
70
  throw new ArgumentException($"Object reference for '{propertyName}' could not resolve instance id {instanceId}");
71
71
 
@@ -26,7 +26,7 @@ namespace UCP.Bridge
26
26
  if (p == null || !p.TryGetValue("instanceId", out var idObj))
27
27
  throw new ArgumentException("Missing 'instanceId' parameter");
28
28
 
29
- var go = EditorUtility.EntityIdToObject(Convert.ToInt32(idObj)) as GameObject;
29
+ var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt32(idObj));
30
30
  if (go == null)
31
31
  throw new ArgumentException($"GameObject not found: {idObj}");
32
32
 
@@ -63,7 +63,7 @@ namespace UCP.Bridge
63
63
  if (p == null || !p.TryGetValue("instanceId", out var idObj))
64
64
  throw new ArgumentException("Missing 'instanceId' parameter");
65
65
 
66
- var go = EditorUtility.EntityIdToObject(Convert.ToInt32(idObj)) as GameObject;
66
+ var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt32(idObj));
67
67
  if (go == null)
68
68
  throw new ArgumentException($"GameObject not found: {idObj}");
69
69
 
@@ -88,7 +88,7 @@ namespace UCP.Bridge
88
88
  if (p == null || !p.TryGetValue("instanceId", out var idObj))
89
89
  throw new ArgumentException("Missing 'instanceId' parameter");
90
90
 
91
- var go = EditorUtility.EntityIdToObject(Convert.ToInt32(idObj)) as GameObject;
91
+ var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt32(idObj));
92
92
  if (go == null)
93
93
  throw new ArgumentException($"GameObject not found: {idObj}");
94
94
 
@@ -116,7 +116,7 @@ namespace UCP.Bridge
116
116
  if (p.TryGetValue("completely", out var compObj))
117
117
  completely = Convert.ToBoolean(compObj);
118
118
 
119
- var go = EditorUtility.EntityIdToObject(Convert.ToInt32(idObj)) as GameObject;
119
+ var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt32(idObj));
120
120
  if (go == null)
121
121
  throw new ArgumentException($"GameObject not found: {idObj}");
122
122
 
@@ -147,7 +147,7 @@ namespace UCP.Bridge
147
147
  if (!p.TryGetValue("path", out var pathObj))
148
148
  throw new ArgumentException("Missing 'path' parameter");
149
149
 
150
- var go = EditorUtility.EntityIdToObject(Convert.ToInt32(idObj)) as GameObject;
150
+ var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt32(idObj));
151
151
  if (go == null)
152
152
  throw new ArgumentException($"GameObject not found: {idObj}");
153
153
 
@@ -191,7 +191,7 @@ namespace UCP.Bridge
191
191
  if (p == null || !p.TryGetValue("instanceId", out var idObj))
192
192
  throw new ArgumentException("Missing 'instanceId' parameter");
193
193
 
194
- var go = EditorUtility.EntityIdToObject(Convert.ToInt32(idObj)) as GameObject;
194
+ var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt32(idObj));
195
195
  if (go == null)
196
196
  throw new ArgumentException($"GameObject not found: {idObj}");
197
197
 
@@ -179,33 +179,40 @@ namespace UCP.Bridge
179
179
 
180
180
  // Use SerializedObject for reliable Unity property enumeration
181
181
  var so = new SerializedObject(comp);
182
- var prop = so.GetIterator();
183
- if (prop.NextVisible(true))
182
+ try
184
183
  {
185
- do
184
+ so.Update();
185
+ var prop = so.GetIterator();
186
+ if (prop.NextVisible(true))
186
187
  {
187
- var fieldDict = new Dictionary<string, object>
188
+ do
188
189
  {
189
- ["name"] = prop.name,
190
- ["displayName"] = prop.displayName,
191
- ["type"] = prop.propertyType.ToString(),
192
- ["editable"] = !prop.isReadOnly(true)
193
- };
194
-
195
- try
196
- {
197
- fieldDict["value"] = SerializedPropertyToValue(prop);
198
- }
199
- catch
200
- {
201
- fieldDict["value"] = "<unreadable>";
190
+ var fieldDict = new Dictionary<string, object>
191
+ {
192
+ ["name"] = prop.name,
193
+ ["displayName"] = prop.displayName,
194
+ ["type"] = prop.propertyType.ToString(),
195
+ ["editable"] = !prop.isReadOnly(true)
196
+ };
197
+
198
+ try
199
+ {
200
+ fieldDict["value"] = SerializedPropertyToValue(prop);
201
+ }
202
+ catch
203
+ {
204
+ fieldDict["value"] = "<unreadable>";
205
+ }
206
+
207
+ fields.Add(fieldDict);
202
208
  }
203
-
204
- fields.Add(fieldDict);
209
+ while (prop.NextVisible(false));
205
210
  }
206
- while (prop.NextVisible(false));
207
211
  }
208
- so.Dispose();
212
+ finally
213
+ {
214
+ so.Dispose();
215
+ }
209
216
 
210
217
  return fields;
211
218
  }
@@ -273,14 +280,17 @@ namespace UCP.Bridge
273
280
  private static object GetPropertyValue(Component comp, string propertyName)
274
281
  {
275
282
  var so = new SerializedObject(comp);
276
- var prop = so.FindProperty(propertyName);
277
- if (prop != null)
283
+ try
284
+ {
285
+ so.Update();
286
+ var prop = so.FindProperty(propertyName);
287
+ if (prop != null)
288
+ return SerializedPropertyToValue(prop);
289
+ }
290
+ finally
278
291
  {
279
- var val = SerializedPropertyToValue(prop);
280
292
  so.Dispose();
281
- return val;
282
293
  }
283
- so.Dispose();
284
294
 
285
295
  // Fallback to reflection
286
296
  var type = comp.GetType();
@@ -298,15 +308,21 @@ namespace UCP.Bridge
298
308
  private static void SetPropertyValue(Component comp, string propertyName, object jsonValue)
299
309
  {
300
310
  var so = new SerializedObject(comp);
301
- var prop = so.FindProperty(propertyName);
302
- if (prop != null)
311
+ try
312
+ {
313
+ so.Update();
314
+ var prop = so.FindProperty(propertyName);
315
+ if (prop != null)
316
+ {
317
+ SetSerializedPropertyValue(prop, jsonValue);
318
+ so.ApplyModifiedProperties();
319
+ return;
320
+ }
321
+ }
322
+ finally
303
323
  {
304
- SetSerializedPropertyValue(prop, jsonValue);
305
- so.ApplyModifiedProperties();
306
324
  so.Dispose();
307
- return;
308
325
  }
309
- so.Dispose();
310
326
 
311
327
  // Fallback to reflection
312
328
  var type = comp.GetType();
@@ -502,7 +518,7 @@ namespace UCP.Bridge
502
518
 
503
519
  private static GameObject FindGameObject(int instanceId)
504
520
  {
505
- var obj = EditorUtility.EntityIdToObject(instanceId) as GameObject;
521
+ var obj = UnityObjectCompat.ResolveByInstanceId<GameObject>(instanceId);
506
522
  if (obj != null) return obj;
507
523
 
508
524
  // Search in loaded scenes
@@ -273,7 +273,7 @@ namespace UCP.Bridge
273
273
 
274
274
  private static GameObject FindGameObject(int instanceId)
275
275
  {
276
- var direct = EditorUtility.EntityIdToObject(instanceId) as GameObject;
276
+ var direct = UnityObjectCompat.ResolveByInstanceId<GameObject>(instanceId);
277
277
  if (direct != null)
278
278
  return direct;
279
279
 
@@ -202,7 +202,7 @@ namespace UCP.Bridge
202
202
 
203
203
  private static GameObject FindByInstanceId(int id)
204
204
  {
205
- var obj = UnityEditor.EditorUtility.EntityIdToObject(id);
205
+ var obj = UnityObjectCompat.ResolveByInstanceId(id);
206
206
  return obj as GameObject;
207
207
  }
208
208
 
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "name": "UCP.Bridge.Editor",
3
3
  "rootNamespace": "UCP.Bridge",
4
- "references": [],
4
+ "references": [
5
+ "UnityEditor.TestRunner"
6
+ ],
5
7
  "includePlatforms": [
6
8
  "Editor"
7
9
  ],
@@ -371,7 +371,7 @@ namespace UCP.Bridge.Tests
371
371
  );
372
372
  Assert.That(getPosition.error, Is.Null);
373
373
 
374
- var updated = EditorUtility.EntityIdToObject(instanceId) as GameObject;
374
+ var updated = EditorUtility.InstanceIDToObject(instanceId) as GameObject;
375
375
  Assert.That(updated, Is.Not.Null);
376
376
  var localPosition = updated.transform.localPosition;
377
377
  Assert.That(localPosition.x, Is.EqualTo(1f).Within(0.001f));
@@ -383,7 +383,7 @@ namespace UCP.Bridge.Tests
383
383
 
384
384
  var delete = _router.Dispatch("object/delete", 1, "{\"instanceId\":" + instanceId + "}");
385
385
  Assert.That(delete.error, Is.Null);
386
- Assert.That(EditorUtility.EntityIdToObject(instanceId), Is.Null);
386
+ Assert.That(EditorUtility.InstanceIDToObject(instanceId), Is.Null);
387
387
  }
388
388
 
389
389
  [Test]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "com.ucp.bridge",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "displayName": "Unity Control Protocol Bridge",
5
5
  "description": "WebSocket bridge for programmatic Unity Editor control via CLI and AI agents.",
6
6
  "unity": "2021.3",
@@ -23,5 +23,7 @@
23
23
  "type": "tool",
24
24
  "documentationUrl": "https://github.com/mflRevan/unity-control-protocol/blob/main/README.md",
25
25
  "changelogUrl": "https://github.com/mflRevan/unity-control-protocol/blob/main/unity-package/com.ucp.bridge/CHANGELOG.md",
26
- "dependencies": {}
26
+ "dependencies": {
27
+ "com.unity.test-framework": "1.1.31"
28
+ }
27
29
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mflrevan/ucp",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Unity Control Protocol - CLI for programmatic Unity Editor control",
5
5
  "license": "MIT",
6
6
  "repository": {