@mflrevan/ucp 0.6.1 → 0.6.3
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 +1 -1
- package/bridge/com.ucp.bridge/CHANGELOG.md +110 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +61 -6
- package/bridge/com.ucp.bridge/Editor/Bridge/EditorStateSummary.cs +165 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/EditorStateSummary.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Compatibility/UnityObjectCompat.cs +22 -5
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs +1 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/HierarchyController.cs +10 -10
- package/bridge/com.ucp.bridge/Editor/Controllers/LogsController.cs +71 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/MaterialController.cs +2 -2
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectLocator.cs +4 -4
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs +3 -3
- package/bridge/com.ucp.bridge/Editor/Controllers/PrefabController.cs +6 -6
- package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs +30 -14
- package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs +732 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneChangeTracker.cs +3 -3
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +3 -3
- package/bridge/com.ucp.bridge/Editor/Controllers/SnapshotController.cs +5 -5
- package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +11 -2
- package/bridge/com.ucp.bridge/Editor/Controllers/TransformController.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs +70 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/UiController.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ViewController.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs +468 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiHost.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs +554 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiLintService.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs +870 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiOperationManager.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs +496 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioApplier.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs +854 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioLoader.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs +374 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiScenarioModels.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs +690 -0
- package/bridge/com.ucp.bridge/Editor/Ui/UiVisualTreeInspector.cs.meta +11 -0
- package/bridge/com.ucp.bridge/{Runtime.meta → Editor/Ui.meta} +1 -1
- package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +191 -3
- package/bridge/com.ucp.bridge/Tests/Editor/SpatialVisualControllerTests.cs +2 -2
- package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs +547 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiControllerTests.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs +253 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiLintServiceTests.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs +587 -0
- package/bridge/com.ucp.bridge/Tests/Editor/UiScenarioTests.cs.meta +11 -0
- package/bridge/com.ucp.bridge/package.json +1 -1
- package/package.json +1 -1
- package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef +0 -14
- package/bridge/com.ucp.bridge/Runtime/UCP.Bridge.Runtime.asmdef.meta +0 -7
|
@@ -109,6 +109,30 @@ namespace UCP.Bridge
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/// <summary>
|
|
113
|
+
/// Error/exception and warning counts in the bridge history after <paramref name="afterId"/>.
|
|
114
|
+
/// Walks back from the newest entry and stops at the cursor, so the cost is proportional to
|
|
115
|
+
/// what the current request logged, not to the history size.
|
|
116
|
+
/// </summary>
|
|
117
|
+
public static void CountLevels(long afterId, out int errors, out int warnings)
|
|
118
|
+
{
|
|
119
|
+
errors = 0;
|
|
120
|
+
warnings = 0;
|
|
121
|
+
lock (s_historyLock)
|
|
122
|
+
{
|
|
123
|
+
for (var index = s_history.Count - 1; index >= 0; index--)
|
|
124
|
+
{
|
|
125
|
+
var entry = s_history[index];
|
|
126
|
+
if (entry.Id <= afterId)
|
|
127
|
+
break;
|
|
128
|
+
if (entry.Level == "error" || entry.Level == "exception")
|
|
129
|
+
errors++;
|
|
130
|
+
else if (entry.Level == "warning")
|
|
131
|
+
warnings++;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
112
136
|
public static long GetLatestId()
|
|
113
137
|
{
|
|
114
138
|
SeedHistoryFromConsole();
|
|
@@ -132,6 +156,53 @@ namespace UCP.Bridge
|
|
|
132
156
|
}
|
|
133
157
|
}
|
|
134
158
|
|
|
159
|
+
/// <summary>
|
|
160
|
+
/// Status summary for the test-run console guard. Unity's test runner writes
|
|
161
|
+
/// "IgnoreFailingMessages:true" / "IgnoreFailingMessages:false" log lines whenever a test
|
|
162
|
+
/// toggles <c>LogAssert.ignoreFailingMessages</c>; everything logged inside such a window is
|
|
163
|
+
/// noise the test declared as expected, so it must not fail the guard. The markers
|
|
164
|
+
/// themselves are dropped as well.
|
|
165
|
+
/// </summary>
|
|
166
|
+
public static Dictionary<string, object> BuildTestGuardSummary(long afterId)
|
|
167
|
+
{
|
|
168
|
+
SeedHistoryFromConsole();
|
|
169
|
+
lock (s_historyLock)
|
|
170
|
+
{
|
|
171
|
+
var ordered = s_history
|
|
172
|
+
.Where(entry => entry.Id > afterId)
|
|
173
|
+
.OrderBy(entry => entry.Id)
|
|
174
|
+
.ToList();
|
|
175
|
+
|
|
176
|
+
return BuildStatusResult(ExcludeExpectedNoise(ordered, entry => entry.Message), afterId);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
internal const string IgnoreFailingMessagesOnMarker = "IgnoreFailingMessages:true";
|
|
181
|
+
internal const string IgnoreFailingMessagesOffMarker = "IgnoreFailingMessages:false";
|
|
182
|
+
|
|
183
|
+
internal static List<T> ExcludeExpectedNoise<T>(IEnumerable<T> entries, Func<T, string> message)
|
|
184
|
+
{
|
|
185
|
+
var result = new List<T>();
|
|
186
|
+
var ignoring = false;
|
|
187
|
+
foreach (var entry in entries)
|
|
188
|
+
{
|
|
189
|
+
var text = (message(entry) ?? string.Empty).Trim();
|
|
190
|
+
if (text == IgnoreFailingMessagesOnMarker)
|
|
191
|
+
{
|
|
192
|
+
ignoring = true;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (text == IgnoreFailingMessagesOffMarker)
|
|
196
|
+
{
|
|
197
|
+
ignoring = false;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (!ignoring)
|
|
201
|
+
result.Add(entry);
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
|
|
135
206
|
private static object HandleTail(string paramsJson)
|
|
136
207
|
{
|
|
137
208
|
var query = ParseQuery(paramsJson, includePattern: false);
|
|
@@ -227,7 +227,7 @@ namespace UCP.Bridge
|
|
|
227
227
|
// Resolve by instanceId (scene object's renderer material)
|
|
228
228
|
if (p.TryGetValue("instanceId", out var idObj))
|
|
229
229
|
{
|
|
230
|
-
|
|
230
|
+
long instanceId = Convert.ToInt64(idObj);
|
|
231
231
|
var obj = UnityObjectCompat.ResolveByInstanceId(instanceId);
|
|
232
232
|
|
|
233
233
|
if (obj is Material 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 = UnityObjectCompat.ResolveByInstanceId<Texture>(Convert.
|
|
333
|
+
var tex = UnityObjectCompat.ResolveByInstanceId<Texture>(Convert.ToInt64(tid));
|
|
334
334
|
mat.SetTexture(propName, tex);
|
|
335
335
|
}
|
|
336
336
|
}
|
|
@@ -9,7 +9,7 @@ namespace UCP.Bridge
|
|
|
9
9
|
/// Shared GameObject resolution for the spatial/visual controllers.
|
|
10
10
|
///
|
|
11
11
|
/// A target may be addressed three ways, tried in priority order:
|
|
12
|
-
/// 1. instanceId (
|
|
12
|
+
/// 1. instanceId (64-bit integer) — canonical, survives nothing but a domain reload; preferred.
|
|
13
13
|
/// 2. path (string) — hierarchy path "Root/Child/Leaf" (leading '/' optional),
|
|
14
14
|
/// resolved across all loaded scenes; survives reloads.
|
|
15
15
|
/// 3. name (string) — first GameObject whose name matches; ambiguous under
|
|
@@ -32,7 +32,7 @@ namespace UCP.Bridge
|
|
|
32
32
|
|
|
33
33
|
if ((p.TryGetValue("instanceId", out var idObj) || p.TryGetValue("id", out idObj)) && idObj != null)
|
|
34
34
|
{
|
|
35
|
-
var id = Convert.
|
|
35
|
+
var id = Convert.ToInt64(idObj);
|
|
36
36
|
var byId = FindByInstanceId(id);
|
|
37
37
|
if (byId != null)
|
|
38
38
|
return byId;
|
|
@@ -60,7 +60,7 @@ namespace UCP.Bridge
|
|
|
60
60
|
throw new ArgumentException("Missing target: provide 'instanceId', 'path', or 'name'");
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
internal static GameObject FindByInstanceId(
|
|
63
|
+
internal static GameObject FindByInstanceId(long instanceId)
|
|
64
64
|
{
|
|
65
65
|
var direct = UnityObjectCompat.ResolveByInstanceId<GameObject>(instanceId);
|
|
66
66
|
if (direct != null)
|
|
@@ -82,7 +82,7 @@ namespace UCP.Bridge
|
|
|
82
82
|
return null;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
private static GameObject FindInHierarchyById(GameObject go,
|
|
85
|
+
private static GameObject FindInHierarchyById(GameObject go, long instanceId)
|
|
86
86
|
{
|
|
87
87
|
if (go.GetId() == instanceId)
|
|
88
88
|
return go;
|
|
@@ -39,7 +39,7 @@ namespace UCP.Bridge
|
|
|
39
39
|
if (value is Dictionary<string, object> reference)
|
|
40
40
|
{
|
|
41
41
|
if (reference.TryGetValue("instanceId", out var instanceId) && instanceId != null)
|
|
42
|
-
return ResolveByInstanceId(Convert.
|
|
42
|
+
return ResolveByInstanceId(Convert.ToInt64(instanceId), propertyName);
|
|
43
43
|
|
|
44
44
|
if (reference.TryGetValue("path", out var path) && path != null)
|
|
45
45
|
return ResolveByPath(path.ToString(), propertyName);
|
|
@@ -58,12 +58,12 @@ namespace UCP.Bridge
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
if (value is sbyte || value is byte || value is short || value is ushort || value is int || value is uint || value is long || value is ulong)
|
|
61
|
-
return ResolveByInstanceId(Convert.
|
|
61
|
+
return ResolveByInstanceId(Convert.ToInt64(value), propertyName);
|
|
62
62
|
|
|
63
63
|
throw new ArgumentException($"Unsupported object reference value for '{propertyName}'");
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
private static UnityEngine.Object ResolveByInstanceId(
|
|
66
|
+
private static UnityEngine.Object ResolveByInstanceId(long instanceId, string propertyName)
|
|
67
67
|
{
|
|
68
68
|
var resolved = UnityObjectCompat.ResolveByInstanceId(instanceId);
|
|
69
69
|
if (resolved == null)
|
|
@@ -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 = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.
|
|
29
|
+
var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt64(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 = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.
|
|
66
|
+
var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt64(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 = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.
|
|
91
|
+
var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt64(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 = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.
|
|
119
|
+
var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt64(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 = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.
|
|
150
|
+
var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt64(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 = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.
|
|
194
|
+
var go = UnityObjectCompat.ResolveByInstanceId<GameObject>(Convert.ToInt64(idObj));
|
|
195
195
|
if (go == null)
|
|
196
196
|
throw new ArgumentException($"GameObject not found: {idObj}");
|
|
197
197
|
|
|
@@ -27,7 +27,7 @@ namespace UCP.Bridge
|
|
|
27
27
|
throw new ArgumentException("Missing 'instanceId' parameter");
|
|
28
28
|
|
|
29
29
|
var componentType = p.TryGetValue("component", out var cObj) ? cObj?.ToString() : null;
|
|
30
|
-
|
|
30
|
+
long instanceId = Convert.ToInt64(idObj);
|
|
31
31
|
var go = FindGameObject(instanceId);
|
|
32
32
|
|
|
33
33
|
if (componentType != null)
|
|
@@ -72,19 +72,19 @@ namespace UCP.Bridge
|
|
|
72
72
|
if (!p.TryGetValue("property", out var propObj) || propObj == null)
|
|
73
73
|
throw new ArgumentException("Missing 'property' parameter");
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
long instanceId = Convert.ToInt64(idObj);
|
|
76
76
|
var go = FindGameObject(instanceId);
|
|
77
77
|
var comp = FindComponent(go, cObj.ToString());
|
|
78
78
|
string propName = propObj.ToString();
|
|
79
79
|
|
|
80
|
-
var value = GetPropertyValue(comp, propName);
|
|
80
|
+
var value = GetPropertyValue(comp, propName, out var typeName);
|
|
81
81
|
return new Dictionary<string, object>
|
|
82
82
|
{
|
|
83
83
|
["instanceId"] = instanceId,
|
|
84
84
|
["component"] = cObj.ToString(),
|
|
85
85
|
["property"] = propName,
|
|
86
|
-
["value"] =
|
|
87
|
-
["type"] =
|
|
86
|
+
["value"] = value,
|
|
87
|
+
["type"] = typeName
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -100,7 +100,7 @@ namespace UCP.Bridge
|
|
|
100
100
|
if (!p.ContainsKey("value"))
|
|
101
101
|
throw new ArgumentException("Missing 'value' parameter");
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
long instanceId = Convert.ToInt64(idObj);
|
|
104
104
|
var go = FindGameObject(instanceId);
|
|
105
105
|
var comp = FindComponent(go, cObj.ToString());
|
|
106
106
|
string propName = propObj.ToString();
|
|
@@ -128,7 +128,7 @@ namespace UCP.Bridge
|
|
|
128
128
|
if (!p.TryGetValue("active", out var activeObj))
|
|
129
129
|
throw new ArgumentException("Missing 'active' parameter");
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
long instanceId = Convert.ToInt64(idObj);
|
|
132
132
|
var go = FindGameObject(instanceId);
|
|
133
133
|
|
|
134
134
|
Undo.RecordObject(go, "UCP Set Active");
|
|
@@ -153,7 +153,7 @@ namespace UCP.Bridge
|
|
|
153
153
|
if (!p.TryGetValue("name", out var nameObj) || nameObj == null)
|
|
154
154
|
throw new ArgumentException("Missing 'name' parameter");
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
long instanceId = Convert.ToInt64(idObj);
|
|
157
157
|
var go = FindGameObject(instanceId);
|
|
158
158
|
|
|
159
159
|
Undo.RecordObject(go, "UCP Rename");
|
|
@@ -277,7 +277,7 @@ namespace UCP.Bridge
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
private static object GetPropertyValue(Component comp, string propertyName)
|
|
280
|
+
private static object GetPropertyValue(Component comp, string propertyName, out string typeName)
|
|
281
281
|
{
|
|
282
282
|
var so = new SerializedObject(comp);
|
|
283
283
|
try
|
|
@@ -285,22 +285,35 @@ namespace UCP.Bridge
|
|
|
285
285
|
so.Update();
|
|
286
286
|
var prop = so.FindProperty(propertyName);
|
|
287
287
|
if (prop != null)
|
|
288
|
+
{
|
|
289
|
+
// Already JSON-shaped -- reporting its type from the SerializedProperty keeps
|
|
290
|
+
// `get-property` and `get-fields` describing the same field the same way.
|
|
291
|
+
typeName = prop.propertyType.ToString();
|
|
288
292
|
return SerializedPropertyToValue(prop);
|
|
293
|
+
}
|
|
289
294
|
}
|
|
290
295
|
finally
|
|
291
296
|
{
|
|
292
297
|
so.Dispose();
|
|
293
298
|
}
|
|
294
299
|
|
|
295
|
-
// Fallback to reflection
|
|
300
|
+
// Fallback to reflection for names Unity does not serialize (e.g. Transform.position).
|
|
296
301
|
var type = comp.GetType();
|
|
297
302
|
var fi = type.GetField(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
298
303
|
if (fi != null)
|
|
299
|
-
|
|
304
|
+
{
|
|
305
|
+
var raw = fi.GetValue(comp);
|
|
306
|
+
typeName = raw != null ? raw.GetType().Name : fi.FieldType.Name;
|
|
307
|
+
return ConvertToJson(raw);
|
|
308
|
+
}
|
|
300
309
|
|
|
301
310
|
var pi = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
|
|
302
311
|
if (pi != null && pi.CanRead)
|
|
303
|
-
|
|
312
|
+
{
|
|
313
|
+
var raw = pi.GetValue(comp);
|
|
314
|
+
typeName = raw != null ? raw.GetType().Name : pi.PropertyType.Name;
|
|
315
|
+
return ConvertToJson(raw);
|
|
316
|
+
}
|
|
304
317
|
|
|
305
318
|
throw new ArgumentException($"Property '{propertyName}' not found on {type.Name}");
|
|
306
319
|
}
|
|
@@ -488,6 +501,9 @@ namespace UCP.Bridge
|
|
|
488
501
|
return new List<object> { (double)c.r, (double)c.g, (double)c.b, (double)c.a };
|
|
489
502
|
if (value is UnityEngine.Object uObj)
|
|
490
503
|
return ObjectReferenceResolver.Serialize(uObj);
|
|
504
|
+
// Values that are already JSON-shaped pass through untouched.
|
|
505
|
+
if (value is IList || value is IDictionary)
|
|
506
|
+
return value;
|
|
491
507
|
return value.ToString();
|
|
492
508
|
}
|
|
493
509
|
|
|
@@ -516,7 +532,7 @@ namespace UCP.Bridge
|
|
|
516
532
|
return Convert.ChangeType(jsonValue, targetType);
|
|
517
533
|
}
|
|
518
534
|
|
|
519
|
-
private static GameObject FindGameObject(
|
|
535
|
+
private static GameObject FindGameObject(long instanceId)
|
|
520
536
|
{
|
|
521
537
|
var obj = UnityObjectCompat.ResolveByInstanceId<GameObject>(instanceId);
|
|
522
538
|
if (obj != null) return obj;
|
|
@@ -536,7 +552,7 @@ namespace UCP.Bridge
|
|
|
536
552
|
throw new ArgumentException($"GameObject not found: {instanceId}");
|
|
537
553
|
}
|
|
538
554
|
|
|
539
|
-
private static GameObject FindInHierarchy(GameObject go,
|
|
555
|
+
private static GameObject FindInHierarchy(GameObject go, long instanceId)
|
|
540
556
|
{
|
|
541
557
|
if (go.GetId() == instanceId) return go;
|
|
542
558
|
for (int i = 0; i < go.transform.childCount; i++)
|