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

Portal linking radius in Nether reduced from 128 to 16 blocks


    • Icon: Bug Bug
    • Resolution: Works As Intended
    • None
    • 1.16.2 Release Candidate 1, 1.16.2
    • Community Consensus
    • World generation

      The Bug:

      In previous versions of the game, when going through a Nether portal in the Overworld the game would search a 17x17 chunk area, centered on the chunk containing the point with the coordinates of the Overworld portal divided by 8, for an existing portal and pick the closest one or generate a new portal. This behavior has been changed and now the game only searches a 3x3 chunk area. The linking radius is unchanged in the Overworld.


      Code Analysis:

      The main portal-linking logic happens in Teleporter.placeInExistingPortal() (line 29). A check at the start of the function sets the linking distance to 1 chunk if the entity is entering the Nether. Setting radius to 128 and skipping the check fixes the issue, mostly.

      public Optional<TeleportationRepositioner.Result> placeInExistingPortal(BlockPos blockPos, boolean inNether) {
         PointOfInterestManager pointofinterestmanager = this.world.getPointOfInterestManager();
         int radius = inNether ? 16 : 128; //This line causes the bug
         pointofinterestmanager.ensureLoadedAndValid(this.world, blockPos, radius);
         /* The rest of the code searches the area and finds the closest portal */

      The second half of the fix is removing an unnecessary filter from PointOfInterestManager.getInSquare() (line 59). The filter checks that the portal block is within radius blocks of the entity's equivalent position in the new dimension in both the x and z axes. This can preclude parts of chunks from being searched even if the chunk is within the search region, which makes linking inconsistent. Removing the filter, along with the previous change, completely fixes the issue.

      public Stream<PointOfInterest> getInSquare(Predicate<PointOfInterestType> predicate, BlockPos blockPos, int radius, PointOfInterestManager.Status status) {
         int i = Math.floorDiv(radius, 16) + 1;
         return ChunkPos.getAllInBox(new ChunkPos(blockPos), i).flatMap((chunk) -> {
            return this.getInChunk(predicate, chunk, status);
         }).filter((portal) -> { //This filter is unnecessary and causes an edge-case bug
            BlockPos portalPos = portal.getPos();
            return Math.abs(portalPos.getX() - blockPos.getX()) <= radius && Math.abs(portalPos.getZ() - blockPos.getZ()) <= radius;

      I generated this code using the most recent release of MCP Reborn (as of 8-14-2020).

            grum [Mojang] Grum (Erik Broes)
            kittycatkenobi kittycatkenobi
            10 Vote for this issue
            14 Start watching this issue