Paper/Spigot-Server-Patches/0329-Cache-World-Entity-Type-counts.patch
Shane Freeder fb25dc17c6 Updated Upstream (Bukkit/CraftBukkit)
Upstream has released updates that appears 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:
da08d022 SPIGOT-4700: Add PlayerFishEvent.State.REEL_IN
0cef14e4 Remove draft API from selectEntities

CraftBukkit Changes:
a46fdbc6 Remove outdated build delay.
3697519b SPIGOT-4708: Fix ExactChoice recipes neglecting material
9ead7009 SPIGOT-4677: Add minecraft.admin.command_feedback permission
c3749a23 Remove the Damage tag from items when it is 0.
f74c7b95 SPIGOT-4706: Can't interact with active item
494eef45 Mention requirement of JIRA ticket for bug fixes
51d62dec SPIGOT-4702: Exception when middle clicking certain slots
be557e69 SPIGOT-4700: Add PlayerFishEvent.State.REEL_IN
2019-04-22 22:36:14 +01:00

230 lines
9.2 KiB
Diff

From ea48b312bc5e985bd2c1654d8494d235bcd632a4 Mon Sep 17 00:00:00 2001
From: Colin Godsey <crgodsey@gmail.com>
Date: Wed, 8 Aug 2018 10:10:06 -0600
Subject: [PATCH] Cache World Entity Type counts
Optimizes mob spawning by keeping a count of entities by type
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldEntityList.java b/src/main/java/com/destroystokyo/paper/PaperWorldEntityList.java
new file mode 100644
index 0000000000..a10a5bc138
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldEntityList.java
@@ -0,0 +1,121 @@
+package com.destroystokyo.paper;
+
+import net.minecraft.server.Entity;
+import net.minecraft.server.EntityInsentient;
+import net.minecraft.server.EnumCreatureType;
+import net.minecraft.server.IAnimal;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.World;
+import net.minecraft.server.WorldServer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class PaperWorldEntityList extends ArrayList<Entity> {
+
+ private final WorldServer world;
+ private final int[] entityCounts = new int[EnumCreatureType.values().length];
+
+
+ public PaperWorldEntityList(World world) {
+ this.world = (WorldServer) world;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Entity> c) {
+ for (Entity e : c) {
+ updateEntityCount(e, 1);
+ }
+
+ return super.addAll(c);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c) {
+ for (Object e : c) {
+ if (e instanceof Entity && ((Entity) e).getWorld() == world) {
+ updateEntityCount((Entity) e, -1);
+ }
+ }
+
+ return super.removeAll(c);
+ }
+
+ @Override
+ public boolean add(Entity e) {
+ updateEntityCount(e, 1);
+
+ return super.add(e);
+ }
+
+ @Override
+ public Entity remove(int index) {
+ guard();
+ Entity entity = super.remove(index);
+ if (entity != null) updateEntityCount(entity, -1);
+ return entity;
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ guard();
+ if (super.remove(o)) {
+ updateEntityCount((Entity) o, -1);
+ return true;
+ }
+ return false;
+ }
+
+ private void guard() {
+ if (world.guardEntityList) {
+ throw new java.util.ConcurrentModificationException();
+ }
+ }
+
+ public int getCreatureCount(EnumCreatureType type) {
+ return entityCounts[type.ordinal()];
+ }
+
+ private void updateEntityCount(EnumCreatureType type, int amt) {
+ int count = entityCounts[type.ordinal()];
+
+ count += amt;
+
+ if (count < 0) {
+ MinecraftServer.LOGGER.error("Paper - Entity count cache has gone negative");
+ count = 0;
+ }
+
+ entityCounts[type.ordinal()] = count;
+ }
+
+ public void updateEntityCount(Entity entity, int amt) {
+ if (!(entity instanceof IAnimal)) return;
+
+ if (entity instanceof EntityInsentient) {
+ EntityInsentient entityinsentient = (EntityInsentient) entity;
+ if (amt > 0 && entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) {
+ return;
+ }
+ }
+ if (amt < 0) {
+ if (!entity.hasBeenCounted) {
+ return;
+ }
+ // Only remove once, we remove from if the entity list is guarded, but may be called later
+ entity.hasBeenCounted = false;
+ } else {
+ if (entity.hasBeenCounted) {
+ return;
+ }
+ entity.hasBeenCounted = true;
+ }
+
+ for (EnumCreatureType type : EnumCreatureType.values()) {
+ if (type.matches(entity)) {
+ updateEntityCount(type, amt);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
index 4dc7c8ba68..90e0d9d453 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -122,6 +122,7 @@ public abstract class Entity implements INamableTileEntity, ICommandListener, Ke
private boolean az;
public boolean dead;
public boolean shouldBeRemoved; // Paper
+ public boolean hasBeenCounted = false; // Paper
public float width;
public float length;
public float J;
diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java
index ee5078370c..856ddf2a74 100644
--- a/src/main/java/net/minecraft/server/EntityInsentient.java
+++ b/src/main/java/net/minecraft/server/EntityInsentient.java
@@ -259,6 +259,7 @@ public abstract class EntityInsentient extends EntityLiving {
public void tick() {
super.tick();
+ if (isTypeNotPersistent() && hasBeenCounted == this.isPersistent()) ((com.destroystokyo.paper.PaperWorldEntityList) this.world.entityList).updateEntityCount(this, hasBeenCounted ? -1 : 1); // Paper - adjust count if persistence state changes
if (!this.world.isClientSide) {
this.dl();
if (this.ticksLived % 5 == 0) {
diff --git a/src/main/java/net/minecraft/server/EnumCreatureType.java b/src/main/java/net/minecraft/server/EnumCreatureType.java
index 79e52f7bac..42f6a6a93a 100644
--- a/src/main/java/net/minecraft/server/EnumCreatureType.java
+++ b/src/main/java/net/minecraft/server/EnumCreatureType.java
@@ -16,6 +16,8 @@ public enum EnumCreatureType {
this.h = flag1;
}
+ public boolean matches(Entity entity) { return innerClass().isAssignableFrom(entity.getClass()); } // Paper
+ public Class<? extends IAnimal> innerClass() { return this.a(); } // Paper - OBFHELPER
public Class<? extends IAnimal> a() {
return this.e;
}
diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java
index e626165520..d125fae03b 100644
--- a/src/main/java/net/minecraft/server/SpawnerCreature.java
+++ b/src/main/java/net/minecraft/server/SpawnerCreature.java
@@ -114,7 +114,7 @@ public final class SpawnerCreature {
if ((!enumcreaturetype.c() || flag1) && (enumcreaturetype.c() || flag) && (!enumcreaturetype.d() || flag2)) {
k = limit * i / SpawnerCreature.b; // CraftBukkit - use per-world limits
- int l1 = worldserver.a(enumcreaturetype.a(), k);
+ int l1 = ((com.destroystokyo.paper.PaperWorldEntityList) worldserver.entityList).getCreatureCount(enumcreaturetype); // Paper - entity count cache
if (l1 <= k) {
BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition();
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index e31e366249..b007eb36c7 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -45,7 +45,8 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
private static final EnumDirection[] a = EnumDirection.values();
private int b = 63;
// Spigot start - guard entity list from removals
- public final List<Entity> entityList = new java.util.ArrayList<Entity>()
+ public final List<Entity> entityList = new com.destroystokyo.paper.PaperWorldEntityList(this);
+ /* // Paper start
{
@Override
public Entity remove(int index)
@@ -69,6 +70,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
}
}
};
+ */ // Paper end
// Spigot end
protected final Set<Entity> g = com.google.common.collect.Sets.newHashSet(); public Set<Entity> getEntityUnloadQueue() { return g; };// Paper - OBFHELPER
//public final List<TileEntity> tileEntityList = Lists.newArrayList(); // Paper - remove unused list
@@ -139,8 +141,10 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
public final com.destroystokyo.paper.PaperWorldConfig paperConfig; // Paper
public final co.aikar.timings.WorldTimingsHandler timings; // Paper
- private boolean guardEntityList; // Spigot
+ public boolean guardEntityList; // Spigot // Paper - public
public static BlockPosition lastPhysicsProblem; // Spigot
+ public static boolean haveWeSilencedAPhysicsCrash;
+ public static String blockLocation;
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
private int tileTickPosition;
@@ -1121,6 +1125,7 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
Chunk chunk = entity.getCurrentChunk(); // Paper
if (chunk != null) chunk.removeEntity(entity); // Paper
entity.shouldBeRemoved = true; // Paper
+ ((com.destroystokyo.paper.PaperWorldEntityList) entityList).updateEntityCount(entity, -1); // Paper
if (!guardEntityList) { // Spigot - It will get removed after the tick if we are ticking // Paper - always remove from current chunk above
// CraftBukkit start - Decrement loop variable field if we've already ticked this entity
--
2.21.0