feat(render): implement Campaign AR and terrain fidelity
This commit is contained in:
parent
99cf26e00c
commit
7a5f96ede5
368 changed files with 50611 additions and 950 deletions
|
|
@ -23,6 +23,29 @@ public interface IRetailUiAutomationCheckpoint
|
|||
string? Error { get; }
|
||||
}
|
||||
|
||||
public enum RetailUiAutomationRenderPackState
|
||||
{
|
||||
Retail,
|
||||
CandidatePending,
|
||||
Active,
|
||||
FailedToRetail,
|
||||
}
|
||||
|
||||
public readonly record struct RetailUiAutomationRenderPackStatus(
|
||||
RetailUiAutomationRenderPackState State,
|
||||
string PackId,
|
||||
string PresetId,
|
||||
long ActivationGeneration,
|
||||
string? FailureReason)
|
||||
{
|
||||
public static RetailUiAutomationRenderPackStatus Retail { get; } = new(
|
||||
RetailUiAutomationRenderPackState.Retail,
|
||||
"retail",
|
||||
"off",
|
||||
ActivationGeneration: 0,
|
||||
FailureReason: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Narrow bridge from retained-UI scripts to render/world lifecycle
|
||||
/// diagnostics. Implementations run on the same update/render thread as the
|
||||
|
|
@ -33,6 +56,42 @@ public interface IRetailUiAutomationRuntime
|
|||
bool IsWorldReady { get; }
|
||||
bool IsWorldViewportVisible { get; }
|
||||
int PortalMaterializationCount { get; }
|
||||
int RenderPackPerformanceSampleCount => 0;
|
||||
bool RenderPackFailedToRetail => false;
|
||||
RetailUiAutomationRenderPackStatus RenderPackStatus =>
|
||||
RetailUiAutomationRenderPackStatus.Retail;
|
||||
int FramebufferWidth => 0;
|
||||
int FramebufferHeight => 0;
|
||||
bool TrySelectRenderPack(string presetId, out string error)
|
||||
{
|
||||
error = "render-pack selection automation is unavailable";
|
||||
return false;
|
||||
}
|
||||
bool TryDisableRenderPack(out string error)
|
||||
{
|
||||
error = "render-pack selection automation is unavailable";
|
||||
return false;
|
||||
}
|
||||
bool TryReenableRenderPack(out string error)
|
||||
{
|
||||
error = "render-pack selection automation is unavailable";
|
||||
return false;
|
||||
}
|
||||
bool TryResizeFramebuffer(int width, int height, out string error)
|
||||
{
|
||||
error = "framebuffer resize automation is unavailable";
|
||||
return false;
|
||||
}
|
||||
bool TryResetRenderPackPerformance(out string error)
|
||||
{
|
||||
error = "render-pack performance automation is unavailable";
|
||||
return false;
|
||||
}
|
||||
bool TryRequestClientClose(out string error)
|
||||
{
|
||||
error = "client-close automation is unavailable";
|
||||
return false;
|
||||
}
|
||||
bool TryRequestCheckpoint(
|
||||
string name,
|
||||
out IRetailUiAutomationCheckpoint? checkpoint,
|
||||
|
|
@ -205,7 +264,10 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
|
|||
"command" => DoCommand(command),
|
||||
"input" => DoInput(command),
|
||||
"checkpoint" => DoCheckpoint(command),
|
||||
"renderpack" => DoRenderPack(command),
|
||||
"resize" => DoResize(command),
|
||||
"screenshot" => DoScreenshot(command),
|
||||
"close-client" => DoCloseClient(command),
|
||||
_ => Stop(command, $"unknown command '{p[0]}'"),
|
||||
};
|
||||
}
|
||||
|
|
@ -333,7 +395,7 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
|
|||
private bool DoWait(ScriptCommand command)
|
||||
{
|
||||
var p = command.Parts;
|
||||
if (p.Length < 2) return Stop(command, "usage: wait item|element|ms|world-ready|world-visible|materialized ...");
|
||||
if (p.Length < 2) return Stop(command, "usage: wait item|element|ms|world-ready|world-visible|materialized|render-pack|render-pack-samples|framebuffer ...");
|
||||
|
||||
string target = p[1].ToLowerInvariant();
|
||||
if (target == "item")
|
||||
|
|
@ -376,7 +438,168 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
|
|||
return WaitOrTimeout(command, TimeoutMs(p, 3, 60000), $"portal materialization {occurrence}");
|
||||
}
|
||||
|
||||
return Stop(command, "usage: wait item|element|ms|world-ready|world-visible|materialized ...");
|
||||
if (target == "render-pack-samples")
|
||||
{
|
||||
if (_runtime is null)
|
||||
return Stop(command, "render-pack performance automation is unavailable");
|
||||
if (p.Length < 3
|
||||
|| !TryParseInt(p[2], out int required)
|
||||
|| required <= 0)
|
||||
{
|
||||
return Stop(
|
||||
command,
|
||||
"usage: wait render-pack-samples <count> [timeoutMs]");
|
||||
}
|
||||
if (_runtime.RenderPackPerformanceSampleCount >= required)
|
||||
return true;
|
||||
// An unavailable preset cannot ever fill an enhanced performance
|
||||
// window. Finish this wait immediately so the following screenshot
|
||||
// captures the controller's fully resource-free default fallback;
|
||||
// the harness validates the exact failure class and zero-work
|
||||
// metadata instead of turning every fallback into a five-minute
|
||||
// timeout.
|
||||
if (_runtime.RenderPackFailedToRetail)
|
||||
return true;
|
||||
return WaitOrTimeout(
|
||||
command,
|
||||
TimeoutMs(p, 3, 300000),
|
||||
$"{required} render-pack performance samples");
|
||||
}
|
||||
|
||||
if (target == "render-pack")
|
||||
{
|
||||
if (_runtime is null)
|
||||
return Stop(command, "render-pack selection automation is unavailable");
|
||||
if (p.Length < 3 || !TryNormalizeRenderPackPreset(p[2], out string preset))
|
||||
{
|
||||
return Stop(
|
||||
command,
|
||||
"usage: wait render-pack retail|low|medium|high|auto [timeoutMs]");
|
||||
}
|
||||
|
||||
RetailUiAutomationRenderPackStatus status = _runtime.RenderPackStatus;
|
||||
bool expectRetail = string.Equals(
|
||||
preset,
|
||||
"retail",
|
||||
StringComparison.Ordinal);
|
||||
if (expectRetail
|
||||
&& status.State == RetailUiAutomationRenderPackState.Retail
|
||||
&& string.Equals(status.PackId, "retail", StringComparison.OrdinalIgnoreCase)
|
||||
&& string.Equals(status.PresetId, "off", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!expectRetail
|
||||
&& status.State == RetailUiAutomationRenderPackState.Active
|
||||
&& string.Equals(
|
||||
status.PackId,
|
||||
"acdream.atmospheric",
|
||||
StringComparison.OrdinalIgnoreCase)
|
||||
&& string.Equals(status.PresetId, preset, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (status.State == RetailUiAutomationRenderPackState.FailedToRetail)
|
||||
{
|
||||
return Stop(
|
||||
command,
|
||||
$"render pack '{preset}' failed to retail: "
|
||||
+ (status.FailureReason ?? "no failure reason was published"));
|
||||
}
|
||||
return WaitOrTimeout(
|
||||
command,
|
||||
TimeoutMs(p, 3, 90000),
|
||||
$"render pack '{preset}' activation");
|
||||
}
|
||||
|
||||
if (target == "framebuffer")
|
||||
{
|
||||
if (_runtime is null)
|
||||
return Stop(command, "framebuffer resize automation is unavailable");
|
||||
if (p.Length < 4
|
||||
|| !TryParseInt(p[2], out int width)
|
||||
|| !TryParseInt(p[3], out int height)
|
||||
|| width <= 0
|
||||
|| height <= 0)
|
||||
{
|
||||
return Stop(
|
||||
command,
|
||||
"usage: wait framebuffer <width> <height> [timeoutMs]");
|
||||
}
|
||||
if (_runtime.FramebufferWidth == width
|
||||
&& _runtime.FramebufferHeight == height)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return WaitOrTimeout(
|
||||
command,
|
||||
TimeoutMs(p, 4, 30000),
|
||||
$"framebuffer {width}x{height}");
|
||||
}
|
||||
|
||||
return Stop(command, "usage: wait item|element|ms|world-ready|world-visible|materialized|render-pack|render-pack-samples|framebuffer ...");
|
||||
}
|
||||
|
||||
private bool DoRenderPack(ScriptCommand command)
|
||||
{
|
||||
if (_runtime is null)
|
||||
return Stop(command, "render-pack automation is unavailable");
|
||||
var p = command.Parts;
|
||||
if (p.Length == 2
|
||||
&& string.Equals(p[1], "reset-performance", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _runtime.TryResetRenderPackPerformance(out string error)
|
||||
|| Stop(command, error);
|
||||
}
|
||||
if (p.Length == 3
|
||||
&& string.Equals(p[1], "select", StringComparison.OrdinalIgnoreCase)
|
||||
&& TryNormalizeRenderPackPreset(p[2], out string preset))
|
||||
{
|
||||
return _runtime.TrySelectRenderPack(preset, out string error)
|
||||
|| Stop(command, error);
|
||||
}
|
||||
if (p.Length == 2
|
||||
&& string.Equals(p[1], "disable", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _runtime.TryDisableRenderPack(out string error)
|
||||
|| Stop(command, error);
|
||||
}
|
||||
if (p.Length == 2
|
||||
&& string.Equals(p[1], "reenable", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return _runtime.TryReenableRenderPack(out string error)
|
||||
|| Stop(command, error);
|
||||
}
|
||||
return Stop(
|
||||
command,
|
||||
"usage: renderpack reset-performance | renderpack select retail|low|medium|high|auto | renderpack disable | renderpack reenable");
|
||||
}
|
||||
|
||||
private bool DoResize(ScriptCommand command)
|
||||
{
|
||||
if (_runtime is null)
|
||||
return Stop(command, "framebuffer resize automation is unavailable");
|
||||
var p = command.Parts;
|
||||
if (p.Length != 3
|
||||
|| !TryParseInt(p[1], out int width)
|
||||
|| !TryParseInt(p[2], out int height)
|
||||
|| width <= 0
|
||||
|| height <= 0)
|
||||
{
|
||||
return Stop(command, "usage: resize <width> <height>");
|
||||
}
|
||||
return _runtime.TryResizeFramebuffer(width, height, out string error)
|
||||
|| Stop(command, error);
|
||||
}
|
||||
|
||||
private static bool TryNormalizeRenderPackPreset(
|
||||
string value,
|
||||
out string preset)
|
||||
{
|
||||
preset = value.ToLowerInvariant();
|
||||
if (preset == "off")
|
||||
preset = "retail";
|
||||
return preset is "retail" or "low" or "medium" or "high" or "auto";
|
||||
}
|
||||
|
||||
private bool DoSleep(ScriptCommand command)
|
||||
|
|
@ -540,6 +763,16 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
|
|||
return WaitOrTimeout(command, TimeoutMs(command.Parts, 2, 10000), $"screenshot '{name}'");
|
||||
}
|
||||
|
||||
private bool DoCloseClient(ScriptCommand command)
|
||||
{
|
||||
if (command.Parts.Length != 1)
|
||||
return Stop(command, "usage: close-client");
|
||||
if (_runtime is null)
|
||||
return Stop(command, "client-close automation is unavailable");
|
||||
return _runtime.TryRequestClientClose(out string error)
|
||||
|| Stop(command, error);
|
||||
}
|
||||
|
||||
private bool WaitOrTimeout(ScriptCommand command, int timeoutMs, string label)
|
||||
{
|
||||
if (!HasExceeded(timeoutMs)) return false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue