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

Teleporting big distance freezes the server

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Resolution: Fixed
    • Affects Version/s: Minecraft 18w50a
    • Fix Version/s: Minecraft 19w12a
    • Labels:
      None
    • Confirmation Status:
      Confirmed

      Description

      How to reproduce

      Run:

      /tp 20000000 200 20000000
      

      The cause

      Inside class ServerChunkManager (up) in a method that handles updating itself for player movement, there is piece of code like this (decompiled and remapped code):

      final int minX = Math.min(playerChunkX, lastPlayerChunkX) - this.viewDistance;
      final int minZ = Math.min(playerChunkZ, lastPlayerChunkZ) - this.viewDistance;
      final int maxX = Math.max(playerChunkX, lastPlayerChunkX) + this.viewDistance;
      final int maxZ = Math.max(playerChunkZ, lastPlayerChunkZ) + this.viewDistance;
      for (int x = minX; x <= maxX; ++x) {
          for (int z = minZ; z <= maxZ; ++z) {
              final ChunkPos chunkPos = new ChunkPos(x, z);
              final boolean oldLoaded = !flag1 && getWatchDistance(chunkPos, lastPlayerChunkX, lastPlayerChunkZ) <= this.viewDistance;
              final boolean newLoaded = !flag2 && getWatchDistance(chunkPos, playerChunkX, playerChunkZ) <= this.viewDistance;
              this.chunkLoader.sendChunkDataPacket(playerEntity, chunkPos, new Packet[2], oldLoaded, newLoaded);
          }
      }
      

      This code iterates over ALL chunk coordinates in a box with one end at one end of player view distance before movement, and the other and the opposite end of player view area after movement. This obviously isn't going to work for far teleportation.

      The way it was done in older Minecraft versions looks closer to this:

      // dx and dz is player movement in chunks
      for (int x = newX -viewDistance; x <= newX + viewDistance; ++x) {
          for (int z = newZ - viewDistance; z <= newZ + viewDistance; ++z) {
              //is current position outside of the old render distance square?
              if (!isPointInSquare(oldX, oldZ, x, z, viewDistance)) {
                  // newly loaded chunk
              }
              //if we moved the current point to where it would be previously,
              //would it be outside of current render distance square?
              if (!isPointInSquare(newX, newZ, x-dx, z-dz, viewDistance)) {
                  // unloaded chunk
              }
          }
      }
      

      Which uses just the render distance area to determine which chunks are loaded and which chunks are to be unloaded.

        Attachments

          Activity

            People

            • Assignee:
              searge [Mojang] Searge (Michael Stoyke)
              Reporter:
              Barteks2x Bartosz Skrzypczak
            • Votes:
              3 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                CHK: