@mflrevan/ucp 0.6.0 → 0.6.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.
- package/README.md +1 -1
- package/bridge/com.ucp.bridge/CHANGELOG.md +62 -0
- package/bridge/com.ucp.bridge/Editor/Bridge/BridgeServer.cs +42 -5
- package/bridge/com.ucp.bridge/Editor/Controllers/CompilationController.cs +137 -1
- package/bridge/com.ucp.bridge/Editor/Controllers/ProfilerController.cs +80 -5
- package/bridge/com.ucp.bridge/Editor/Controllers/PropertyController.cs +23 -7
- package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs +724 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/RecordingController.cs.meta +11 -0
- package/bridge/com.ucp.bridge/Editor/Controllers/SceneController.cs +24 -2
- package/bridge/com.ucp.bridge/Editor/Controllers/ScriptController.cs +82 -23
- package/bridge/com.ucp.bridge/Editor/Controllers/TestRunnerController.cs +10 -1
- package/bridge/com.ucp.bridge/Editor/Protocol/MiniJson.cs +409 -63
- package/bridge/com.ucp.bridge/Tests/Editor/ControllerSmokeTests.cs +181 -6
- package/bridge/com.ucp.bridge/Tests/Editor/MiniJsonSerializerTests.cs +221 -0
- package/bridge/com.ucp.bridge/Tests/Editor/MiniJsonSerializerTests.cs.meta +2 -0
- package/bridge/com.ucp.bridge/package.json +1 -1
- package/package.json +1 -1
|
@@ -168,19 +168,41 @@ namespace UCP.Bridge
|
|
|
168
168
|
sceneView.Repaint();
|
|
169
169
|
SceneView.RepaintAll();
|
|
170
170
|
|
|
171
|
+
ResolveSceneViewCamera(sceneView, out var cameraPosition, out var cameraRotation);
|
|
172
|
+
|
|
171
173
|
return new Dictionary<string, object>
|
|
172
174
|
{
|
|
173
175
|
["status"] = "ok",
|
|
174
176
|
["instanceId"] = instanceId,
|
|
175
177
|
["name"] = target.name,
|
|
176
178
|
["pivot"] = VectorToList(sceneView.pivot),
|
|
177
|
-
["cameraPosition"] = VectorToList(
|
|
178
|
-
["cameraRotationEuler"] = VectorToList(
|
|
179
|
+
["cameraPosition"] = VectorToList(cameraPosition),
|
|
180
|
+
["cameraRotationEuler"] = VectorToList(cameraRotation.eulerAngles),
|
|
179
181
|
["size"] = sceneView.size,
|
|
180
182
|
["axis"] = axis.HasValue ? VectorToList(axis.Value.normalized) : null
|
|
181
183
|
};
|
|
182
184
|
}
|
|
183
185
|
|
|
186
|
+
/// <summary>
|
|
187
|
+
/// Derive the Scene view camera pose from the authoritative view state
|
|
188
|
+
/// (<c>pivot</c>/<c>rotation</c>/<c>cameraDistance</c>) rather than reading
|
|
189
|
+
/// <c>sceneView.camera.transform</c>.
|
|
190
|
+
///
|
|
191
|
+
/// <c>LookAtDirect</c> updates the view state immediately, but the camera transform is only
|
|
192
|
+
/// synced when the Scene view actually repaints. <c>Repaint()</c> merely queues that, so in
|
|
193
|
+
/// batch mode - and for any caller reading the response in the same frame as the focus -
|
|
194
|
+
/// the camera transform still holds the *previous* pose and the reported values were simply
|
|
195
|
+
/// wrong.
|
|
196
|
+
/// </summary>
|
|
197
|
+
private static void ResolveSceneViewCamera(
|
|
198
|
+
SceneView sceneView,
|
|
199
|
+
out Vector3 position,
|
|
200
|
+
out Quaternion rotation)
|
|
201
|
+
{
|
|
202
|
+
rotation = sceneView.rotation;
|
|
203
|
+
position = sceneView.pivot - (rotation * Vector3.forward) * sceneView.cameraDistance;
|
|
204
|
+
}
|
|
205
|
+
|
|
184
206
|
private static Vector3? TryReadAxis(Dictionary<string, object> parameters)
|
|
185
207
|
{
|
|
186
208
|
if (parameters == null || !parameters.TryGetValue("axis", out var axisObj) || axisObj == null)
|
|
@@ -12,29 +12,35 @@ namespace UCP.Bridge
|
|
|
12
12
|
router.Register("exec/run", HandleRun);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
/// <summary>
|
|
16
|
+
/// Implementing types, cached for the lifetime of the app domain. The scan itself is the
|
|
17
|
+
/// expensive part -- `GetTypes()` over every loaded assembly -- and its result cannot go
|
|
18
|
+
/// stale without a domain reload, which resets this static anyway.
|
|
19
|
+
/// </summary>
|
|
20
|
+
private static Type[] s_scriptTypes;
|
|
21
|
+
|
|
22
|
+
private static Type[] DiscoverScriptTypes()
|
|
16
23
|
{
|
|
17
|
-
|
|
24
|
+
if (s_scriptTypes != null) return s_scriptTypes;
|
|
25
|
+
|
|
18
26
|
var interfaceType = typeof(IUCPScript);
|
|
27
|
+
var bridgeAssemblyName = interfaceType.Assembly.GetName().Name;
|
|
28
|
+
var types = new List<Type>();
|
|
19
29
|
|
|
20
30
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
|
21
31
|
{
|
|
32
|
+
// A type can only implement IUCPScript if its assembly references the one that
|
|
33
|
+
// declares it. Checking cheap reference metadata first avoids materialising the
|
|
34
|
+
// full type list of every framework and Unity assembly in the domain.
|
|
35
|
+
if (assembly != interfaceType.Assembly && !ReferencesAssembly(assembly, bridgeAssemblyName))
|
|
36
|
+
continue;
|
|
37
|
+
|
|
22
38
|
try
|
|
23
39
|
{
|
|
24
40
|
foreach (var type in assembly.GetTypes())
|
|
25
41
|
{
|
|
26
42
|
if (interfaceType.IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface)
|
|
27
|
-
|
|
28
|
-
try
|
|
29
|
-
{
|
|
30
|
-
var instance = (IUCPScript)Activator.CreateInstance(type);
|
|
31
|
-
scripts.Add(instance);
|
|
32
|
-
}
|
|
33
|
-
catch (Exception ex)
|
|
34
|
-
{
|
|
35
|
-
Debug.LogWarning($"[UCP] Failed to instantiate script {type.Name}: {ex.Message}");
|
|
36
|
-
}
|
|
37
|
-
}
|
|
43
|
+
types.Add(type);
|
|
38
44
|
}
|
|
39
45
|
}
|
|
40
46
|
catch (System.Reflection.ReflectionTypeLoadException)
|
|
@@ -43,9 +49,71 @@ namespace UCP.Bridge
|
|
|
43
49
|
}
|
|
44
50
|
}
|
|
45
51
|
|
|
52
|
+
s_scriptTypes = types.ToArray();
|
|
53
|
+
return s_scriptTypes;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private static bool ReferencesAssembly(System.Reflection.Assembly assembly, string name)
|
|
57
|
+
{
|
|
58
|
+
try
|
|
59
|
+
{
|
|
60
|
+
foreach (var reference in assembly.GetReferencedAssemblies())
|
|
61
|
+
{
|
|
62
|
+
if (string.Equals(reference.Name, name, StringComparison.Ordinal)) return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch
|
|
66
|
+
{
|
|
67
|
+
// Dynamic assemblies can refuse to report references; treat them as non-matching.
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private static IUCPScript Instantiate(Type type)
|
|
74
|
+
{
|
|
75
|
+
try
|
|
76
|
+
{
|
|
77
|
+
return (IUCPScript)Activator.CreateInstance(type);
|
|
78
|
+
}
|
|
79
|
+
catch (Exception ex)
|
|
80
|
+
{
|
|
81
|
+
Debug.LogWarning($"[UCP] Failed to instantiate script {type.Name}: {ex.Message}");
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private static List<IUCPScript> DiscoverScripts()
|
|
87
|
+
{
|
|
88
|
+
var scripts = new List<IUCPScript>();
|
|
89
|
+
foreach (var type in DiscoverScriptTypes())
|
|
90
|
+
{
|
|
91
|
+
var instance = Instantiate(type);
|
|
92
|
+
if (instance != null) scripts.Add(instance);
|
|
93
|
+
}
|
|
94
|
+
|
|
46
95
|
return scripts;
|
|
47
96
|
}
|
|
48
97
|
|
|
98
|
+
/// <summary>
|
|
99
|
+
/// Resolve one script by name, stopping at the first match.
|
|
100
|
+
/// `Name` is an instance member, so candidates must be constructed to be identified --
|
|
101
|
+
/// but running *every* script's constructor to invoke one of them is a side effect nobody
|
|
102
|
+
/// asked for, so stop as soon as the target is found.
|
|
103
|
+
/// </summary>
|
|
104
|
+
private static IUCPScript FindScript(string name)
|
|
105
|
+
{
|
|
106
|
+
foreach (var type in DiscoverScriptTypes())
|
|
107
|
+
{
|
|
108
|
+
var instance = Instantiate(type);
|
|
109
|
+
if (instance == null) continue;
|
|
110
|
+
if (string.Equals(instance.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
111
|
+
return instance;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
49
117
|
private static object HandleList(string paramsJson)
|
|
50
118
|
{
|
|
51
119
|
var scripts = DiscoverScripts();
|
|
@@ -78,16 +146,7 @@ namespace UCP.Bridge
|
|
|
78
146
|
if (p.TryGetValue("params", out var paramsObj) && paramsObj != null)
|
|
79
147
|
scriptParams = MiniJson.Serialize(paramsObj);
|
|
80
148
|
|
|
81
|
-
var
|
|
82
|
-
IUCPScript target = null;
|
|
83
|
-
foreach (var s in scripts)
|
|
84
|
-
{
|
|
85
|
-
if (string.Equals(s.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
86
|
-
{
|
|
87
|
-
target = s;
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
149
|
+
var target = FindScript(name);
|
|
91
150
|
|
|
92
151
|
if (target == null)
|
|
93
152
|
throw new ArgumentException($"Script not found: {name}. Use exec/list to see available scripts.");
|
|
@@ -54,7 +54,10 @@ namespace UCP.Bridge
|
|
|
54
54
|
|
|
55
55
|
if (!string.IsNullOrEmpty(filter))
|
|
56
56
|
{
|
|
57
|
-
|
|
57
|
+
// groupNames is regex-matched against each test's full name, so a bare class or
|
|
58
|
+
// method name selects what a caller expects. testNames requires an exact
|
|
59
|
+
// fully-qualified match, which silently selected nothing for "ControllerSmokeTests".
|
|
60
|
+
executionSettings.filters[0].groupNames = new[] { filter };
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
var shouldWaitForPlayModeExit =
|
|
@@ -208,6 +211,12 @@ namespace UCP.Bridge
|
|
|
208
211
|
return;
|
|
209
212
|
}
|
|
210
213
|
|
|
214
|
+
// A filter that matches nothing still yields a root suite -- childless, and named
|
|
215
|
+
// after the project. Counting it as a leaf reported "1 passed" for a run that
|
|
216
|
+
// executed no tests, so a typo'd filter looked like a green suite.
|
|
217
|
+
if (result.Test != null && result.Test.IsSuite)
|
|
218
|
+
return;
|
|
219
|
+
|
|
211
220
|
string status;
|
|
212
221
|
switch (result.TestStatus)
|
|
213
222
|
{
|