PaperMC/Spigot-Server-Patches/0425-Optimize-Collision-to-not-load-chunks.patch
Josh Roy b31089a929
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#5325)
Upstream has released updates that appear to apply and compile correctly.
This update has not been tested by PaperMC and as with ANY update, please do your own testing

Bukkit Changes:
d264e972 #591: Add option for a consumer before spawning an item
1c537fce #590: Add spawn and transform reasons for piglin zombification.

CraftBukkit Changes:
ee5006d1 #810: Add option for a consumer before spawning an item
f6a39d3c #809: Add spawn and transform reasons for piglin zombification.
0c24068a Organise imports

Spigot Changes:
bff52619 Organise imports
2021-03-08 15:12:31 -08:00

135 lines
8.1 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 2 Apr 2020 02:37:57 -0400
Subject: [PATCH] Optimize Collision to not load chunks
The collision code takes an AABB and generates a cuboid of checks rather
than a cylinder, so at high velocity this can generate a lot of chunk checks.
Treat an unloaded chunk as a collision for entities, and also for players if
the "prevent moving into unloaded chunks" setting is enabled.
If that serting is not enabled, collisions will be ignored for players, since
movement will load only the chunk the player enters anyways and avoids loading
massive amounts of surrounding chunks due to large AABB lookups.
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 874dddc5d70dc149c272855a98ed858867dd2bb6..7da08dd7c2396ae1048d857bfae4fee2a9f3b4d9 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -80,6 +80,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
private CraftEntity bukkitEntity;
PlayerChunkMap.EntityTracker tracker; // Paper
+ boolean collisionLoadChunks = false; // Paper
Throwable addedToWorldStack; // Paper - entity debug
public CraftEntity getBukkitEntity() {
if (bukkitEntity == null) {
diff --git a/src/main/java/net/minecraft/server/ICollisionAccess.java b/src/main/java/net/minecraft/server/ICollisionAccess.java
index 7bb0843d76864fc10575532745eb63f9ca478354..25e54a1fadc5d31fb250a3f47524b4f345fc8cc6 100644
--- a/src/main/java/net/minecraft/server/ICollisionAccess.java
+++ b/src/main/java/net/minecraft/server/ICollisionAccess.java
@@ -46,7 +46,9 @@ public interface ICollisionAccess extends IBlockAccess {
}
default boolean b(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Predicate<Entity> predicate) {
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
return this.d(entity, axisalignedbb, predicate).allMatch(VoxelShape::isEmpty);
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
}
Stream<VoxelShape> c(@Nullable Entity entity, AxisAlignedBB axisalignedbb, Predicate<Entity> predicate);
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index bd8d2e60a1d0609d03978328b44516a18a0d2553..73a29023767e6452cd263564c9bce3fb52e93312 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -732,6 +732,7 @@ public abstract class PlayerList {
entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
// CraftBukkit end
+ worldserver1.getChunkProvider().addTicket(TicketType.POST_TELEPORT, new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
while (avoidSuffocation && !worldserver1.getCubes(entityplayer1) && entityplayer1.locY() < 256.0D) {
entityplayer1.setPosition(entityplayer1.locX(), entityplayer1.locY() + 1.0D, entityplayer1.locZ());
}
diff --git a/src/main/java/net/minecraft/server/VoxelShapeSpliterator.java b/src/main/java/net/minecraft/server/VoxelShapeSpliterator.java
index 4967d1ebd109c462a322e4829d01ff519d1b5366..ed0f3ddbcb7d6ce8a59ae3829f4cb11ae75046cb 100644
--- a/src/main/java/net/minecraft/server/VoxelShapeSpliterator.java
+++ b/src/main/java/net/minecraft/server/VoxelShapeSpliterator.java
@@ -9,13 +9,13 @@ import javax.annotation.Nullable;
public class VoxelShapeSpliterator extends AbstractSpliterator<VoxelShape> {
@Nullable
- private final Entity a;
+ private final Entity a; final Entity getEntity() { return this.a; } // Paper - OBFHELPER
private final AxisAlignedBB b;
private final VoxelShapeCollision c;
private final CursorPosition d;
- private final BlockPosition.MutableBlockPosition e;
+ private final BlockPosition.MutableBlockPosition e; final BlockPosition.MutableBlockPosition getMutablePos() { return this.e; } // Paper - OBFHELPER
private final VoxelShape f;
- private final ICollisionAccess g;
+ private final ICollisionAccess g; final ICollisionAccess getCollisionAccess() { return this.g; } // Paper - OBFHELPER
private boolean h;
private final BiPredicate<IBlockData, BlockPosition> i;
@@ -52,23 +52,37 @@ public class VoxelShapeSpliterator extends AbstractSpliterator<VoxelShape> {
boolean a(Consumer<? super VoxelShape> consumer) {
while (true) {
if (this.d.a()) {
- int i = this.d.b();
- int j = this.d.c();
- int k = this.d.d();
+ int i = this.d.b(); final int x = i;
+ int j = this.d.c(); final int y = j;
+ int k = this.d.d(); final int z = k;
int l = this.d.e();
if (l == 3) {
continue;
}
- IBlockAccess iblockaccess = this.a(i, k);
-
- if (iblockaccess == null) {
+ // Paper start - ensure we don't load chunks
+ Entity entity = this.getEntity();
+ BlockPosition.MutableBlockPosition blockposition_mutableblockposition = this.getMutablePos();
+ boolean far = entity != null && MCUtil.distanceSq(entity.locX(), y, entity.locZ(), x, y, z) > 14;
+ blockposition_mutableblockposition.setValues(x, y, z);
+
+ boolean isRegionLimited = this.getCollisionAccess() instanceof RegionLimitedWorldAccess;
+ IBlockData iblockdata = isRegionLimited ? Blocks.VOID_AIR.getBlockData() : ((!far && entity instanceof EntityPlayer) || (entity != null && entity.collisionLoadChunks)
+ ? this.getCollisionAccess().getType(blockposition_mutableblockposition)
+ : this.getCollisionAccess().getTypeIfLoaded(blockposition_mutableblockposition)
+ );
+
+ if (iblockdata == null) {
+ if (!(entity instanceof EntityPlayer) || entity.world.paperConfig.preventMovingIntoUnloadedChunks) {
+ VoxelShape voxelshape3 = VoxelShapes.of(far ? entity.getBoundingBox() : new AxisAlignedBB(new BlockPosition(x, y, z)));
+ consumer.accept(voxelshape3);
+ return true;
+ }
continue;
}
-
- this.e.d(i, j, k);
- IBlockData iblockdata = iblockaccess.getType(this.e);
+ // Paper - moved up
+ // Paper end
if (!this.i.test(iblockdata, this.e) || l == 1 && !iblockdata.d() || l == 2 && !iblockdata.a(Blocks.MOVING_PISTON)) {
continue;
diff --git a/src/main/java/net/minecraft/server/VoxelShapes.java b/src/main/java/net/minecraft/server/VoxelShapes.java
index 881cea7c466f29ff4a89db28d104e8500a548b1f..dd91a57f994f1c23464f5e33ca332529d7d9ea19 100644
--- a/src/main/java/net/minecraft/server/VoxelShapes.java
+++ b/src/main/java/net/minecraft/server/VoxelShapes.java
@@ -239,7 +239,8 @@ public final class VoxelShapes {
if (k2 < 3) {
blockposition_mutableblockposition.a(enumaxiscycle1, i2, j2, l1);
- IBlockData iblockdata = iworldreader.getType(blockposition_mutableblockposition);
+ IBlockData iblockdata = iworldreader.getTypeIfLoaded(blockposition_mutableblockposition); // Paper
+ if (iblockdata == null) return 0.0D; // Paper
if ((k2 != 1 || iblockdata.d()) && (k2 != 2 || iblockdata.a(Blocks.MOVING_PISTON))) {
d0 = iblockdata.b((IBlockAccess) iworldreader, blockposition_mutableblockposition, voxelshapecollision).a(enumdirection_enumaxis2, axisalignedbb.d((double) (-blockposition_mutableblockposition.getX()), (double) (-blockposition_mutableblockposition.getY()), (double) (-blockposition_mutableblockposition.getZ())), d0);