mirror of
https://github.com/PaperMC/Paper.git
synced 2025-07-08 20:39:32 +00:00
If the player dies, then they are removed from the world and as a result are not present in the world entity map. To guarantee that the player entity scheduler is ticked, we can tick all schedulers for players in the server player list, and then skip all players we find in the world entity map. This problem is not present on Folia since Folia must guarantee that the player remains in the world.
96 lines
5.9 KiB
Diff
96 lines
5.9 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/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
|
index 23dfc87db1d5e90099270627197abc0f787a4393..27a01fd28ea565221768f31df02f0a2ddf242fce 100644
|
|
--- a/net/minecraft/world/entity/Entity.java
|
|
+++ b/net/minecraft/world/entity/Entity.java
|
|
@@ -230,6 +230,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
public @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
|
|
|
|
private volatile @Nullable org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity; // Paper - Folia schedulers - volatile
|
|
+ public boolean collisionLoadChunks = false; // Paper
|
|
|
|
public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() {
|
|
if (this.bukkitEntity == null) {
|
|
diff --git a/net/minecraft/world/level/BlockCollisions.java b/net/minecraft/world/level/BlockCollisions.java
|
|
index ed6e4f9fd0c7ad1219e66bc1cb4038191dd6edd8..45a20dbb935b12d429153463dba5d6fd3385dd7a 100644
|
|
--- a/net/minecraft/world/level/BlockCollisions.java
|
|
+++ b/net/minecraft/world/level/BlockCollisions.java
|
|
@@ -80,16 +80,37 @@ public class BlockCollisions<T> extends AbstractIterator<T> {
|
|
@Override
|
|
protected T computeNext() {
|
|
while (this.cursor.advance()) {
|
|
- int i = this.cursor.nextX();
|
|
- int i1 = this.cursor.nextY();
|
|
- int i2 = this.cursor.nextZ();
|
|
+ int i = this.cursor.nextX(); final int x = i; // Paper - OBFHELPER
|
|
+ int i1 = this.cursor.nextY(); final int y = i1; // Paper - OBFHELPER
|
|
+ int i2 = this.cursor.nextZ(); final int z = i2; // Paper - OBFHELPER
|
|
int nextType = this.cursor.getNextType();
|
|
if (nextType != 3) {
|
|
- BlockGetter chunk = this.getChunk(i, i2);
|
|
- if (chunk != null) {
|
|
- this.pos.set(i, i1, i2);
|
|
- BlockState blockState = chunk.getBlockState(this.pos);
|
|
- if ((!this.onlySuffocatingBlocks || blockState.isSuffocating(chunk, this.pos))
|
|
+ // Paper start - ensure we don't load chunks
|
|
+ // BlockGetter blockGetter = this.getChunk(i, k);
|
|
+ if (true) {
|
|
+ @Nullable final Entity source = this.context instanceof net.minecraft.world.phys.shapes.EntityCollisionContext entityContext ? entityContext.getEntity() : null;
|
|
+ final boolean far = source != null && io.papermc.paper.util.MCUtil.distanceSq(source.getX(), y, source.getZ(), x, y, z) > 14;
|
|
+ this.pos.set(x, y, z);
|
|
+ BlockState blockState;
|
|
+ if (this.collisionGetter instanceof net.minecraft.server.level.WorldGenRegion) {
|
|
+ BlockGetter blockGetter = this.getChunk(x, z);
|
|
+ if (blockGetter == null) {
|
|
+ continue;
|
|
+ }
|
|
+ blockState = blockGetter.getBlockState(this.pos);
|
|
+ } else if ((!far && source instanceof net.minecraft.server.level.ServerPlayer) || (source != null && source.collisionLoadChunks)) {
|
|
+ blockState = this.collisionGetter.getBlockState(this.pos);
|
|
+ } else {
|
|
+ blockState = this.collisionGetter.getBlockStateIfLoaded(this.pos);
|
|
+ }
|
|
+ if (blockState == null) {
|
|
+ if (!(source instanceof net.minecraft.server.level.ServerPlayer) || source.level().paperConfig().chunks.preventMovingIntoUnloadedChunks) {
|
|
+ return this.resultProvider.apply(new BlockPos.MutableBlockPos(x, y, z), Shapes.create(far ? source.getBoundingBox() : new AABB(new BlockPos(x, y, z))));
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ if (true // onlySuffocatingBlocks is only true on the client, so we don't care about it here
|
|
+ // Paper end - ensure we don't load chunks
|
|
&& (nextType != 1 || blockState.hasLargeCollisionShape())
|
|
&& (nextType != 2 || blockState.is(Blocks.MOVING_PISTON))) {
|
|
VoxelShape collisionShape = this.context.getCollisionShape(blockState, this.collisionGetter, this.pos);
|
|
diff --git a/net/minecraft/world/level/CollisionGetter.java b/net/minecraft/world/level/CollisionGetter.java
|
|
index 8956e5d66481d8ca874999df8f38eb28651362db..056005f0728ba14c9d0dd9dd16400a35a9656243 100644
|
|
--- a/net/minecraft/world/level/CollisionGetter.java
|
|
+++ b/net/minecraft/world/level/CollisionGetter.java
|
|
@@ -50,11 +50,13 @@ public interface CollisionGetter extends BlockGetter {
|
|
}
|
|
|
|
default boolean noCollision(@Nullable Entity entity, AABB collisionBox, boolean checkLiquid) {
|
|
+ try { if (entity != null) entity.collisionLoadChunks = true; // Paper
|
|
for (VoxelShape voxelShape : checkLiquid ? this.getBlockAndLiquidCollisions(entity, collisionBox) : this.getBlockCollisions(entity, collisionBox)) {
|
|
if (!voxelShape.isEmpty()) {
|
|
return false;
|
|
}
|
|
}
|
|
+ } finally { if (entity != null) entity.collisionLoadChunks = false; } // Paper
|
|
|
|
if (!this.getEntityCollisions(entity, collisionBox).isEmpty()) {
|
|
return false;
|