2021-06-13 22:05:18 +00:00
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/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
2022-06-09 08:51:45 +00:00
index f14d4bfd5ac03eeffefcf98e1077d915fd3fa2cb..d8b34055aff358cb2c236199da1e22d84213ea1e 100644
2021-06-13 22:05:18 +00:00
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
2022-06-08 04:22:42 +00:00
@@ -795,6 +795,7 @@ public abstract class PlayerList {
2021-06-13 22:05:18 +00:00
entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
// CraftBukkit end
+ worldserver1.getChunkSource().addRegionTicket(net.minecraft.server.level.TicketType.POST_TELEPORT, new net.minecraft.world.level.ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
2022-03-01 05:43:03 +00:00
while (avoidSuffocation && !worldserver1.noCollision((Entity) entityplayer1) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) {
2021-06-13 22:05:18 +00:00
entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
2022-06-17 07:00:17 +00:00
index c652aab302357c22a404118cdd113d3162b1a753..ba6ed98fd09632336980270385165112eb21da46 100644
2021-06-13 22:05:18 +00:00
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
2022-06-17 07:00:17 +00:00
@@ -235,6 +235,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource {
2022-06-08 04:22:42 +00:00
public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper
2021-06-13 22:05:18 +00:00
public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
+ public boolean collisionLoadChunks = false; // Paper
private CraftEntity bukkitEntity;
2021-12-13 04:31:32 +00:00
public @org.jetbrains.annotations.Nullable net.minecraft.server.level.ChunkMap.TrackedEntity tracker; // Paper
2021-11-24 18:46:06 +00:00
diff --git a/src/main/java/net/minecraft/world/level/BlockCollisions.java b/src/main/java/net/minecraft/world/level/BlockCollisions.java
2022-06-09 08:51:45 +00:00
index 8390ce194ccc692139c0e870c16a7fb76ac8ba68..95e22c91bc701785f4804e5d4e0a6b420b9830fd 100644
2021-11-24 18:46:06 +00:00
--- a/src/main/java/net/minecraft/world/level/BlockCollisions.java
+++ b/src/main/java/net/minecraft/world/level/BlockCollisions.java
@@ -66,22 +66,41 @@ public class BlockCollisions extends AbstractIterator<VoxelShape> {
protected VoxelShape computeNext() {
2021-06-13 22:05:18 +00:00
while(true) {
if (this.cursor.advance()) {
- int i = this.cursor.nextX();
- int j = this.cursor.nextY();
- int k = this.cursor.nextZ();
2021-11-24 18:46:06 +00:00
+ int i = this.cursor.nextX(); final int x = i; // Paper
+ int j = this.cursor.nextY(); final int y = j; // Paper
+ int k = this.cursor.nextZ(); final int z = k; // Paper
2021-06-13 22:05:18 +00:00
int l = this.cursor.getNextType();
if (l == 3) {
continue;
}
2021-11-24 18:46:06 +00:00
+ // Paper start - ensure we don't load chunks
+ final @Nullable Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null;
+ boolean far = source != null && net.minecraft.server.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14;
+ this.pos.set(x, y, z);
2021-06-13 22:05:18 +00:00
- BlockGetter blockGetter = this.getChunk(i, k);
- if (blockGetter == null) {
2021-07-09 10:16:57 +00:00
+ BlockState blockState;
+ if (this.collisionGetter instanceof net.minecraft.server.level.WorldGenRegion) {
2021-11-24 18:46:06 +00:00
+ BlockGetter blockGetter = this.getChunk(x, z);
+ if (blockGetter == null) {
2021-07-09 10:16:57 +00:00
+ continue;
2021-11-24 18:46:06 +00:00
+ }
+ blockState = blockGetter.getBlockState(this.pos);
+ } else if ((!far && source instanceof net.minecraft.server.level.ServerPlayer) || (source != null && source.collisionLoadChunks)) {
2021-07-09 10:16:57 +00:00
+ blockState = this.collisionGetter.getBlockState(this.pos);
+ } else {
2021-12-05 23:32:02 +00:00
+ blockState = this.collisionGetter.getBlockStateIfLoaded(this.pos);
2021-07-09 10:16:57 +00:00
+ }
2021-06-13 22:05:18 +00:00
+
+ if (blockState == null) {
2022-06-09 08:51:45 +00:00
+ if (!(source instanceof net.minecraft.server.level.ServerPlayer) || source.level.paperConfig().chunks.preventMovingIntoUnloadedChunks) {
2021-11-24 18:46:06 +00:00
+ return Shapes.create(far ? source.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
2021-06-13 22:05:18 +00:00
+ }
2021-11-24 18:46:06 +00:00
+ // Paper end
2021-06-13 22:05:18 +00:00
continue;
}
- this.pos.set(i, j, k);
- BlockState blockState = blockGetter.getBlockState(this.pos);
2021-11-24 18:46:06 +00:00
- if (this.onlySuffocatingBlocks && !blockState.isSuffocating(blockGetter, this.pos) || l == 1 && !blockState.hasLargeCollisionShape() || l == 2 && !blockState.is(Blocks.MOVING_PISTON)) {
+ // Paper - moved up
+ if (/*this.onlySuffocatingBlocks && (!blockState.isSuffocating(blockGetter, this.pos)) ||*/ l == 1 && !blockState.hasLargeCollisionShape() || l == 2 && !blockState.is(Blocks.MOVING_PISTON)) { // Paper - onlySuffocatingBlocks is only true on the client, so we don't care about it here
2021-06-13 22:05:18 +00:00
continue;
}
2021-11-24 18:46:06 +00:00
diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
index 4c373d6c8ddd9f5db88888cd8dbbfc24eb5df793..56d94c94fb0d4dc468bb5d69be655ddd5c6b5360 100644
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
@@ -44,11 +44,13 @@ public interface CollisionGetter extends BlockGetter {
}
default boolean noCollision(@Nullable Entity entity, AABB box) {
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
for(VoxelShape voxelShape : this.getBlockCollisions(entity, box)) {
if (!voxelShape.isEmpty()) {
return false;
}
}
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
if (!this.getEntityCollisions(entity, box).isEmpty()) {
return false;