Assign an owner to each run
Example states: WAITING, RUNNING, FINISHING. Start creates a new runId; finish is accepted only from RUNNING with the same ID. Until cleaning is confirmed, the arena will not return to WAITING.
Create a folder round-demo and a file RoundDemo.java with the code below. The JDK 25 used by Paper 26.3 is suitable for the experiment. There is no game API in the model: this is a transition test, not a ready-made arena.
Run the model and compare the four responses
Execute javac -encoding UTF-8 RoundDemo.java then java RoundDemo; The compiler syntax is in javac documentation 25. Expected responses: true, false, false, true. The code intentionally does not issue rewards.
import java.util.UUID;
public final class RoundDemo {
enum State { WAITING, RUNNING, FINISHING }
private State state = State.WAITING;
private UUID runId;
UUID start() {
if (state != State.WAITING) throw new IllegalStateException("Раунд уже занят");
runId = UUID.randomUUID();
state = State.RUNNING;
return runId;
}
boolean finish(UUID expected) {
if (state != State.RUNNING || !expected.equals(runId)) return false;
state = State.FINISHING;
return true;
}
void cleanup(UUID expected) {
if (state != State.FINISHING || !expected.equals(runId))
throw new IllegalStateException("Не тот этап очистки");
state = State.WAITING;
runId = null;
}
public static void main(String[] args) {
RoundDemo round = new RoundDemo();
UUID first = round.start();
System.out.println("Первый финиш: " + round.finish(first));
System.out.println("Повторный финиш: " + round.finish(first));
round.cleanup(first);
UUID second = round.start();
System.out.println("Старый таймер: " + round.finish(first));
System.out.println("Новый финиш: " + round.finish(second));
round.cleanup(second);
}
}Add scenarios that break the expected sequence
Temporarily call a second start() immediately after the first: IllegalStateException expected. After running the second round, call cleanup(first): the cleanup of someone else's run should be rejected. These experiments test the consequences, not just the presence of the enum.
| Crash | Saved rule |
|---|---|
| Old runId timer | No completion of a new round |
| Two finishes of one runId | The result is accepted once |
| Cleanup did not complete | New start is prohibited |
| Return from background database | Check the status and the same runId |
Link transitions to real confirmations
In Paper, process transitions in the game thread, and return the I/O result as a separate task. For a complex entrance, add PREPARING: inventory saved, arena ready, teleport confirmed. None of these stages should subtly mean RUNNING.
FINISHING closes receiving results; the outcome and intention of the reward are then stored. Cleaning only removes the resources of its runId. Upon restart, the model's memory will disappear, so unfinished operations require a persistent log. Clearing failure means the arena is occupied, not allowing another game to start on top of it.
Failure of the snapshot should terminate the login without clearing the inventory. Save regular stuff before logging in.
Repeated finishing after a restart is checked with a unique key in the database. Save outcome and reward intent.
