-
Bug
-
Resolution: Unresolved
-
None
-
1.20.4
-
None
-
Plausible
-
Save Data
-
Normal
-
Gameplay
In singleplayer (and potentially multiplayer, I haven't tested it there), a simple bug in the code where timer variables aren't saved after being update creates a 1 minute window after a wandering trader spawn attempt in which relogging during this window causes another spawn attempt 1 minute after rejoining, and can then be repeated theoretically hundreds of thousands of times (until integer overflow occurs).
Every minute the game decrements a 20 minute timer by 1 minute, then saves it to the level data. When it see this timer has a value less than or equal to 0 it performs a spawn attempt and resets the data but unsaved to the world. The next time the timer is saved is a minute after the spawn attempt, and so it is possible to then reset the timer back to the previously saved value (of 0) by rejoining the world, and after a minute it will decrement the timer by 1200 ticks, save it, and perform another spawn attempt. Repeating this again you can keep resetting the timer to a non-positive value and continuously force a spawn attempt every minute rather than every 20 minutes as intended.
Here's the code responsible for the bug and some comments for further explanation.
public int tick(ServerLevel serverLevel, boolean bl, boolean bl2) { if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) { return 0; } if (--this.tickDelay > 0) { return 0; } this.tickDelay = 1200; //only happens every minute, which is why there is a minute long window. this.spawnDelay -= 1200; this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); //saves the value before resetting. if (this.spawnDelay > 0) { return 0; } this.spawnDelay = 24000; //resets the value without saving it. if (!serverLevel.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { return 0; } int n = this.spawnChance; this.spawnChance = Mth.clamp(this.spawnChance + 25, 25, 75); this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); if (this.random.nextInt(100) > n) { return 0; } if (this.spawn(serverLevel)) { this.spawnChance = 25; return 1; } return 0; }
I imagine a similar thing can be done on multiplayer by restarting the server, though less efficient.