Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-268140

Save bug allows for a wandering trader spawn attempt to occur every minute.

XMLWordPrintable

    • Icon: Bug 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.

            Unassigned Unassigned
            __toad_ Toadytop
            Votes:
            3 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              CHK: