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

Teleporting big distance freezes the server

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Minecraft 19w12a
    • Minecraft 18w50a
    • None
    • Confirmed

      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.

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

              Created:
              Updated:
              Resolved:
              CHK: