com.valectric.mooserunner 2.1.15 → 2.1.17
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.
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
"MooseRunner.Demo.Support",
|
|
7
7
|
"UniTask",
|
|
8
8
|
"MooseRunner.helper",
|
|
9
|
+
"MooseRunner.Editor",
|
|
9
10
|
"MooseRunner.Runtime"
|
|
10
11
|
],
|
|
11
|
-
"includePlatforms": [
|
|
12
|
+
"includePlatforms": [
|
|
13
|
+
"Editor"
|
|
14
|
+
],
|
|
12
15
|
"excludePlatforms": [],
|
|
13
16
|
"allowUnsafeCode": false,
|
|
14
17
|
"precompiledReferences": [
|
|
@@ -5,6 +5,9 @@ using System.Collections;
|
|
|
5
5
|
using Object = UnityEngine.Object;
|
|
6
6
|
using MooseRunner.Multiplaytest;
|
|
7
7
|
using MooseRunner.helper;
|
|
8
|
+
using MooseRunner.SessionRecorder;
|
|
9
|
+
using System.IO;
|
|
10
|
+
using System.Threading;
|
|
8
11
|
using System.Threading.Tasks;
|
|
9
12
|
|
|
10
13
|
namespace MooseRunner.Internal.Tests
|
|
@@ -204,67 +207,115 @@ namespace MooseRunner.Internal.Tests
|
|
|
204
207
|
|
|
205
208
|
/// <summary>
|
|
206
209
|
/// Tests the "Dying" mechanic, ensuring the entity is destroyed or marked dead when health reaches zero.
|
|
210
|
+
/// Also demonstrates SessionRecorder usage: records the test, then asks Gemini to describe what happened.
|
|
211
|
+
/// When Unity Recorder isn't installed every facade call throws InvalidOperationException with install
|
|
212
|
+
/// instructions; the catches log the message so all three throw sites surface in the test output.
|
|
213
|
+
/// The Stop and Analyze calls run in a finally block so they fire even when the ghost-cat scenario
|
|
214
|
+
/// fails — important for demonstrating all three throw sites in a customer install.
|
|
207
215
|
/// </summary>
|
|
208
216
|
[Test]
|
|
209
217
|
public async Task TestDying()
|
|
210
218
|
{
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
Assert.IsNotNull(ghostCatPrefab, "The Ghost_Cat prefab could not be found in the Resources folder.");
|
|
219
|
+
SessionInfo recordingSession = null;
|
|
220
|
+
string outputPath = Path.Combine(Application.dataPath, "../.mooserunner/Recordings/TestDying");
|
|
214
221
|
|
|
215
|
-
//
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
222
|
+
// SessionRecorder soft-dep: start a recording. Throws with install instructions if
|
|
223
|
+
// com.unity.recorder isn't installed.
|
|
224
|
+
try
|
|
225
|
+
{
|
|
226
|
+
var cfg = new SessionRecordingConfig(Camera.main, outputPath);
|
|
227
|
+
recordingSession = await SessionRecorderFacade.Instance.StartRecordingAsync(cfg, CancellationToken.None);
|
|
228
|
+
Debug.Log("[SessionRecorder] Started recording: " + recordingSession.SessionPath);
|
|
229
|
+
}
|
|
230
|
+
catch (InvalidOperationException ex)
|
|
231
|
+
{
|
|
232
|
+
Debug.LogWarning("[SessionRecorder] StartRecordingAsync threw: " + ex.Message);
|
|
233
|
+
}
|
|
219
234
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
235
|
+
try
|
|
236
|
+
{
|
|
237
|
+
// Load the "Ghost_Cat" prefab from the Resources folder
|
|
238
|
+
GameObject ghostCatPrefab = Resources.Load<GameObject>("Ghost_Cat");
|
|
239
|
+
Assert.IsNotNull(ghostCatPrefab, "The Ghost_Cat prefab could not be found in the Resources folder.");
|
|
223
240
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
0.5f); // Position the wall directly in front of the Ghost_Cat
|
|
241
|
+
// Spawn the "Ghost_Cat" prefab into the scene
|
|
242
|
+
GameObject ghostCatInstance =
|
|
243
|
+
Object.Instantiate(ghostCatPrefab, new Vector3(0f, 2f, 0f), Quaternion.identity);
|
|
244
|
+
Assert.IsNotNull(ghostCatInstance, "Failed to instantiate the Ghost_Cat prefab.");
|
|
229
245
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
wallRigidbody.isKinematic = true;
|
|
246
|
+
// Get the Enemy component
|
|
247
|
+
Enemy enemyComponent = ghostCatInstance.GetComponent<Enemy>();
|
|
248
|
+
Assert.IsNotNull(enemyComponent, "The Ghost_Cat instance does not have an Enemy component.");
|
|
234
249
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
fire.transform.localScale = new Vector3(1f, 1f, 3f); // Scale the box to 2 along the x-axis
|
|
250
|
+
// Create a box object
|
|
251
|
+
GameObject box = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
252
|
+
box.transform.position =
|
|
253
|
+
new Vector3(ghostCatInstance.transform.position.x, 0.5f,
|
|
254
|
+
0.5f); // Position the wall directly in front of the Ghost_Cat
|
|
241
255
|
|
|
242
|
-
|
|
243
|
-
|
|
256
|
+
// Add a Rigidbody and Collider component to ensure collision detection works
|
|
257
|
+
box.AddComponent<BoxCollider>();
|
|
258
|
+
Rigidbody wallRigidbody = box.AddComponent<Rigidbody>();
|
|
259
|
+
wallRigidbody.isKinematic = true;
|
|
244
260
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
261
|
+
// Create a red block simulating fire
|
|
262
|
+
GameObject fire = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
263
|
+
fire.name = "Fire"; // Rename the block to "Fire"
|
|
264
|
+
fire.transform.position =
|
|
265
|
+
new Vector3(ghostCatInstance.transform.position.x, 0f, 2.5f);
|
|
266
|
+
fire.transform.localScale = new Vector3(1f, 1f, 3f);
|
|
248
267
|
|
|
249
|
-
|
|
250
|
-
fire.AddComponent<FireComponent>();
|
|
268
|
+
fire.GetComponent<Renderer>().material.color = Color.red;
|
|
251
269
|
|
|
252
|
-
|
|
253
|
-
|
|
270
|
+
BoxCollider collider = fire.AddComponent<BoxCollider>();
|
|
271
|
+
collider.isTrigger = true;
|
|
254
272
|
|
|
255
|
-
|
|
256
|
-
await Task.Yield();
|
|
273
|
+
fire.AddComponent<FireComponent>();
|
|
257
274
|
|
|
258
|
-
|
|
259
|
-
float initialY = ghostCatInstance.transform.position.y;
|
|
260
|
-
await WaitForSecondsUnity(7f);
|
|
275
|
+
enemyComponent.moveForward = true;
|
|
261
276
|
|
|
262
|
-
|
|
263
|
-
enemyComponent.moveForward = false;
|
|
277
|
+
await Task.Yield();
|
|
264
278
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
279
|
+
float initialY = ghostCatInstance.transform.position.y;
|
|
280
|
+
await WaitForSecondsUnity(7f);
|
|
281
|
+
|
|
282
|
+
enemyComponent.moveForward = false;
|
|
283
|
+
|
|
284
|
+
Assert.IsTrue(ghostCatInstance == null || !ghostCatInstance.activeSelf,
|
|
285
|
+
"The Ghost_Cat was not destroyed or deactivated.");
|
|
286
|
+
}
|
|
287
|
+
finally
|
|
288
|
+
{
|
|
289
|
+
// SessionRecorder soft-dep: stop recording. Throws the same install-instruction
|
|
290
|
+
// message when Recorder isn't installed. In finally so it fires even when the
|
|
291
|
+
// scenario above failed (e.g. prefab/component resolution issues).
|
|
292
|
+
try
|
|
293
|
+
{
|
|
294
|
+
SessionRecorderFacade.Instance.StopRecording();
|
|
295
|
+
Debug.Log("[SessionRecorder] Stopped recording");
|
|
296
|
+
}
|
|
297
|
+
catch (InvalidOperationException ex)
|
|
298
|
+
{
|
|
299
|
+
Debug.LogWarning("[SessionRecorder] StopRecording threw: " + ex.Message);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// SessionRecorder soft-dep: video analysis via Gemini. Same install-instruction
|
|
303
|
+
// message when Recorder isn't installed (different from a Gemini-not-configured
|
|
304
|
+
// error — that one only surfaces once we get past the Recorder gate).
|
|
305
|
+
try
|
|
306
|
+
{
|
|
307
|
+
string sessionPath = recordingSession?.SessionPath ?? outputPath;
|
|
308
|
+
var result = await SessionRecorderFacade.Instance.AnalyzeVideoSegmentAsync(
|
|
309
|
+
sessionPath, 0.0, 5.0,
|
|
310
|
+
"Did the Ghost_Cat catch fire and die?",
|
|
311
|
+
CancellationToken.None);
|
|
312
|
+
Debug.Log("[SessionRecorder] Gemini analysis: " + result.Summary);
|
|
313
|
+
}
|
|
314
|
+
catch (InvalidOperationException ex)
|
|
315
|
+
{
|
|
316
|
+
Debug.LogWarning("[SessionRecorder] AnalyzeVideoSegmentAsync threw: " + ex.Message);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
268
319
|
}
|
|
269
320
|
|
|
270
321
|
/// <summary>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "com.valectric.mooserunner",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.17",
|
|
4
4
|
"displayName": "MooseRunner",
|
|
5
5
|
"description": "MooseRunner boosts PlayMode testing with Hot Reload, MCP for AIs, timescale control, and Task support. It enables rapid iteration, auto test reruns, full documentation and dedicated support.",
|
|
6
6
|
"unity": "6000.2",
|