@mflrevan/ucp 0.3.2 → 0.4.0
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 +3 -3
- package/bridge/com.ucp.bridge/CHANGELOG.md +30 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +1 -1
- package/bridge/com.ucp.bridge/Editor/Controllers/EditorController.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/FileController.cs +15 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/ObjectReferenceResolver.cs.meta +2 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +158 -0
- package/bridge/com.ucp.bridge/Editor/Protocol/CommandRouter.cs +8 -0
- package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +81 -1
- package/bridge/com.ucp.bridge/package.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @mflrevan/ucp
|
|
2
2
|
|
|
3
|
-
Version `0.
|
|
3
|
+
Version `0.4.0` 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
|
|
|
@@ -30,7 +30,7 @@ pnpm approve-builds
|
|
|
30
30
|
cd /path/to/MyUnityProject
|
|
31
31
|
ucp doctor
|
|
32
32
|
ucp connect
|
|
33
|
-
ucp snapshot
|
|
33
|
+
ucp scene snapshot
|
|
34
34
|
ucp object get-fields --id 46894 --component Transform
|
|
35
35
|
ucp asset search -t Material
|
|
36
36
|
ucp build targets
|
|
@@ -49,7 +49,7 @@ Or add this to `Packages/manifest.json`:
|
|
|
49
49
|
```json
|
|
50
50
|
{
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"com.ucp.bridge": "https://github.com/mflRevan/unity-control-protocol.git?path=unity-package/com.ucp.bridge#v0.
|
|
52
|
+
"com.ucp.bridge": "https://github.com/mflRevan/unity-control-protocol.git?path=unity-package/com.ucp.bridge#v0.4.0"
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
```
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2026-03-15
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added `scene/focus` so the CLI can align the Unity Scene view to a target object for screenshot-driven iteration.
|
|
8
|
+
- Added smoke coverage for asset refresh after `file/write` and Scene view focus axis handling.
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- `scene/focus` now exposes the stable axis-alignment workflow only, without public distance overrides.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Fixed `file/write` and `file/patch` so changes under `Assets/` and `Packages/` trigger a synchronous `AssetDatabase.Refresh`, making newly created scripts and assets available immediately.
|
|
17
|
+
- Fixed Scene view focus behavior and validation coverage so live automation and package smoke tests agree on the resulting alignment.
|
|
18
|
+
|
|
19
|
+
## [0.3.3] - 2026-03-14
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Added missing Unity metadata for `EditorController.cs` and `ObjectReferenceResolver.cs` so both controllers import reliably in embedded and tracked package installs.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- `CommandRouter` now maps `ArgumentException` to `InvalidParams` and `UnauthorizedAccessException` to `FileAccessDenied` without emitting misleading internal-error logs.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Fixed negative smoke tests around unresolved object references and project-root path traversal.
|
|
32
|
+
|
|
3
33
|
## [0.3.2] - 2026-03-14
|
|
4
34
|
|
|
5
35
|
### Added
|
|
@@ -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.
|
|
29
|
+
private const string ProtocolVersion = "0.4.0";
|
|
30
30
|
|
|
31
31
|
private static TcpListener s_listener;
|
|
32
32
|
private static CancellationTokenSource s_cts;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
using System;
|
|
2
2
|
using System.Collections.Generic;
|
|
3
3
|
using System.IO;
|
|
4
|
+
using UnityEditor;
|
|
4
5
|
using UnityEngine;
|
|
5
6
|
|
|
6
7
|
namespace UCP.Bridge
|
|
@@ -67,6 +68,7 @@ namespace UCP.Bridge
|
|
|
67
68
|
Directory.CreateDirectory(dir);
|
|
68
69
|
|
|
69
70
|
File.WriteAllText(fullPath, contentObj.ToString());
|
|
71
|
+
RefreshProjectAssets(pathObj.ToString());
|
|
70
72
|
|
|
71
73
|
return new Dictionary<string, object>
|
|
72
74
|
{
|
|
@@ -116,6 +118,7 @@ namespace UCP.Bridge
|
|
|
116
118
|
|
|
117
119
|
var patched = original.Replace(find, replace);
|
|
118
120
|
File.WriteAllText(fullPath, patched);
|
|
121
|
+
RefreshProjectAssets(pathObj.ToString());
|
|
119
122
|
|
|
120
123
|
return new Dictionary<string, object>
|
|
121
124
|
{
|
|
@@ -126,5 +129,17 @@ namespace UCP.Bridge
|
|
|
126
129
|
|
|
127
130
|
throw new ArgumentException("Unsupported patch format. Use {\"find\": \"...\", \"replace\": \"...\"}");
|
|
128
131
|
}
|
|
132
|
+
|
|
133
|
+
private static void RefreshProjectAssets(string relativePath)
|
|
134
|
+
{
|
|
135
|
+
var normalized = relativePath.Replace('\\', '/');
|
|
136
|
+
if (normalized.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase)
|
|
137
|
+
|| normalized.Equals("Assets", StringComparison.OrdinalIgnoreCase)
|
|
138
|
+
|| normalized.StartsWith("Packages/", StringComparison.OrdinalIgnoreCase)
|
|
139
|
+
|| normalized.Equals("Packages", StringComparison.OrdinalIgnoreCase))
|
|
140
|
+
{
|
|
141
|
+
AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
129
144
|
}
|
|
130
145
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
using System.Collections.Generic;
|
|
2
2
|
using UnityEditor;
|
|
3
3
|
using UnityEditor.SceneManagement;
|
|
4
|
+
using UnityEngine;
|
|
4
5
|
using UnityEngine.SceneManagement;
|
|
5
6
|
|
|
6
7
|
namespace UCP.Bridge
|
|
@@ -12,6 +13,7 @@ namespace UCP.Bridge
|
|
|
12
13
|
router.Register("scene/list", HandleList);
|
|
13
14
|
router.Register("scene/load", HandleLoad);
|
|
14
15
|
router.Register("scene/active", HandleActive);
|
|
16
|
+
router.Register("scene/focus", HandleFocus);
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
private static object HandleList(string paramsJson)
|
|
@@ -107,5 +109,161 @@ namespace UCP.Bridge
|
|
|
107
109
|
["rootCount"] = scene.rootCount
|
|
108
110
|
};
|
|
109
111
|
}
|
|
112
|
+
|
|
113
|
+
private static object HandleFocus(string paramsJson)
|
|
114
|
+
{
|
|
115
|
+
var parameters = MiniJson.Deserialize(paramsJson) as Dictionary<string, object>;
|
|
116
|
+
if (parameters == null || !parameters.TryGetValue("instanceId", out var idObj))
|
|
117
|
+
throw new System.ArgumentException("Missing 'instanceId' parameter");
|
|
118
|
+
|
|
119
|
+
var instanceId = System.Convert.ToInt32(idObj);
|
|
120
|
+
var target = FindGameObject(instanceId);
|
|
121
|
+
var bounds = CalculateFocusBounds(target);
|
|
122
|
+
var sceneView = SceneView.lastActiveSceneView ?? EditorWindow.GetWindow<SceneView>();
|
|
123
|
+
|
|
124
|
+
if (sceneView == null)
|
|
125
|
+
throw new System.InvalidOperationException("Unable to open Scene view");
|
|
126
|
+
|
|
127
|
+
sceneView.Show();
|
|
128
|
+
sceneView.Focus();
|
|
129
|
+
Selection.activeGameObject = target;
|
|
130
|
+
|
|
131
|
+
var focusPoint = bounds.center;
|
|
132
|
+
var focusSize = Mathf.Max(bounds.extents.magnitude * 2f, 1f);
|
|
133
|
+
var axis = TryReadAxis(parameters);
|
|
134
|
+
|
|
135
|
+
if (axis.HasValue)
|
|
136
|
+
{
|
|
137
|
+
var normalizedAxis = axis.Value.normalized;
|
|
138
|
+
var rotation = Quaternion.LookRotation(-normalizedAxis, SelectUpVector(normalizedAxis));
|
|
139
|
+
sceneView.LookAtDirect(focusPoint, rotation, focusSize);
|
|
140
|
+
}
|
|
141
|
+
else
|
|
142
|
+
{
|
|
143
|
+
sceneView.LookAtDirect(focusPoint, sceneView.rotation, focusSize);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
sceneView.Repaint();
|
|
147
|
+
SceneView.RepaintAll();
|
|
148
|
+
|
|
149
|
+
return new Dictionary<string, object>
|
|
150
|
+
{
|
|
151
|
+
["status"] = "ok",
|
|
152
|
+
["instanceId"] = instanceId,
|
|
153
|
+
["name"] = target.name,
|
|
154
|
+
["pivot"] = VectorToList(sceneView.pivot),
|
|
155
|
+
["cameraPosition"] = VectorToList(sceneView.camera.transform.position),
|
|
156
|
+
["cameraRotationEuler"] = VectorToList(sceneView.camera.transform.rotation.eulerAngles),
|
|
157
|
+
["size"] = sceneView.size,
|
|
158
|
+
["axis"] = axis.HasValue ? VectorToList(axis.Value.normalized) : null
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private static Vector3? TryReadAxis(Dictionary<string, object> parameters)
|
|
163
|
+
{
|
|
164
|
+
if (parameters == null || !parameters.TryGetValue("axis", out var axisObj) || axisObj == null)
|
|
165
|
+
return null;
|
|
166
|
+
|
|
167
|
+
if (axisObj is not List<object> values || values.Count != 3)
|
|
168
|
+
throw new System.ArgumentException("axis must be an array of exactly three numeric values");
|
|
169
|
+
|
|
170
|
+
var axis = new Vector3(
|
|
171
|
+
System.Convert.ToSingle(values[0]),
|
|
172
|
+
System.Convert.ToSingle(values[1]),
|
|
173
|
+
System.Convert.ToSingle(values[2]));
|
|
174
|
+
|
|
175
|
+
if (axis.sqrMagnitude < 0.0001f)
|
|
176
|
+
throw new System.ArgumentException("axis must not be the zero vector");
|
|
177
|
+
|
|
178
|
+
return axis;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private static Vector3 SelectUpVector(Vector3 axis)
|
|
182
|
+
{
|
|
183
|
+
if (Mathf.Abs(Vector3.Dot(axis, Vector3.up)) > 0.98f)
|
|
184
|
+
return Vector3.forward;
|
|
185
|
+
|
|
186
|
+
return Vector3.up;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private static Bounds CalculateFocusBounds(GameObject target)
|
|
190
|
+
{
|
|
191
|
+
var hasBounds = false;
|
|
192
|
+
var bounds = new Bounds(target.transform.position, Vector3.one);
|
|
193
|
+
|
|
194
|
+
foreach (var renderer in target.GetComponentsInChildren<Renderer>())
|
|
195
|
+
{
|
|
196
|
+
if (!hasBounds)
|
|
197
|
+
{
|
|
198
|
+
bounds = renderer.bounds;
|
|
199
|
+
hasBounds = true;
|
|
200
|
+
}
|
|
201
|
+
else
|
|
202
|
+
{
|
|
203
|
+
bounds.Encapsulate(renderer.bounds);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
foreach (var collider in target.GetComponentsInChildren<Collider>())
|
|
208
|
+
{
|
|
209
|
+
if (!hasBounds)
|
|
210
|
+
{
|
|
211
|
+
bounds = collider.bounds;
|
|
212
|
+
hasBounds = true;
|
|
213
|
+
}
|
|
214
|
+
else
|
|
215
|
+
{
|
|
216
|
+
bounds.Encapsulate(collider.bounds);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (!hasBounds)
|
|
221
|
+
bounds = new Bounds(target.transform.position, Vector3.one);
|
|
222
|
+
|
|
223
|
+
return bounds;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private static GameObject FindGameObject(int instanceId)
|
|
227
|
+
{
|
|
228
|
+
var direct = EditorUtility.InstanceIDToObject(instanceId) as GameObject;
|
|
229
|
+
if (direct != null)
|
|
230
|
+
return direct;
|
|
231
|
+
|
|
232
|
+
for (var index = 0; index < SceneManager.sceneCount; index++)
|
|
233
|
+
{
|
|
234
|
+
var scene = SceneManager.GetSceneAt(index);
|
|
235
|
+
if (!scene.isLoaded)
|
|
236
|
+
continue;
|
|
237
|
+
|
|
238
|
+
foreach (var root in scene.GetRootGameObjects())
|
|
239
|
+
{
|
|
240
|
+
var found = FindInHierarchy(root, instanceId);
|
|
241
|
+
if (found != null)
|
|
242
|
+
return found;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
throw new System.ArgumentException($"GameObject not found: {instanceId}");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private static GameObject FindInHierarchy(GameObject gameObject, int instanceId)
|
|
250
|
+
{
|
|
251
|
+
if (gameObject.GetInstanceID() == instanceId)
|
|
252
|
+
return gameObject;
|
|
253
|
+
|
|
254
|
+
foreach (Transform child in gameObject.transform)
|
|
255
|
+
{
|
|
256
|
+
var found = FindInHierarchy(child.gameObject, instanceId);
|
|
257
|
+
if (found != null)
|
|
258
|
+
return found;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private static List<object> VectorToList(Vector3 value)
|
|
265
|
+
{
|
|
266
|
+
return new List<object> { value.x, value.y, value.z };
|
|
267
|
+
}
|
|
110
268
|
}
|
|
111
269
|
}
|
|
@@ -31,6 +31,14 @@ namespace UCP.Bridge
|
|
|
31
31
|
var result = handler(paramsJson);
|
|
32
32
|
return JsonRpcResponse.Success(id, result);
|
|
33
33
|
}
|
|
34
|
+
catch (ArgumentException ex)
|
|
35
|
+
{
|
|
36
|
+
return JsonRpcResponse.Error(id, ErrorCodes.InvalidParams, ex.Message);
|
|
37
|
+
}
|
|
38
|
+
catch (UnauthorizedAccessException ex)
|
|
39
|
+
{
|
|
40
|
+
return JsonRpcResponse.Error(id, ErrorCodes.FileAccessDenied, ex.Message);
|
|
41
|
+
}
|
|
34
42
|
catch (Exception ex)
|
|
35
43
|
{
|
|
36
44
|
Debug.LogError($"[UCP] Error handling '{method}': {ex}");
|
|
@@ -17,6 +17,7 @@ namespace UCP.Bridge.Tests
|
|
|
17
17
|
private const string TempPrefabPath = "Assets/UcpControllerSmoke.prefab";
|
|
18
18
|
private const string TempMaterialPath = "Assets/UcpControllerSmoke.mat";
|
|
19
19
|
private const string TempTextPath = "Assets/UcpControllerSmoke.txt";
|
|
20
|
+
private const string TempScriptPath = "Assets/UcpControllerSmokeComponent.cs";
|
|
20
21
|
|
|
21
22
|
private CommandRouter _router;
|
|
22
23
|
|
|
@@ -34,12 +35,14 @@ namespace UCP.Bridge.Tests
|
|
|
34
35
|
PrefabController.Register(_router);
|
|
35
36
|
BuildController.Register(_router);
|
|
36
37
|
EditorSettingsController.Register(_router);
|
|
38
|
+
SceneController.Register(_router);
|
|
37
39
|
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
|
38
40
|
DeleteTempAsset();
|
|
39
41
|
DeleteTempReferenceAsset();
|
|
40
42
|
DeleteTempPrefab();
|
|
41
43
|
DeleteTempMaterial();
|
|
42
44
|
DeleteTempTextFile();
|
|
45
|
+
DeleteTempScriptFile();
|
|
43
46
|
LogsController.ClearHistoryForTests();
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -51,6 +54,7 @@ namespace UCP.Bridge.Tests
|
|
|
51
54
|
DeleteTempPrefab();
|
|
52
55
|
DeleteTempMaterial();
|
|
53
56
|
DeleteTempTextFile();
|
|
57
|
+
DeleteTempScriptFile();
|
|
54
58
|
LogsController.ClearHistoryForTests();
|
|
55
59
|
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
|
56
60
|
}
|
|
@@ -301,6 +305,7 @@ namespace UCP.Bridge.Tests
|
|
|
301
305
|
);
|
|
302
306
|
|
|
303
307
|
Assert.That(response.error, Is.Not.Null);
|
|
308
|
+
Assert.That(response.error.code, Is.EqualTo(ErrorCodes.InvalidParams));
|
|
304
309
|
}
|
|
305
310
|
|
|
306
311
|
[Test]
|
|
@@ -348,9 +353,75 @@ namespace UCP.Bridge.Tests
|
|
|
348
353
|
var readResult = (Dictionary<string, object>)read.result;
|
|
349
354
|
Assert.That(readResult["content"].ToString(), Is.EqualTo("hello patched"));
|
|
350
355
|
|
|
351
|
-
LogAssert.Expect(LogType.Error, new Regex("\\[UCP\\] Error handling 'file/read':"));
|
|
352
356
|
var traversal = _router.Dispatch("file/read", 1, "{\"path\":\"../outside.txt\"}");
|
|
353
357
|
Assert.That(traversal.error, Is.Not.Null);
|
|
358
|
+
Assert.That(traversal.error.code, Is.EqualTo(ErrorCodes.FileAccessDenied));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
[Test]
|
|
362
|
+
public void FileController_Write_RefreshesAssetDatabaseForNewAssets()
|
|
363
|
+
{
|
|
364
|
+
var write = _router.Dispatch(
|
|
365
|
+
"file/write",
|
|
366
|
+
1,
|
|
367
|
+
"{\"path\":\"Assets/UcpControllerSmokeComponent.cs\",\"content\":\"using UnityEngine; public class UcpControllerSmokeComponent : MonoBehaviour {}\"}"
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
Assert.That(write.error, Is.Null);
|
|
371
|
+
|
|
372
|
+
var script = AssetDatabase.LoadAssetAtPath<MonoScript>(TempScriptPath);
|
|
373
|
+
Assert.That(script, Is.Not.Null);
|
|
374
|
+
Assert.That(script.name, Is.EqualTo("UcpControllerSmokeComponent"));
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
[Test]
|
|
378
|
+
public void SceneFocus_WithAxis_AlignsSceneCameraTowardTarget()
|
|
379
|
+
{
|
|
380
|
+
var sceneView = EditorWindow.GetWindow<SceneView>();
|
|
381
|
+
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
382
|
+
cube.name = "FocusTarget";
|
|
383
|
+
cube.transform.position = new Vector3(2f, 1f, 3f);
|
|
384
|
+
cube.transform.localScale = new Vector3(2f, 2f, 2f);
|
|
385
|
+
|
|
386
|
+
var response = _router.Dispatch(
|
|
387
|
+
"scene/focus",
|
|
388
|
+
1,
|
|
389
|
+
"{\"instanceId\":" + cube.GetInstanceID() + ",\"axis\":[1,0,1]}"
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
Assert.That(response.error, Is.Null);
|
|
393
|
+
|
|
394
|
+
var result = (Dictionary<string, object>)response.result;
|
|
395
|
+
Assert.That(result["name"].ToString(), Is.EqualTo("FocusTarget"));
|
|
396
|
+
Assert.That(Selection.activeGameObject, Is.EqualTo(cube));
|
|
397
|
+
|
|
398
|
+
var expectedDirection = new Vector3(1f, 0f, 1f).normalized;
|
|
399
|
+
var axisData = (List<object>)result["axis"];
|
|
400
|
+
var returnedAxis = new Vector3(
|
|
401
|
+
System.Convert.ToSingle(axisData[0]),
|
|
402
|
+
System.Convert.ToSingle(axisData[1]),
|
|
403
|
+
System.Convert.ToSingle(axisData[2]));
|
|
404
|
+
var actualForward = sceneView.camera.transform.forward;
|
|
405
|
+
Assert.That(Vector3.Dot(returnedAxis.normalized, expectedDirection), Is.GreaterThan(0.98f));
|
|
406
|
+
Assert.That(Mathf.Abs(Vector3.Dot(actualForward.normalized, expectedDirection)), Is.GreaterThan(0.98f));
|
|
407
|
+
Assert.That(Vector3.Distance(sceneView.pivot, cube.transform.position), Is.LessThan(2f));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
[Test]
|
|
411
|
+
public void SceneFocus_RejectsZeroAxisVector()
|
|
412
|
+
{
|
|
413
|
+
EditorWindow.GetWindow<SceneView>();
|
|
414
|
+
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
415
|
+
cube.name = "ZeroAxisTarget";
|
|
416
|
+
|
|
417
|
+
var response = _router.Dispatch(
|
|
418
|
+
"scene/focus",
|
|
419
|
+
1,
|
|
420
|
+
"{\"instanceId\":" + cube.GetInstanceID() + ",\"axis\":[0,0,0]}"
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
Assert.That(response.error, Is.Not.Null);
|
|
424
|
+
Assert.That(response.error.code, Is.EqualTo(ErrorCodes.InvalidParams));
|
|
354
425
|
}
|
|
355
426
|
|
|
356
427
|
[Test]
|
|
@@ -531,6 +602,15 @@ namespace UCP.Bridge.Tests
|
|
|
531
602
|
}
|
|
532
603
|
}
|
|
533
604
|
|
|
605
|
+
private static void DeleteTempScriptFile()
|
|
606
|
+
{
|
|
607
|
+
if (AssetDatabase.LoadMainAssetAtPath(TempScriptPath) != null)
|
|
608
|
+
{
|
|
609
|
+
AssetDatabase.DeleteAsset(TempScriptPath);
|
|
610
|
+
AssetDatabase.SaveAssets();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
534
614
|
private static string FindFirstFloatOrRangeProperty(Shader shader)
|
|
535
615
|
{
|
|
536
616
|
for (var index = 0; index < shader.GetPropertyCount(); index++)
|