Завершить контентную архитектуру этапа 4

This commit is contained in:
2026-08-18 22:03:38 +03:00
parent 2ddac2775f
commit 5051f316fe
39 changed files with 1954 additions and 259 deletions
@@ -26,6 +26,7 @@ public final class LevelEightPlaythroughTest {
.recoverAfterClockExpires(driver, 20_000L);
assertTrue("Recovery run " + run + ": " + result.diagnostic(), result.completed());
assertEquals("Recovery must not hide a reset/death shortcut", 0, result.deaths());
assertTrace(result);
}
}
}
@@ -39,6 +40,7 @@ public final class LevelEightPlaythroughTest {
.completeIntendedRoute(driver, 15_000L);
assertTrue("Intended run " + run + ": " + result.diagnostic(), result.completed());
assertEquals("The intended route is deathless", 0, result.deaths());
assertTrace(result);
}
}
}
@@ -51,9 +53,16 @@ public final class LevelEightPlaythroughTest {
assertTrue("Stressed scheduling: " + result.diagnostic(), result.completed());
assertEquals("The stressed intended route is deathless", 0, result.deaths());
assertTrace(result);
}
}
private static void assertTrace(LevelEightScenario.Result result) {
assertTrue(result.traceJson(), result.traceJson().contains("\"traceVersion\":1"));
assertTrue(result.traceJson(), result.traceJson().contains("\"level\":8"));
assertTrue(result.diagnostic(), result.diagnostic().contains("traceId=" + result.traceId()));
}
private static AndroidDriver driver(ActivityScenario<MainActivity> activity) {
return driver(activity, 0L);
}
@@ -11,19 +11,26 @@ final class LevelEightScenario {
private final boolean completed;
private final int deaths;
private final String diagnostic;
private final String traceJson;
private final String traceId;
Result(boolean completed, int deaths, String diagnostic) {
Result(boolean completed, int deaths, String diagnostic, BotCommandTrace trace) {
this.completed = completed;
this.deaths = deaths;
this.diagnostic = diagnostic;
this.traceJson = trace.json();
this.traceId = trace.id();
this.diagnostic = diagnostic + "; traceId=" + traceId;
}
boolean completed() { return completed; }
int deaths() { return deaths; }
String diagnostic() { return diagnostic; }
String traceJson() { return traceJson; }
String traceId() { return traceId; }
}
Result recoverAfterClockExpires(LevelPlaytestBot.Driver driver, long timeoutMillis) {
driver = new BotTraceDriver(driver, "Level 8 recovery route");
driver.startLevel(8);
GameView.AutomationSnapshot snapshot = driver.snapshot();
PlaytestSimulationBudget budget = PlaytestSimulationBudget.start(
@@ -71,6 +78,7 @@ final class LevelEightScenario {
}
Result completeIntendedRoute(LevelPlaytestBot.Driver driver, long timeoutMillis) {
driver = new BotTraceDriver(driver, "Level 8 intended route");
driver.startLevel(8);
GameView.AutomationSnapshot snapshot = driver.snapshot();
PlaytestSimulationBudget budget = PlaytestSimulationBudget.start(
@@ -99,6 +107,7 @@ final class LevelEightScenario {
&& MovingPlatformLaunchPolicy.readyToBoard(current, 1_050f));
if (failed(snapshot, budget, driver)) return snapshot;
traceStep(driver, "Jump onto the moving platform");
driver.setInput(false, true, true);
driver.waitForNextDecision(64L);
driver.setInput(false, true, false);
@@ -112,6 +121,7 @@ final class LevelEightScenario {
current -> MovingPlatformLaunchPolicy.ready(current, LAUNCH_PLATFORM_X));
if (failed(snapshot, budget, driver)) return snapshot;
traceStep(driver, "Jump from the moving platform");
driver.setInput(false, true, true);
driver.waitForNextDecision(64L);
driver.setInput(false, true, false);
@@ -148,6 +158,7 @@ final class LevelEightScenario {
return failure("Reach the open-door jump", snapshot, budget, driver);
}
traceStep(driver, "Final ledge jump");
driver.setInput(false, true, true);
driver.waitForNextDecision(64L);
driver.setInput(false, true, false);
@@ -155,15 +166,17 @@ final class LevelEightScenario {
GameView.AutomationSnapshot::completed);
driver.setInput(false, false, false);
if (!snapshot.completed()) return failure(step, snapshot, budget, driver);
BotCommandTrace trace = finishTrace(driver, "COMPLETED", step, snapshot);
return new Result(true, snapshot.deaths(), step + " completed; "
+ budget.timingState(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
+ "; " + state(snapshot));
+ "; " + state(snapshot), trace);
}
private GameView.AutomationSnapshot positionForFinalJump(
LevelPlaytestBot.Driver driver, PlaytestSimulationBudget budget
) {
lastStep = "Reach the open-door jump";
traceStep(driver, lastStep);
GameView.AutomationSnapshot snapshot = driver.snapshot();
while (!budget.exhausted(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
&& snapshot.playerAlive() && !snapshot.completed() && snapshot.allDoorsOpen()) {
@@ -188,6 +201,7 @@ final class LevelEightScenario {
LevelPlaytestBot.Driver driver, PlaytestSimulationBudget budget, String step,
LevelPlaytestBot.SnapshotCondition completion
) {
traceStep(driver, step);
driver.setInput(false, true, true);
driver.waitForNextDecision(64L);
driver.setInput(false, true, false);
@@ -198,6 +212,7 @@ final class LevelEightScenario {
LevelPlaytestBot.Driver driver, PlaytestSimulationBudget budget
) {
lastStep = "Return beneath the recovery relay";
traceStep(driver, lastStep);
GameView.AutomationSnapshot snapshot = driver.snapshot();
while (!budget.exhausted(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
&& snapshot.playerAlive() && !snapshot.completed()) {
@@ -223,6 +238,7 @@ final class LevelEightScenario {
LevelPlaytestBot.Input input, LevelPlaytestBot.SnapshotCondition completion
) {
lastStep = step;
traceStep(driver, step);
GameView.AutomationSnapshot snapshot = driver.snapshot();
while (!budget.exhausted(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
&& snapshot.playerAlive()
@@ -260,10 +276,24 @@ final class LevelEightScenario {
private Result failure(String step, GameView.AutomationSnapshot snapshot,
PlaytestSimulationBudget budget, LevelPlaytestBot.Driver driver) {
BotCommandTrace trace = finishTrace(driver, "FAILED", step, snapshot);
return new Result(false, snapshot.deaths(), step + " failed; lastStep=" + lastStep
+ "; " + budget.timingState(
snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
+ "; " + state(snapshot));
+ "; " + state(snapshot), trace);
}
private static void traceStep(LevelPlaytestBot.Driver driver, String step) {
if (driver instanceof BotTraceDriver) ((BotTraceDriver) driver).step(step);
}
private static BotCommandTrace finishTrace(LevelPlaytestBot.Driver driver, String outcome,
String step,
GameView.AutomationSnapshot snapshot) {
if (!(driver instanceof BotTraceDriver)) {
throw new IllegalStateException("Level 8 scenario requires its tracing driver");
}
return ((BotTraceDriver) driver).finish(outcome, step, snapshot);
}
private static String state(GameView.AutomationSnapshot snapshot) {