// Console commands of the harness itself (DESIGN_UE.md sections 9.1 and 9.2): state dumps, screenshots, // teleport, camera, scenarios, quit. One commands file per system: DescentCommands_.cpp. #include "Debug/DescentCommandUtil.h" #include "Debug/DescentDebugSubsystem.h" #include "Debug/DescentScenario.h" #include "Debug/DescentStateRegistry.h" #include "TheDescent.h" #include "HAL/IConsoleManager.h" namespace { void CmdDumpState(const TArray& Args, UWorld* World) { if (Args.Num() < 1) { Descent::Cmd::Fail(World, TEXT("Descent.DumpState"), TEXT("usage: Descent.DumpState (writes Saved/State/.json)")); return; } FString PathOrError; if (UDescentDebugSubsystem::DumpState(World, Args[0], PathOrError)) { UE_LOG(LogDescent, Display, TEXT("DumpState: wrote %s"), *PathOrError); } else { Descent::Cmd::Fail(World, TEXT("Descent.DumpState"), PathOrError); } } void CmdShot(const TArray& Args, UWorld* World) { UDescentDebugSubsystem* Sub = UDescentDebugSubsystem::Get(World); if (Args.Num() < 1 || !Sub) { Descent::Cmd::Fail(World, TEXT("Descent.Shot"), TEXT("usage: Descent.Shot (writes Saved/Shots/.png and .json; needs a running game)")); return; } Sub->RequestShot(Args[0], [World](const FDescentShotResult& R) { if (R.bOk) { UE_LOG(LogDescent, Display, TEXT("Shot: wrote %s (%dx%d, mean luma %.3f, centre %.3f, p99 %.3f, non-black %.1f%%)"), *R.Path, R.Size.X, R.Size.Y, R.Stats.MeanLuma, R.Stats.CentreLuma, R.Stats.P99Luma, R.Stats.NonBlack * 100.0); } else { Descent::Cmd::Fail(World, TEXT("Descent.Shot"), R.Error); } }); } void CmdShotRegion(const TArray& Args, UWorld* World) { TArray N; if (Args.Num() < 5 || !Descent::Cmd::ParseNumbers(Args, 1, 4, N)) { Descent::Cmd::Fail(World, TEXT("Descent.ShotRegion"), TEXT("usage: Descent.ShotRegion x0 y0 x1 y1 (fractions 0..1 of the frame, origin top left)")); return; } double Mean = 0.0; FString Error; if (UDescentDebugSubsystem::MeasureShotRegion(Args[0], N[0], N[1], N[2], N[3], Mean, Error)) { UE_LOG(LogDescent, Display, TEXT("ShotRegion %s [%.3f %.3f %.3f %.3f]: mean luma %.4f"), *Args[0], N[0], N[1], N[2], N[3], Mean); } else { Descent::Cmd::Fail(World, TEXT("Descent.ShotRegion"), Error); } } void CmdShotRing(const TArray& Args, UWorld* World) { TArray N; if (Args.Num() < 5 || !Descent::Cmd::ParseNumbers(Args, 1, 4, N)) { Descent::Cmd::Fail(World, TEXT("Descent.ShotRing"), TEXT("usage: Descent.ShotRing cx cy r0 r1 (pixels, origin top left)")); return; } double Mean = 0.0; FString Error; if (UDescentDebugSubsystem::MeasureShotRing(Args[0], N[0], N[1], N[2], N[3], Mean, Error)) { UE_LOG(LogDescent, Display, TEXT("ShotRing %s centre (%.0f, %.0f) r %.0f..%.0f: mean luma %.4f"), *Args[0], N[0], N[1], N[2], N[3], Mean); } else { Descent::Cmd::Fail(World, TEXT("Descent.ShotRing"), Error); } } void CmdTeleport(const TArray& Args, UWorld* World) { TArray N; if (!Descent::Cmd::ParseNumbers(Args, 0, 3, N)) { Descent::Cmd::Fail(World, TEXT("Descent.Teleport"), TEXT("usage: Descent.Teleport x y z (metres)")); return; } if (UDescentDebugSubsystem::Teleport(World, FVector(N[0], N[1], N[2]))) { UE_LOG(LogDescent, Display, TEXT("Teleport: moved to %.2f %.2f %.2f m"), N[0], N[1], N[2]); } else { Descent::Cmd::Fail(World, TEXT("Descent.Teleport"), TEXT("no pawn or view target")); } } void CmdCamera(const TArray& Args, UWorld* World) { TArray N; UDescentDebugSubsystem* Sub = UDescentDebugSubsystem::Get(World); if (!Sub || !Descent::Cmd::ParseNumbers(Args, 0, 6, N)) { Descent::Cmd::Fail(World, TEXT("Descent.Camera"), TEXT("usage: Descent.Camera x y z pitch yaw roll [fov] (metres, degrees)")); return; } const float Fov = Args.Num() > 6 && Args[6].IsNumeric() ? FCString::Atof(*Args[6]) : 60.f; if (!Sub->PlaceCamera(FVector(N[0], N[1], N[2]), FRotator(N[3], N[4], N[5]), Fov)) { Descent::Cmd::Fail(World, TEXT("Descent.Camera"), TEXT("no player controller")); } } void CmdScenario(const TArray& Args, UWorld* World) { UDescentDebugSubsystem* Sub = UDescentDebugSubsystem::Get(World); if (Args.Num() < 1 || !Sub) { Descent::Cmd::Fail(World, TEXT("Descent.Scenario"), TEXT("usage: Descent.Scenario (see Descent.ListScenarios)")); return; } Sub->StartScenario(Args[0]); } void CmdListScenarios(const TArray&, UWorld*) { for (const FString& Name : FDescentScenarioRegistry::Get().GetNames()) { const FDescentScenarioRegistry::FEntry* E = FDescentScenarioRegistry::Get().Find(Name); UE_LOG(LogDescent, Display, TEXT("scenario %s - %s"), *Name, E ? *E->Description : TEXT("")); } } void CmdSections(const TArray&, UWorld*) { for (const FName& Name : FDescentStateRegistry::Get().GetSectionNames()) { UE_LOG(LogDescent, Display, TEXT("state section: %s"), *Name.ToString()); } } void CmdQuit(const TArray& Args, UWorld*) { const int32 Code = Args.Num() > 0 ? FCString::Atoi(*Args[0]) : 0; UDescentDebugSubsystem::QuitProcess(Code, TEXT("Descent.Quit")); } FAutoConsoleCommandWithWorldAndArgs GHarnessCmdDumpState( TEXT("Descent.DumpState"), TEXT("Descent.DumpState - write Saved/State/.json"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdDumpState)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdShot( TEXT("Descent.Shot"), TEXT("Descent.Shot - write Saved/Shots/.png (+ .json luminance sidecar) of the current view"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdShot)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdShotRegion( TEXT("Descent.ShotRegion"), TEXT("Descent.ShotRegion x0 y0 x1 y1 - mean luma of a rectangle (fractions) of a shot; appended to its .json"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdShotRegion)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdShotRing( TEXT("Descent.ShotRing"), TEXT("Descent.ShotRing cx cy r0 r1 - mean luma of a ring (pixels) of a shot; appended to its .json"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdShotRing)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdTeleport( TEXT("Descent.Teleport"), TEXT("Descent.Teleport x y z - move the player pawn to x y z metres"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdTeleport)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdCamera( TEXT("Descent.Camera"), TEXT("Descent.Camera x y z pitch yaw roll [fov] - scenario camera, metres and degrees"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdCamera)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdScenario( TEXT("Descent.Scenario"), TEXT("Descent.Scenario - start a registered scenario in the running game"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdScenario)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdListScenarios( TEXT("Descent.ListScenarios"), TEXT("Descent.ListScenarios - list registered scenarios"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdListScenarios)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdSections( TEXT("Descent.Sections"), TEXT("Descent.Sections - list registered state-dump sections"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdSections)); FAutoConsoleCommandWithWorldAndArgs GHarnessCmdQuit( TEXT("Descent.Quit"), TEXT("Descent.Quit [exitcode] - end the process (ignored inside the editor: Esc stops Play)"), FConsoleCommandWithWorldAndArgsDelegate::CreateStatic(&CmdQuit)); }