WHAT YOU WILL MAKE
24 rules inspection and game acceptance records
Debugging is based on evidence. Read your own location in the stack and repeat three Bugs for extra-score scores, late endings and double counting; verify rules and connections with 24 pure Java checks and 10 game scenes, respectively. Continue with Lesson 38 OreRush Project. The test uses Java21; the in-game check continues to use ordinary Paper1.21.11. Faulty clips should only be placed on the practice copy and do not overwrite the working version.
Before you start: Continue with the Ore Dash in Lesson 38
01 / 12
Before starting: first recognize the running position
The first 30 lessons lay the foundation for ordinary Java programs. At this stage, the code is connected to the Paper server: the Minecraft client is responsible for entering the world, the server loads the plug-in, and the events and commands hand over player actions to your methods.
This book uses JDK 21 and Paper 1.21.11, and the client version is also consistent. The latest version on the download page may have changed, select it by version number. This book uses normal plugin.yml and the Bukkit API; no claims are made to support Folia at this stage.
The short examples in the picture frame are partial fragments. Read the location description of this section first, and do not save each as a plug-in. The file name will be clearly given for the complete file; when the same file is divided into multiple segments, they will be connected by number, and the package name, import and outer class will only appear once.
- Prediction: Write success conditions and expected messages first.
- Run: After successful construction, install and restart on the dedicated local test server.
- Verification: Ordinary players, management identities and consoles take corresponding paths respectively.
02 / 12
The red stack is a positioning map
The server throws out a long list of red letters, and Fang guesses from the bottom. The detective handed over a magnifying glass: first identify the type and cause of the anomaly, then find the first location of your project, and follow the call path to avoid getting lost in the log.
Debug first reproduce, then narrow down the conditions, and finally fix one point and retest. There are two levels of testing: pure Java checking rules, and real server checking whether events, commands and scheduling are connected correctly. Compilation approval cannot replace in-game acceptance.
- Exception typeExplain what type of failure
- Own source filesFind the first location in the project
- Reproduction stepsThe same input can be retested
The teaching instruction stack is not the actual measurement log. See the description in this section for the location.
java.lang.NullPointerException: ...
at de.teacherma.orerush.OreRushPlugin.onCommand(OreRushPlugin.java:58)
at org.bukkit.command.PluginCommand.execute(PluginCommand.java:...)Write a fault record · See the description in this section for the location
Steps: Enter/orerush score
Expected: Not registered yet
Actual: Red letter abnormality
Environment: Java21 Paper1.21.11 Plug-in version and complete exception are attached separately03 / 12
If the player cannot be found, stop first.
Querying online players may result in null, and offline does not mean "finding an invisible Player". Check results immediately before reading names or sending messages. Not all nulls should be forced to the default object, sometimes it is more appropriate to explicitly tell the operator to fail.
- Query objectOnline search may be null
- Check failedDescription offline and stop
- Success objectMethod is called later
The security fragment that can be added to the management command · See the description in this section for the location
Player target = getServer().getPlayerExact(name);
if (target == null) {
sender.sendMessage("Player is not online, please check name");
return true;
}
target.sendMessage("The teacher invites you to take the test");Keep the exception instead of pretending to be successful · See the description in this section for the location
catch (IOException ex) {
getLogger().log(Level.WARNING, "Read failed", ex);
}04 / 12
Boundary Repair 1: Bonus points after the end
The bad version only checks whether the player has signed up. When the list is still there after the game, if you continue to mine, your points will increase. Add "in game" to the condition of the extra point method, and even if the caller forgets to check, the core rules can still block extra points outside the game.
Stop and think about it: If the repeated start test of the rule class passes, can it prove that the server only creates one scheduled task? What else to observe?
- WAITINGNo points will be added even if you have registered
- RUNNINGWrite only after you have registered and scored correctly
- ENDINGEntrance is closed
Bad version, forgotten status · Intentional error, predict first and then repair
if (scores.containsKey(id)) scores.merge(id, points, Integer::sum);The location of the restored entrance is shown in this section.
if (state == State.RUNNING && scores.containsKey(id) && points > 0)
scores.computeIfPresent(id, (key, old) -> old + points);Inspections that can reveal problems·The location is explained in this section
r.add(alex, 10); // In WAITING Status
check(r.snapshot().get(alex) == 0, "waiting cannot score");05 / 12
Boundary Repair 2 The game of surviving for one more second
If it is judged that remaining is equal to 0 first and then subtracted, the 2-second game will not end until the third callback. Let's use an example that's short enough to count: start with 2, change to 1 for the first time, change to 0 for the second time and settle. Don't really have to wait a minute.
- Initial 2No callback, still competing
- 1st tick1 left, not over
- The 2nd tickReturn to zero and end once
Bad version: judge first and then subtract · Intentional error, predict first and then fix
if (remaining == 0) return true;
remaining--;
return false;It ends when it returns to zero. See the description in this section for the position.
if (--remaining > 0) return false;
state = State.ENDING;
return true;| Number of callbacks | Remaining after repair | Whether to end |
|---|---|---|
| 0 | 2 | No |
| 1 | 1 | No |
| 2 | 0 | Yes |
| 3 | 0 | No, end without repeating |
06 / 12
Boundary Repair Three Two referees count seconds at the same time
The bad version creates a task every time it receives a start. Press it twice and the seconds will drop as if you have taken a potion of urgency. First let GameRound.start verify the status, and only enter the scheduler if successful; when stopping, both cancel and clear the task field.
- Check status firstRepeat start rejected
- Re-create tasksOnly successful paths are arranged
- End cleanupcancel and task is set to null
Before entering the next step along the arrow, the conditions of the previous step must be met; the rejected branch returns early.
Do not place the creation task before checking · See the description in this section for the location
if (!round.start(duration)) {
sender.sendMessage("Unable to start");
return true;
}
// Create the task belowCleaning should be complete·Complete files
if (task != null) task.cancel();
task = null;
round.reset();
names.clear();07 / 12
The first half of the automatic inspection program
Create new checks/RoundChecks.java in the OreRush project. This page continues from the next page which is a complete file and does not include the plug-in JAR. When the check fails, an AssertionError is thrown and the operation fails immediately; it will not be skipped silently like Java assert, which is turned off by default.
- Air bureau and registrationRefuse no one to start and repeat registration
- Start boundaryBoth duration and status are verified
- Scoring BoundaryOut-of-match, outsider and negative score rejection
RoundChecks Part 1 · Sequentially connected to the same source file
import de.teacherma.orerush.GameRound;
import java.util.UUID;
public class RoundChecks {
private static int checks;
private static void check(boolean condition, String name) {
checks++;
if (!condition) throw new AssertionError(name);
}
public static void main(String[] args) {
UUID alex = new UUID(0, 1), steve = new UUID(0, 2);
GameRound r = new GameRound();
check(!r.start(60), "empty cannot start");
check(r.join(alex), "first join");
check(!r.join(alex), "duplicate join");
r.add(alex, 10);
check(r.snapshot().get(alex) == 0, "waiting cannot score");
check(!r.start(0), "zero duration rejected");
check(!r.start(3601), "too long rejected");
check(r.start(2), "start two seconds");
check(!r.start(2), "duplicate start rejected");
check(!r.join(steve), "late join rejected");
r.add(alex, 10); r.add(steve, 10); r.add(alex, -5);
check(r.snapshot().get(alex) == 10, "valid points only");
check(!r.snapshot().containsKey(steve), "outsider cannot score");08 / 12
The lower part of the automatic inspection program
Continue to the previous page. After returning to zero, try adding points again, reset again, and check whether the old score snapshot still exists. Finally overrides deep slate ore, normal stone and null input. Outputs PASS 24 checks on success.
- Time and endThe second tick returns to zero
- Reset and SnapshotOld snapshots still retain results
- Material rulesDeep slate, ordinary stone and null
RoundChecks Part 2 · Sequentially connected to the same source file
check(!r.tick() && r.remaining() == 1, "first tick");
check(r.tick(), "second tick ends");
check(r.state() == GameRound.State.ENDING, "closed before result");
r.add(alex, 10);
check(r.snapshot().get(alex) == 10, "ending cannot score");
check(!r.tick(), "cannot end twice");
var result = r.snapshot();
r.reset();
check(r.state() == GameRound.State.WAITING, "reset state");
check(r.snapshot().isEmpty(), "reset enrollment");
check(result.get(alex) == 10, "snapshot survives reset");
check(GameRound.points("DEEPSLATE_DIAMOND_ORE") == 10, "deep diamond");
check(GameRound.points("GOLD_ORE") == 5, "gold");
check(GameRound.points("DEEPSLATE_IRON_ORE") == 3, "deep iron");
check(GameRound.points("STONE") == 0, "ordinary block");
check(GameRound.points(null) == 0, "missing material");
System.out.println("PASS " + checks + " checks");
}
}First create a new checks/sources.txt, and write the following two source file paths relative to the project root directory, one per line. Then run the short command from the project root directory; you can also run RoundChecks.main directly from the IDE.
checks/sources.txt · Full content
src/main/java/de/teacherma/orerush/GameRound.java
checks/RoundChecks.javaRun Windows project root directory · See the instructions in this section for the location
javac -encoding UTF-8 -d checks/out @checks/sources.txt
java -cp checks/out RoundChecksOutput
PASS 24 checks09 / 12
Test the game in ten scenarios
What is automatically checked is digital rules, and there are more command permissions, modes, worlds and other plug-ins in the game. Operate according to the table and record the "actual results" and log location; when you find a problem, only change one condition and try again, so that the evidence will not teleport like the Ender Man.
- Rule CheckNumbers and status can be independently verified
- Game acceptancePermission event scheduling needs to be aligned
- Two pieces of evidenceCannot replace each other
| Number and action | Expected |
|---|---|
| 1 No one signed up to start | Reject |
| 2 Repeat join with the same person | Second rejection |
| 3 Two people sign up to start | Only start one round |
| 4 Start again immediately | Rejected, no second task |
| 5 Mining by those who have not signed up | No scoring |
| 6 Creative mode or different world mining | No scoring |
| 7 Protection to cancel mining | No scoring |
| 8 dig again after natural end | No scoring |
| 9 stop during timing | No subsequent countdown broadcast |
| 10 Stop the service and restart after registration starts again | Old tasks and local data are not restored |
10 / 12
Find the real time-consuming before optimizing
When players say "stuck", it may be caused by network, world generation, or plug-ins. Record the time, number of people, operations and reproduction steps first, and then measure. Don't declare a for loop guilty just when you see it: looping ten points is not the same thing as writing a file for every piece of ore.
- Reproduce firstRecord operations, number of people and time
- Measure againIdentify the real time-consuming path
- Post-improvementRetest the same scenario
Only a section of pure calculation is measured. See the description in this section for the position.
long started = System.nanoTime();
var result = round.snapshot();
long elapsedNs = System.nanoTime() - started;
// Single result is subject to JVM Influences such as preheating are not formal performance conclusions..Useful but not excessive logs · See the description in this section for the location
getLogger().info("OreRush started, players=" + round.snapshot().size());- Do not download web pages, traverse all blocks, or save entire files every time you mine.
- In the test server, you can use the performance analyzer according to Paper's official Profiling guide, first check the time-consuming calls and then optimize.
- Check the player name, address and path before sharing logs or analysis reports; underage students should not upload complete server information by themselves.
11 / 12
Expansion challenges and own acceptance records
Leave the source code, actual running results and a problem record. Explain it in your own words first, and then run the verification; where the results are different from the predictions, they are often the most worthy of discussion.
- Wooden PickaxeExplain your own stack
- Iron PickaxeRepair three boundary bugs
- Diamond PickaxeMake a read-only self-test command
- Wooden Pickaxe: Explain a stack of one's own project, pointing out exceptions, methods and source file locations.
- Iron Pickaxe: Reproduce and fix three bugs in this lesson in the practice copy, and submit the test results before and after the repairs.
- Diamond Pickaxe: Make a read-only self-test command to display the version, current status and number of applicants; do not output private information.
- Acceptance requirements: Keep the pre-repair recurrence steps, positioning basis and post-repair results; switch to a deskmate and record the operation, and you should still get a consistent conclusion.
| I can complete it independently | Mastered | Practice again |
|---|---|---|
| Errors can be reproduced with evidence | □ | □ |
| Will run 24 rule checks | □ | □ |
| Able to distinguish unit rules from game acceptance | □ | □ |
12 / 12
Leave the evidence for the next adventure
Divide "can compile", "number rules pass" and "actual performance of the game is correct" into three columns. Scenarios that are not running are written to be tested; when bugs are discovered, trigger conditions, expected, actual, minimum repairs, and retest results are recorded.
| Category | The operation you selected | Evidence left behind |
|---|---|---|
| Normal | A successful path for this lesson | Version and actual output |
| Border | The moment before the end, the maximum value or the full backpack | Compare item by item with contract |
| Reject | Wrong parameters, no permissions or irrelevant events | The feedback is clear and the status has not been changed by mistake. |
- Explain why each arrow in this lesson points from here to there; the parallel cards have no sequential meaning.
- First change a rule, then modify the description and expectations at the same time, and retest with the same input.
TAKE IT WITH YOU
Take the lesson offline
The complete lesson, code, diagrams and exercises, in your preferred language.
