This patch replaces the vanilla collision code for both block and entity collisions with faster implementations by JellySquid, used originally in her Lithium mod. Optimizes Full Block voxel collisions, and removes streams from Entity collisions Original code by JellySquid, licensed under GNU Lesser General Public License v3.0 you can find the original code on https://github.com/jellysquid3/lithium-fabric/tree/1.15.x/fabric (Yarn mappings) Ported by Co-authored-by: Zoutelande <54509836+Zoutelande@users.noreply.github.com> Touched up by Aikar to keep previous paper optimizations
202 lines
9.1 KiB
Diff
202 lines
9.1 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Wed, 4 Jul 2018 02:10:36 -0400
|
|
Subject: [PATCH] Store reference to current Chunk for Entity and Block
|
|
Entities
|
|
|
|
This enables us a fast reference to the entities current chunk instead
|
|
of having to look it up by hashmap lookups.
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
|
index b39ce329aa0b2e8da679a7b658f707f1da1f1a99..4d7dc714748a82470d00e787eeb3dc7ca08c656a 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -29,7 +29,7 @@ public class Chunk implements IChunkAccess {
|
|
private final ChunkSection[] sections;
|
|
private BiomeStorage d;
|
|
private final Map<BlockPosition, NBTTagCompound> e;
|
|
- public boolean loaded;
|
|
+ public boolean loaded; public boolean isLoaded() { return loaded; } // Paper - OBFHELPER
|
|
public final World world;
|
|
public final Map<HeightMap.Type, HeightMap> heightMap;
|
|
private final ChunkConverter i;
|
|
@@ -55,11 +55,36 @@ public class Chunk implements IChunkAccess {
|
|
this(world, chunkcoordintpair, biomestorage, ChunkConverter.a, TickListEmpty.b(), TickListEmpty.b(), 0L, (ChunkSection[]) null, (Consumer) null);
|
|
}
|
|
|
|
+ // Paper start
|
|
+ private class TileEntityHashMap extends java.util.HashMap<BlockPosition, TileEntity> {
|
|
+ @Override
|
|
+ public TileEntity put(BlockPosition key, TileEntity value) {
|
|
+ TileEntity replaced = super.put(key, value);
|
|
+ if (replaced != null) {
|
|
+ replaced.setCurrentChunk(null);
|
|
+ }
|
|
+ if (value != null) {
|
|
+ value.setCurrentChunk(Chunk.this);
|
|
+ }
|
|
+ return replaced;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public TileEntity remove(Object key) {
|
|
+ TileEntity removed = super.remove(key);
|
|
+ if (removed != null) {
|
|
+ removed.setCurrentChunk(null);
|
|
+ }
|
|
+ return removed;
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
public Chunk(World world, ChunkCoordIntPair chunkcoordintpair, BiomeStorage biomestorage, ChunkConverter chunkconverter, TickList<Block> ticklist, TickList<FluidType> ticklist1, long i, @Nullable ChunkSection[] achunksection, @Nullable Consumer<Chunk> consumer) {
|
|
this.sections = new ChunkSection[16];
|
|
this.e = Maps.newHashMap();
|
|
this.heightMap = Maps.newEnumMap(HeightMap.Type.class);
|
|
- this.tileEntities = Maps.newHashMap();
|
|
+ this.tileEntities = new TileEntityHashMap(); // Paper
|
|
this.l = Maps.newHashMap();
|
|
this.m = Maps.newHashMap();
|
|
this.n = new ShortList[16];
|
|
@@ -462,6 +487,7 @@ public class Chunk implements IChunkAccess {
|
|
}
|
|
|
|
entity.inChunk = true;
|
|
+ entity.setCurrentChunk(this); // Paper
|
|
entity.chunkX = this.loc.x;
|
|
entity.chunkY = k;
|
|
entity.chunkZ = this.loc.z;
|
|
@@ -474,6 +500,7 @@ public class Chunk implements IChunkAccess {
|
|
((HeightMap) this.heightMap.get(heightmap_type)).a(along);
|
|
}
|
|
|
|
+ public void removeEntity(Entity entity) { this.b(entity); } // Paper - OBFHELPER
|
|
public void b(Entity entity) {
|
|
this.a(entity, entity.chunkY);
|
|
}
|
|
@@ -487,7 +514,12 @@ public class Chunk implements IChunkAccess {
|
|
i = this.entitySlices.length - 1;
|
|
}
|
|
|
|
- this.entitySlices[i].remove(entity);
|
|
+ // Paper start
|
|
+ if (entity.currentChunk != null && entity.currentChunk.get() == this) entity.setCurrentChunk(null);
|
|
+ if (!this.entitySlices[i].remove(entity)) {
|
|
+ return;
|
|
+ }
|
|
+ // Paper end
|
|
this.entities.remove(entity); // Paper
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
|
|
index 6c7816fdc1ef476969cb70c8ea697b60746d6ab4..0d8262b1d2722e716f95db4c9a8a132c54b613cf 100644
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
|
@@ -134,7 +134,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
private static final DataWatcherObject<Boolean> aB = DataWatcher.a(Entity.class, DataWatcherRegistry.i);
|
|
private static final DataWatcherObject<Boolean> aC = DataWatcher.a(Entity.class, DataWatcherRegistry.i);
|
|
protected static final DataWatcherObject<EntityPose> POSE = DataWatcher.a(Entity.class, DataWatcherRegistry.s);
|
|
- public boolean inChunk;
|
|
+ public boolean inChunk; public boolean isAddedToChunk() { return inChunk; } // Paper - OBFHELPER
|
|
public int chunkX; public int getChunkX() { return chunkX; } // Paper - OBFHELPER
|
|
public int chunkY; public int getChunkY() { return chunkY; } // Paper - OBFHELPER
|
|
public int chunkZ; public int getChunkZ() { return chunkZ; } // Paper - OBFHELPER
|
|
@@ -178,7 +178,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
}
|
|
|
|
public boolean isChunkLoaded() {
|
|
- return world.isChunkLoaded((int) Math.floor(this.locX) >> 4, (int) Math.floor(this.locZ) >> 4);
|
|
+ return getCurrentChunk() != null;
|
|
}
|
|
// CraftBukkit end
|
|
|
|
@@ -1709,6 +1709,43 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
|
|
}
|
|
|
|
// Paper start
|
|
+ java.lang.ref.WeakReference<Chunk> currentChunk = null;
|
|
+
|
|
+ public void setCurrentChunk(Chunk chunk) {
|
|
+ this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
|
|
+ }
|
|
+ /**
|
|
+ * Returns the entities current registered chunk. If the entity is not added to a chunk yet, it will return null
|
|
+ */
|
|
+ public Chunk getCurrentChunk() {
|
|
+ final Chunk chunk = currentChunk != null ? currentChunk.get() : null;
|
|
+ if (chunk != null && chunk.isLoaded()) {
|
|
+ return chunk;
|
|
+ }
|
|
+
|
|
+ return !isAddedToChunk() ? null : ((ChunkProviderServer) world.chunkProvider).getChunkAtIfLoadedMainThreadNoCache(getChunkX(), getChunkZ());
|
|
+ }
|
|
+
|
|
+ /**
|
|
+ * Returns the chunk at the location, using the entities local cache if avail
|
|
+ * Will only return null if the location specified is not loaded
|
|
+ */
|
|
+ public Chunk getCurrentChunkAt(int x, int z) {
|
|
+ Chunk chunk = getCurrentChunk();
|
|
+ if (chunk != null && getChunkX() == chunk.getPos().x && getChunkZ() == chunk.getPos().z) {
|
|
+ return chunk;
|
|
+ }
|
|
+ return ((ChunkProviderServer) world.chunkProvider).getChunkAtIfLoadedMainThreadNoCache(getChunkX(), getChunkZ());
|
|
+ }
|
|
+ /**
|
|
+ * Returns the chunk at the entities current location, using the entities local cache if avail
|
|
+ * Ideally this is always the same as getCurrentChunk, but only becomes different in registration issues.
|
|
+ * Will only return null if the location specified is not loaded
|
|
+ */
|
|
+ public Chunk getChunkAtLocation() {
|
|
+ return getCurrentChunkAt((int)Math.floor(locX) >> 4, (int)Math.floor(locZ) >> 4);
|
|
+ }
|
|
+
|
|
private MinecraftKey entityKey;
|
|
private String entityKeyString;
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
|
|
index 9071bb7ece6d38d85b4ea11e53671f3ec5210b28..820180ab3f7053c348caa80cc21f15dfa3d26afd 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntity.java
|
|
@@ -51,6 +51,15 @@ public abstract class TileEntity implements KeyedObject { // Paper
|
|
getMinecraftKey(); // Try to load if it doesn't exists.
|
|
return tileEntityKeyString;
|
|
}
|
|
+
|
|
+ private java.lang.ref.WeakReference<Chunk> currentChunk = null;
|
|
+ public Chunk getCurrentChunk() {
|
|
+ final Chunk chunk = currentChunk != null ? currentChunk.get() : null;
|
|
+ return chunk != null && chunk.isLoaded() ? chunk : null;
|
|
+ }
|
|
+ public void setCurrentChunk(Chunk chunk) {
|
|
+ this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
|
|
+ }
|
|
// Paper end
|
|
|
|
@Nullable
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
index 056525526e87fa75f026278a82311640a3b466db..5a047dd68223363ef83f8d5b77adbd45f7531113 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
|
@@ -138,6 +138,7 @@ import net.minecraft.server.EntityZombieVillager;
|
|
import net.minecraft.server.EnumChatFormat;
|
|
import net.minecraft.server.IChatBaseComponent;
|
|
import net.minecraft.server.NBTTagCompound;
|
|
+import org.bukkit.Chunk; // Paper
|
|
import org.bukkit.EntityEffect;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.Server;
|
|
@@ -179,6 +180,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
|
this.entity = entity;
|
|
}
|
|
|
|
+ @Override
|
|
+ public Chunk getChunk() {
|
|
+ net.minecraft.server.Chunk currentChunk = entity.getCurrentChunk();
|
|
+ return currentChunk != null ? currentChunk.bukkitChunk : getLocation().getChunk();
|
|
+ }
|
|
+
|
|
public static CraftEntity getEntity(CraftServer server, Entity entity) {
|
|
/*
|
|
* Order is *EXTREMELY* important -- keep it right! =D
|