186 lines
11 KiB
Diff
186 lines
11 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/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
index dfdde9722bc0d83916779014b7718eef2c01b3db..86c5549196a4e9011c5240e7918b466c299be4a3 100644
|
|
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
|
@@ -59,12 +59,23 @@ import net.minecraft.server.MCUtil;
|
|
import net.minecraft.server.MinecraftServer;
|
|
import net.minecraft.server.PlayerAdvancements;
|
|
import net.minecraft.server.ServerScoreboard;
|
|
+import net.minecraft.server.level.ServerLevel;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.server.level.ServerPlayerGameMode;
|
|
+import net.minecraft.server.level.TicketType;
|
|
+import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
|
+import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
|
+import net.minecraft.sounds.SoundEvents;
|
|
+import net.minecraft.sounds.SoundSource;
|
|
+import net.minecraft.stats.ServerStatsCounter;
|
|
+import net.minecraft.stats.Stats;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.tags.Tag;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.effect.MobEffectInstance;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityType;
|
|
+import net.minecraft.world.level.ChunkPos;
|
|
import net.minecraft.world.level.GameRules;
|
|
import net.minecraft.world.level.GameType;
|
|
import net.minecraft.world.level.Level;
|
|
@@ -90,15 +101,6 @@ import io.papermc.paper.adventure.PaperAdventure; // Paper
|
|
import com.google.common.base.Predicate;
|
|
import com.google.common.collect.Iterables;
|
|
import net.minecraft.server.dedicated.DedicatedServer;
|
|
-import net.minecraft.server.level.ServerLevel;
|
|
-import net.minecraft.server.level.ServerPlayer;
|
|
-import net.minecraft.server.level.ServerPlayerGameMode;
|
|
-import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
|
-import net.minecraft.server.network.ServerLoginPacketListenerImpl;
|
|
-import net.minecraft.sounds.SoundEvents;
|
|
-import net.minecraft.sounds.SoundSource;
|
|
-import net.minecraft.stats.ServerStatsCounter;
|
|
-import net.minecraft.stats.Stats;
|
|
import org.bukkit.craftbukkit.CraftServer;
|
|
import org.bukkit.craftbukkit.CraftWorld;
|
|
|
|
@@ -805,6 +807,7 @@ public abstract class PlayerList {
|
|
entityplayer1.forceSetPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
|
// CraftBukkit end
|
|
|
|
+ worldserver1.getChunkSource().addRegionTicket(TicketType.POST_TELEPORT, new ChunkPos(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper
|
|
while (avoidSuffocation && !worldserver1.noCollision(entityplayer1) && entityplayer1.getY() < 256.0D) {
|
|
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
|
|
index 7e198b94f349d4c4d61502f5ad8c60686800d88f..b8dcc91a191f25ca578e0858abf6c1b874fee15d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
@@ -168,6 +168,7 @@ public abstract class Entity implements Nameable, CommandSource, net.minecraft.s
|
|
private CraftEntity bukkitEntity;
|
|
|
|
ChunkMap.TrackedEntity tracker; // Paper
|
|
+ public boolean collisionLoadChunks = false; // Paper
|
|
public Throwable addedToWorldStack; // Paper - entity debug
|
|
public CraftEntity getBukkitEntity() {
|
|
if (bukkitEntity == null) {
|
|
diff --git a/src/main/java/net/minecraft/world/level/CollisionGetter.java b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
|
index d9e69195ee0af4dfb90bf0e8f4cc65e63f7ecf5b..1b52f2a0ce9cb847d7d57b38f4b8b6bed8de2cd9 100644
|
|
--- a/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
|
+++ b/src/main/java/net/minecraft/world/level/CollisionGetter.java
|
|
@@ -54,7 +54,9 @@ public interface CollisionGetter extends BlockGetter {
|
|
}
|
|
|
|
default boolean noCollision(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate) {
|
|
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
|
|
return this.getCollisions(entity, axisalignedbb, predicate).allMatch(VoxelShape::isEmpty);
|
|
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
|
|
}
|
|
|
|
Stream<VoxelShape> getEntityCollisions(@Nullable Entity entity, AABB axisalignedbb, Predicate<Entity> predicate);
|
|
diff --git a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
|
|
index 7208c61da48ce5e735810b6268490584e1d5c260..feca9ff34936686c0665ae0dbc926869087df3a7 100644
|
|
--- a/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/CollisionSpliterator.java
|
|
@@ -7,6 +7,9 @@ import java.util.function.Consumer;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Cursor3D;
|
|
+import net.minecraft.server.MCUtil;
|
|
+import net.minecraft.server.level.ServerPlayer;
|
|
+import net.minecraft.server.level.WorldGenRegion;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
@@ -21,13 +24,13 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
|
public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
|
|
|
|
@Nullable
|
|
- private final Entity source;
|
|
+ private final Entity source; final Entity getEntity() { return this.source; } // Paper - OBFHELPER
|
|
private final AABB box;
|
|
private final CollisionContext context;
|
|
private final Cursor3D cursor;
|
|
- private final BlockPos.MutableBlockPos pos;
|
|
+ private final BlockPos.MutableBlockPos pos; final BlockPos.MutableBlockPos getMutablePos() { return this.pos; } // Paper - OBFHELPER
|
|
private final VoxelShape entityShape;
|
|
- private final CollisionGetter collisionGetter;
|
|
+ private final CollisionGetter collisionGetter; final CollisionGetter getCollisionAccess() { return this.collisionGetter; } // Paper - OBFHELPER
|
|
private boolean needsBorderCheck;
|
|
private final BiPredicate<BlockState, BlockPos> predicate;
|
|
|
|
@@ -64,23 +67,37 @@ public class CollisionSpliterator extends AbstractSpliterator<VoxelShape> {
|
|
boolean collisionCheck(Consumer<? super VoxelShape> consumer) {
|
|
while (true) {
|
|
if (this.cursor.advance()) {
|
|
- int i = this.cursor.nextX();
|
|
- int j = this.cursor.nextY();
|
|
- int k = this.cursor.nextZ();
|
|
+ int i = this.cursor.nextX(); final int x = i;
|
|
+ int j = this.cursor.nextY(); final int y = j;
|
|
+ int k = this.cursor.nextZ(); final int z = k;
|
|
int l = this.cursor.getNextType();
|
|
|
|
if (l == 3) {
|
|
continue;
|
|
}
|
|
|
|
- BlockGetter iblockaccess = this.getChunk(i, k);
|
|
-
|
|
- if (iblockaccess == null) {
|
|
+ // Paper start - ensure we don't load chunks
|
|
+ Entity entity = this.getEntity();
|
|
+ BlockPos.MutableBlockPos blockposition_mutableblockposition = this.getMutablePos();
|
|
+ boolean far = entity != null && MCUtil.distanceSq(entity.getX(), y, entity.getZ(), x, y, z) > 14;
|
|
+ blockposition_mutableblockposition.setValues(x, y, z);
|
|
+
|
|
+ boolean isRegionLimited = this.getCollisionAccess() instanceof WorldGenRegion;
|
|
+ BlockState iblockdata = isRegionLimited ? Blocks.VOID_AIR.defaultBlockState() : ((!far && entity instanceof ServerPlayer) || (entity != null && entity.collisionLoadChunks)
|
|
+ ? this.getCollisionAccess().getBlockState(blockposition_mutableblockposition)
|
|
+ : this.getCollisionAccess().getTypeIfLoaded(blockposition_mutableblockposition)
|
|
+ );
|
|
+
|
|
+ if (iblockdata == null) {
|
|
+ if (!(entity instanceof ServerPlayer) || entity.level.paperConfig.preventMovingIntoUnloadedChunks) {
|
|
+ VoxelShape voxelshape3 = Shapes.of(far ? entity.getBoundingBox() : new AABB(new BlockPos(x, y, z)));
|
|
+ consumer.accept(voxelshape3);
|
|
+ return true;
|
|
+ }
|
|
continue;
|
|
}
|
|
-
|
|
- this.pos.set(i, j, k);
|
|
- BlockState iblockdata = iblockaccess.getBlockState(this.pos);
|
|
+ // Paper - moved up
|
|
+ // Paper end
|
|
|
|
if (!this.predicate.test(iblockdata, this.pos) || l == 1 && !iblockdata.hasLargeCollisionShape() || l == 2 && !iblockdata.is(Blocks.MOVING_PISTON)) {
|
|
continue;
|
|
diff --git a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
|
index fa2942d0b0424390daee2121f8959034c5352e0b..c14d5ebe16a693834ed218af8f737714065b2e17 100644
|
|
--- a/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
|
+++ b/src/main/java/net/minecraft/world/phys/shapes/Shapes.java
|
|
@@ -249,7 +249,8 @@ public final class Shapes {
|
|
|
|
if (k2 < 3) {
|
|
blockposition_mutableblockposition.set(enumaxiscycle1, i2, j2, l1);
|
|
- BlockState iblockdata = world.getBlockState(blockposition_mutableblockposition);
|
|
+ BlockState iblockdata = world.getTypeIfLoaded(blockposition_mutableblockposition); // Paper
|
|
+ if (iblockdata == null) return 0.0D; // Paper
|
|
|
|
if ((k2 != 1 || iblockdata.hasLargeCollisionShape()) && (k2 != 2 || iblockdata.is(Blocks.MOVING_PISTON))) {
|
|
initial = iblockdata.getCollisionShape((BlockGetter) world, blockposition_mutableblockposition, context).collide(enumdirection_enumaxis2, box.move((double) (-blockposition_mutableblockposition.getX()), (double) (-blockposition_mutableblockposition.getY()), (double) (-blockposition_mutableblockposition.getZ())), initial);
|