Editor utility that runs automated test scenarios in play mode. It parses a JSON array of steps and executes UI clicks, simulated player input, and waits; it can record video via VideoRecordingDriver and returns a ToolOutcome with results.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Sandbox;
namespace Editor.Mcp
{
internal static class ScenarioRunner
{
public static async Task<ToolOutcome<object>> ExecuteScenarioAsync( string scenarioName, string stepsJson, bool recordVideo = false )
{
if ( !Game.IsPlaying )
{
return ToolOutcome<object>.Failure( null, ToolStatus.Unavailable, "scenario.playmode_inactive", "Play mode must be active to run test scenarios." );
}
if ( recordVideo )
{
VideoRecordingDriver.Control( "start", $"{scenarioName}.mp4" );
}
var failures = new List<object>();
int executed = 0;
try
{
using var doc = JsonDocument.Parse( stepsJson );
foreach ( var element in doc.RootElement.EnumerateArray() )
{
var type = element.GetProperty( "type" ).GetString() ?? "";
executed++;
switch ( type.ToLowerInvariant() )
{
case "ui_click":
var selector = element.GetProperty( "selector" ).GetString() ?? "";
var uiRes = await SyntheticUiDriver.InteractAsync( selector, "click" );
if ( uiRes.Status != ToolStatus.Ready )
{
var errMsg = uiRes.Diagnostics.FirstOrDefault()?.Message ?? "UI interaction failed";
failures.Add( new { Step = executed, Type = type, Error = errMsg } );
}
break;
case "player_input":
var action = element.GetProperty( "action" ).GetString() ?? "forward";
var duration = element.TryGetProperty( "durationMs", out var d ) ? d.GetInt32() : 100;
await SyntheticInputDriver.SimulateInputAsync( action, "pulse", duration );
break;
case "wait":
var waitMs = element.TryGetProperty( "durationMs", out var w ) ? w.GetInt32() : 100;
await Task.Delay( waitMs );
break;
}
}
}
catch ( Exception ex )
{
failures.Add( new { Step = executed, Error = ex.Message } );
}
finally
{
if ( recordVideo )
{
VideoRecordingDriver.Control( "stop" );
}
}
return ToolOutcome<object>.Ready( new
{
Scenario = scenarioName,
Passed = failures.Count == 0,
StepsExecuted = executed,
Failures = failures
} );
}
}
}