Завершить контентную архитектуру этапа 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
@@ -127,14 +127,18 @@ public final class LevelPlaytestBot {
private final int corpseCount;
private final String diagnostic;
private final String lastStep;
private final String traceJson;
private final String traceId;
Result(boolean completed, boolean doorOpened, int deaths, int corpseCount,
String diagnostic, String lastStep) {
String diagnostic, String lastStep, BotCommandTrace trace) {
this.completed = completed;
this.doorOpened = doorOpened;
this.deaths = deaths;
this.corpseCount = corpseCount;
this.diagnostic = diagnostic;
this.traceJson = trace.json();
this.traceId = trace.id();
this.diagnostic = diagnostic + "; traceId=" + traceId;
this.lastStep = lastStep;
}
@@ -144,6 +148,8 @@ public final class LevelPlaytestBot {
public int corpseCount() { return corpseCount; }
public String diagnostic() { return diagnostic; }
public String lastStep() { return lastStep; }
public String traceJson() { return traceJson; }
public String traceId() { return traceId; }
}
public Result run(Driver driver, Scenario scenario, long timeoutMillis) {
@@ -154,6 +160,8 @@ public final class LevelPlaytestBot {
String lastStep = scenario.steps.isEmpty() ? null : scenario.steps.get(0).name;
boolean doorOpened = false;
GameView.AutomationSnapshot last = driver.snapshot();
BotCommandTrace.Builder trace = BotCommandTrace.builder(
scenario.levelNumber, scenario.name, last);
long scenarioStartedAtSimulation = last.elapsedMilliseconds();
long stepStartedAtSimulation = scenarioStartedAtSimulation;
@@ -164,20 +172,22 @@ public final class LevelPlaytestBot {
last.elapsedMilliseconds(), scenarioStartedAtSimulation);
doorOpened |= last.allDoorsOpen();
if (last.completed()) {
driver.setInput(false, false, false);
applyInput(driver, trace, Input.none(), lastStep, last);
BotCommandTrace finishedTrace = trace.finish("COMPLETED", lastStep, last);
return new Result(true, doorOpened, last.deaths(), last.corpseCount(),
scenario.name + " completed; step=" + lastStep + "; "
+ timingState(simulationElapsed, wallElapsed) + "; "
+ snapshotState(last),
lastStep);
lastStep, finishedTrace);
}
if (wallElapsed >= wallWatchdogMillis) {
driver.setInput(false, false, false);
applyInput(driver, trace, Input.none(), lastStep, last);
BotCommandTrace finishedTrace = trace.finish("WALL_WATCHDOG", lastStep, last);
return new Result(false, doorOpened, last.deaths(), last.corpseCount(),
scenario.name + " stopped by wall-clock watchdog; step=" + lastStep
+ "; " + timingState(simulationElapsed, wallElapsed) + "; "
+ snapshotState(last),
lastStep);
lastStep, finishedTrace);
}
if (simulationElapsed >= timeoutMillis) break;
if (stepIndex >= scenario.steps.size()) break;
@@ -185,34 +195,43 @@ public final class LevelPlaytestBot {
Step step = scenario.steps.get(stepIndex);
lastStep = step.name;
if (step.completion.reached(last)) {
driver.setInput(false, false, false);
trace.checkpoint(step.name, last);
applyInput(driver, trace, Input.none(), step.name, last);
stepIndex++;
stepStartedAtSimulation = last.elapsedMilliseconds();
continue;
}
if (elapsed(last.elapsedMilliseconds(), stepStartedAtSimulation)
>= step.timeoutMillis) {
driver.setInput(false, false, false);
applyInput(driver, trace, Input.none(), step.name, last);
BotCommandTrace finishedTrace = trace.finish("STEP_TIMEOUT", step.name, last);
return new Result(false, doorOpened, last.deaths(), last.corpseCount(),
scenario.name + " timed out in simulation; step=" + step.name
+ "; " + timingState(simulationElapsed, wallElapsed) + "; "
+ snapshotState(last),
step.name);
step.name, finishedTrace);
}
driver.setInput(step.input.moveLeft, step.input.moveRight, step.input.jump);
applyInput(driver, trace, step.input, step.name, last);
driver.waitForNextDecision(DECISION_MILLIS);
}
driver.setInput(false, false, false);
applyInput(driver, trace, Input.none(), lastStep, last);
long wallElapsed = elapsed(driver.currentTimeMillis(), scenarioStartedAtWall);
long simulationElapsed = elapsed(
last.elapsedMilliseconds(), scenarioStartedAtSimulation);
BotCommandTrace finishedTrace = trace.finish("SIMULATION_BUDGET", lastStep, last);
return new Result(false, doorOpened, last.deaths(), last.corpseCount(),
scenario.name + " exhausted its simulation budget; step=" + lastStep
+ "; " + timingState(simulationElapsed, wallElapsed) + "; "
+ snapshotState(last),
lastStep);
lastStep, finishedTrace);
}
private static void applyInput(Driver driver, BotCommandTrace.Builder trace, Input input,
String step, GameView.AutomationSnapshot snapshot) {
driver.setInput(input.moveLeft, input.moveRight, input.jump);
trace.input(step, input.moveLeft, input.moveRight, input.jump, snapshot);
}
private static long wallWatchdogMillis(long simulationBudgetMillis) {