From ede8ec738706ecf28e0af415d1596a9a8ca4c47a Mon Sep 17 00:00:00 2001 From: Colin Godsey Date: Wed, 8 Aug 2018 15:22:58 -0600 Subject: [PATCH 1/8] add entity count cache #1207 --- .../Add-entity-count-cache.patch | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 Spigot-Server-Patches/Add-entity-count-cache.patch diff --git a/Spigot-Server-Patches/Add-entity-count-cache.patch b/Spigot-Server-Patches/Add-entity-count-cache.patch new file mode 100644 index 0000000000..0b17355a0b --- /dev/null +++ b/Spigot-Server-Patches/Add-entity-count-cache.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Godsey +Date: Wed, 8 Aug 2018 16:10:06 -0600 +Subject: [PATCH] Add entity count cache + + +diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java +index 004c3ec4..09c2bc32 100644 +--- a/src/main/java/net/minecraft/server/World.java ++++ b/src/main/java/net/minecraft/server/World.java +@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose + // Spigot start - guard entity list from removals + public final List entityList = new java.util.ArrayList() + { ++ // Paper start - entity count cache ++ @Override ++ public boolean addAll(Collection c) { ++ for(Entity e : c) { ++ updateEntityCount(e, true); ++ } ++ ++ return super.addAll(c); ++ } ++ ++ @Override ++ public boolean removeAll(Collection c) { ++ for(Object e : c) { ++ if(e instanceof Entity) { ++ updateEntityCount((Entity)e, false); ++ } ++ } ++ ++ return super.removeAll(c); ++ } ++ ++ @Override ++ public boolean add(Entity e) { ++ updateEntityCount(e, true); ++ ++ return super.add(e); ++ } ++ ++ // Paper end ++ + @Override + public Entity remove(int index) + { + guard(); ++ updateEntityCount(get(index), false); // Paper + return super.remove( index ); + } + +@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose + public boolean remove(Object o) + { + guard(); ++ if(o instanceof Entity) updateEntityCount((Entity)o, false); // Paper + return super.remove( o ); + } + +@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose + public final Map playersByName = Maps.newHashMap(); // Paper - World EntityHuman Lookup Optimizations + public final List k = Lists.newArrayList(); + protected final IntHashMap entitiesById = new IntHashMap(); ++ private Map, Integer> countCache = new HashMap(); // Paper + private final long G = 16777215L; + private int H; public int getSkylightSubtracted() { return this.H; } public void setSkylightSubtracted(int value) { this.H = value;} // Paper - OBFHELPER + protected int m = (new Random()).nextInt(); +@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose + + } + +- public int a(Class oclass) { ++ // Paper start - entity count cache ++ private int countEntityType(Class oclass) { + int i = 0; + Iterator iterator = this.entityList.iterator(); + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); +- if (entity.shouldBeRemoved) continue; // Paper + // CraftBukkit start - Split out persistent check, don't apply it to special persistent mobs +- if (entity instanceof EntityInsentient) { +- EntityInsentient entityinsentient = (EntityInsentient) entity; +- if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { +- continue; +- } ++ if (shouldIgnoreForCount(entity)) { ++ continue; + } + + if (oclass.isAssignableFrom(entity.getClass())) { +@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose + return i; + } + ++ public int getEntityCount(Class oclass) { return a(oclass); } // Paper - OBFHELPER ++ public int a(Class oclass) { ++ if(countCache.containsKey(oclass)) { ++ return countCache.get(oclass); ++ } else { ++ int count = countEntityType(oclass); ++ ++ countCache.put(oclass, count); ++ ++ return count; ++ } ++ } ++ ++ public boolean shouldIgnoreForCount(Entity entity) { ++ if (entity instanceof EntityInsentient) { ++ EntityInsentient entityinsentient = (EntityInsentient) entity; ++ return entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent(); ++ } ++ ++ return false; ++ } ++ ++ protected void updateEntityCount(Entity entity, boolean incr) { ++ if(entity == null) return; ++ if(shouldIgnoreForCount(entity)) return; ++ ++ countCache.replaceAll((clazz, count) -> { ++ if(clazz.isAssignableFrom(entity.getClass())) { ++ int newCount = count; ++ ++ if(incr) newCount++; ++ else newCount--; ++ ++ if(newCount < 0) { ++ e.warn("Entity count cache has gone negative"); ++ newCount = 0; ++ } ++ ++ return newCount; ++ } else { ++ return count; ++ } ++ }); ++ } ++ // Paper end ++ + public void addChunkEntities(Collection collection) { a(collection); } // Paper - OBFHELPER + public void a(Collection collection) { + org.spigotmc.AsyncCatcher.catchOp( "entity world add"); // Spigot +-- +2.15.2 (Apple Git-101.1) + From b473051336978cbede1087ed7b740b4631313faf Mon Sep 17 00:00:00 2001 From: Colin Godsey Date: Wed, 8 Aug 2018 15:23:54 -0600 Subject: [PATCH 2/8] Configurable water over lava #1227 --- ...le-speed-for-water-flowing-over-lava.patch | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch diff --git a/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch b/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch new file mode 100644 index 0000000000..166dccd812 --- /dev/null +++ b/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Godsey +Date: Wed, 8 Aug 2018 16:33:21 -0600 +Subject: [PATCH] Configurable speed for water flowing over lava + + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 61c8b58b..ab3f59ad 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -0,0 +0,0 @@ public class PaperWorldConfig { + } + } + ++ public int waterOverLavaFlowSpeed; ++ private void waterOverLavaFlowSpeed() { ++ waterOverLavaFlowSpeed = getInt("water-over-lava-flow-speed", 5); ++ log("Water over lava flow speed: " + waterOverLavaFlowSpeed); ++ } ++ + public enum DuplicateUUIDMode { + SAFE_REGEN, REGEN, DELETE, NOTHING, WARN + } +diff --git a/src/main/java/net/minecraft/server/BlockFluids.java b/src/main/java/net/minecraft/server/BlockFluids.java +index 6ecc1f84..637f6580 100644 +--- a/src/main/java/net/minecraft/server/BlockFluids.java ++++ b/src/main/java/net/minecraft/server/BlockFluids.java +@@ -0,0 +0,0 @@ public class BlockFluids extends Block implements IFluidSource { + + public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1) { + if (this.a(world, blockposition, iblockdata)) { +- world.H().a(blockposition, iblockdata.s().c(), this.a((IWorldReader) world)); ++ world.H().a(blockposition, iblockdata.s().c(), this.getFlowSpeed(world, blockposition)); // Paper + } + + } ++ ++ /** ++ * Paper - Get flow speed. Throttle if its water and flowing adjacent to lava ++ */ ++ public int getFlowSpeed(World world, BlockPosition blockposition) { ++ if (this.material == Material.WATER && ( ++ world.getType(blockposition.north(1)).getBlock().material == Material.LAVA || ++ world.getType(blockposition.south(1)).getBlock().material == Material.LAVA || ++ world.getType(blockposition.west(1)).getBlock().material == Material.LAVA || ++ world.getType(blockposition.east(1)).getBlock().material == Material.LAVA)) { ++ return world.paperConfig.waterOverLavaFlowSpeed; ++ } ++ return this.a(world); ++ } + + public IBlockData updateState(IBlockData iblockdata, EnumDirection enumdirection, IBlockData iblockdata1, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) { + if (iblockdata.s().d() || iblockdata1.s().d()) { +@@ -0,0 +0,0 @@ public class BlockFluids extends Block implements IFluidSource { + + public void doPhysics(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) { + if (this.a(world, blockposition, iblockdata)) { +- world.H().a(blockposition, iblockdata.s().c(), this.a((IWorldReader) world)); ++ world.H().a(blockposition, iblockdata.s().c(), this.getFlowSpeed(world, blockposition)); // Paper + } + + } +-- +2.15.2 (Apple Git-101.1) + From 52573735641077487fb593e310b7a2fe4d23f0a6 Mon Sep 17 00:00:00 2001 From: Colin Godsey Date: Wed, 8 Aug 2018 18:07:03 -0600 Subject: [PATCH 3/8] pr fixes --- .../Add-entity-count-cache.patch | 106 +++++++++--------- ...le-speed-for-water-flowing-over-lava.patch | 6 +- 2 files changed, 58 insertions(+), 54 deletions(-) diff --git a/Spigot-Server-Patches/Add-entity-count-cache.patch b/Spigot-Server-Patches/Add-entity-count-cache.patch index 0b17355a0b..962f4d2c2d 100644 --- a/Spigot-Server-Patches/Add-entity-count-cache.patch +++ b/Spigot-Server-Patches/Add-entity-count-cache.patch @@ -1,11 +1,11 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Colin Godsey -Date: Wed, 8 Aug 2018 16:10:06 -0600 +Date: Wed, 8 Aug 2018 10:10:06 -0600 Subject: [PATCH] Add entity count cache diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 004c3ec4..09c2bc32 100644 +index 004c3ec47..c392595c0 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose @@ -15,7 +15,7 @@ index 004c3ec4..09c2bc32 100644 + // Paper start - entity count cache + @Override + public boolean addAll(Collection c) { -+ for(Entity e : c) { ++ for (Entity e : c) { + updateEntityCount(e, true); + } + @@ -24,8 +24,8 @@ index 004c3ec4..09c2bc32 100644 + + @Override + public boolean removeAll(Collection c) { -+ for(Object e : c) { -+ if(e instanceof Entity) { ++ for (Object e : c) { ++ if (e instanceof Entity) { + updateEntityCount((Entity)e, false); + } + } @@ -54,7 +54,7 @@ index 004c3ec4..09c2bc32 100644 public boolean remove(Object o) { guard(); -+ if(o instanceof Entity) updateEntityCount((Entity)o, false); // Paper ++ if (o instanceof Entity) updateEntityCount((Entity)o, false); // Paper return super.remove( o ); } @@ -67,47 +67,48 @@ index 004c3ec4..09c2bc32 100644 private int H; public int getSkylightSubtracted() { return this.H; } public void setSkylightSubtracted(int value) { this.H = value;} // Paper - OBFHELPER protected int m = (new Random()).nextInt(); @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose - } -- public int a(Class oclass) { -+ // Paper start - entity count cache -+ private int countEntityType(Class oclass) { + public int a(Class oclass) { ++ if (true) return getEntityCount(oclass); //Paper - short circuit to cached method ++ int i = 0; Iterator iterator = this.entityList.iterator(); - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); -- if (entity.shouldBeRemoved) continue; // Paper - // CraftBukkit start - Split out persistent check, don't apply it to special persistent mobs -- if (entity instanceof EntityInsentient) { -- EntityInsentient entityinsentient = (EntityInsentient) entity; -- if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { -- continue; -- } -+ if (shouldIgnoreForCount(entity)) { -+ continue; - } - - if (oclass.isAssignableFrom(entity.getClass())) { @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose return i; } -+ public int getEntityCount(Class oclass) { return a(oclass); } // Paper - OBFHELPER -+ public int a(Class oclass) { -+ if(countCache.containsKey(oclass)) { -+ return countCache.get(oclass); -+ } else { -+ int count = countEntityType(oclass); ++ // Paper start - entity count cache ++ private int countEntityType(Class oclass) { ++ int i = 0; ++ Iterator iterator = this.entityList.iterator(); + -+ countCache.put(oclass, count); ++ while (iterator.hasNext()) { ++ Entity entity = (Entity) iterator.next(); + -+ return count; ++ if (shouldIgnoreForCount(entity)) continue; ++ if (oclass.isAssignableFrom(entity.getClass())) i++; + } ++ ++ return i; ++ } ++ ++ public int getEntityCount(Class oclass) { ++ Integer count = countCache.get(oclass); ++ ++ if (count != null) return count; ++ ++ count = countEntityType(oclass); ++ ++ countCache.put(oclass, count); ++ ++ return count; + } + + public boolean shouldIgnoreForCount(Entity entity) { ++ if (entity == null) return true; ++ + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + return entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent(); @@ -116,27 +117,30 @@ index 004c3ec4..09c2bc32 100644 + return false; + } + ++ protected void updateEntityCount(Class clazz, boolean incr) { ++ Integer countObject = countCache.get(clazz); ++ ++ if (countObject == null) return; ++ ++ int count = countObject; ++ ++ if (incr) count++; ++ else count--; ++ ++ if(count < 0) { ++ e.warn("Entity count cache has gone negative"); ++ count = 0; ++ } ++ ++ countCache.put(clazz, count); ++ } ++ + protected void updateEntityCount(Entity entity, boolean incr) { -+ if(entity == null) return; -+ if(shouldIgnoreForCount(entity)) return; ++ if (shouldIgnoreForCount(entity)) return; + -+ countCache.replaceAll((clazz, count) -> { -+ if(clazz.isAssignableFrom(entity.getClass())) { -+ int newCount = count; -+ -+ if(incr) newCount++; -+ else newCount--; -+ -+ if(newCount < 0) { -+ e.warn("Entity count cache has gone negative"); -+ newCount = 0; -+ } -+ -+ return newCount; -+ } else { -+ return count; -+ } -+ }); ++ for (Class clazz = entity.getClass() ; !clazz.equals(Object.class) ; clazz = clazz.getSuperclass()) { ++ updateEntityCount(clazz, incr); ++ } + } + // Paper end + diff --git a/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch b/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch index 166dccd812..4dd7ba5c1e 100644 --- a/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch +++ b/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch @@ -1,11 +1,11 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Colin Godsey -Date: Wed, 8 Aug 2018 16:33:21 -0600 +Date: Wed, 8 Aug 2018 11:33:21 -0600 Subject: [PATCH] Configurable speed for water flowing over lava diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 61c8b58b..ab3f59ad 100644 +index 61c8b58b1..ab3f59ad7 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -0,0 +0,0 @@ public class PaperWorldConfig { @@ -22,7 +22,7 @@ index 61c8b58b..ab3f59ad 100644 SAFE_REGEN, REGEN, DELETE, NOTHING, WARN } diff --git a/src/main/java/net/minecraft/server/BlockFluids.java b/src/main/java/net/minecraft/server/BlockFluids.java -index 6ecc1f84..637f6580 100644 +index 6ecc1f84e..637f6580b 100644 --- a/src/main/java/net/minecraft/server/BlockFluids.java +++ b/src/main/java/net/minecraft/server/BlockFluids.java @@ -0,0 +0,0 @@ public class BlockFluids extends Block implements IFluidSource { From bf52fa14d4447ae2b0610ca4a578a33069277e09 Mon Sep 17 00:00:00 2001 From: Colin Godsey Date: Wed, 8 Aug 2018 20:49:02 -0600 Subject: [PATCH 4/8] reduced down to EnumCreatureType --- .../Add-entity-count-cache.patch | 149 +++++++++++++----- ...le-speed-for-water-flowing-over-lava.patch | 65 -------- 2 files changed, 109 insertions(+), 105 deletions(-) delete mode 100644 Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch diff --git a/Spigot-Server-Patches/Add-entity-count-cache.patch b/Spigot-Server-Patches/Add-entity-count-cache.patch index 962f4d2c2d..c2ce96d0cf 100644 --- a/Spigot-Server-Patches/Add-entity-count-cache.patch +++ b/Spigot-Server-Patches/Add-entity-count-cache.patch @@ -4,10 +4,90 @@ Date: Wed, 8 Aug 2018 10:10:06 -0600 Subject: [PATCH] Add entity count cache +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index d6b56d685..3d973deb7 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati + } + // CraftBukkit end */ + ++ /* ++ * Paper - clear count cache every once in a while. ++ * Cache can never be entirely trusted because ++ * an entity may become persistent or not ++ * during its lifetime. ++ */ ++ if (this.ticks % 600 == 0) worldserver.clearEntityCountCache(); ++ + this.methodProfiler.a("tick"); + + CrashReport crashreport; +diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java +index f525fd1b4..494759a1c 100644 +--- a/src/main/java/net/minecraft/server/SpawnerCreature.java ++++ b/src/main/java/net/minecraft/server/SpawnerCreature.java +@@ -0,0 +0,0 @@ public final class SpawnerCreature { + // CraftBukkit end + + if ((!enumcreaturetype.c() || flag1) && (enumcreaturetype.c() || flag) && (!enumcreaturetype.d() || flag2)) { +- k = worldserver.a(enumcreaturetype.a()); ++ k = worldserver.getCreatureCount(enumcreaturetype); // Paper - entity count cache + int l1 = limit * i / b; // CraftBukkit - use per-world limits + + if (k <= l1) { diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 004c3ec47..c392595c0 100644 +index 004c3ec47..baf73a411 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java +@@ -0,0 +0,0 @@ + package net.minecraft.server; + +-import co.aikar.timings.Timings; + import com.destroystokyo.paper.event.server.ServerExceptionEvent; + import com.destroystokyo.paper.exception.ServerInternalException; + import com.google.common.base.MoreObjects; + import com.google.common.collect.Lists; +-import java.util.ArrayList; +-import java.util.Collection; +-import java.util.Iterator; +-import java.util.List; +-import java.util.Random; +-import java.util.UUID; ++ ++import java.util.*; + + import java.util.function.Function; + import java.util.function.Predicate; +-import java.util.function.Supplier; + import javax.annotation.Nullable; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + + // CraftBukkit start + import com.google.common.collect.Maps; +-import java.util.HashMap; // Paper +-import java.util.Map; + import org.bukkit.Bukkit; + import org.bukkit.block.BlockState; + import org.bukkit.craftbukkit.CraftServer; +@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.CraftWorld; + import org.bukkit.craftbukkit.block.CraftBlockState; + import org.bukkit.craftbukkit.block.data.CraftBlockData; + import org.bukkit.craftbukkit.event.CraftEventFactory; +-import org.bukkit.craftbukkit.util.CraftMagicNumbers; +-import org.bukkit.craftbukkit.util.LongHashSet; // Paper +-import org.bukkit.entity.Player; +-import org.bukkit.event.block.BlockCanBuildEvent; + import org.bukkit.event.block.BlockPhysicsEvent; + import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; + import org.bukkit.generator.ChunkGenerator; + // CraftBukkit end + // Paper start +-import java.util.Set; + import com.google.common.collect.Sets; + // Paper end + public abstract class World implements GeneratorAccess, IIBlockAccess, AutoCloseable { @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose // Spigot start - guard entity list from removals public final List entityList = new java.util.ArrayList() @@ -62,63 +142,41 @@ index 004c3ec47..c392595c0 100644 public final Map playersByName = Maps.newHashMap(); // Paper - World EntityHuman Lookup Optimizations public final List k = Lists.newArrayList(); protected final IntHashMap entitiesById = new IntHashMap(); -+ private Map, Integer> countCache = new HashMap(); // Paper ++ private Map countCache = new EnumMap(EnumCreatureType.class); // Paper - entity count cache private final long G = 16777215L; private int H; public int getSkylightSubtracted() { return this.H; } public void setSkylightSubtracted(int value) { this.H = value;} // Paper - OBFHELPER protected int m = (new Random()).nextInt(); @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose + } ++ public int getEntityCount(Class oclass) { return a(oclass); } // Paper - OBFHELPER public int a(Class oclass) { -+ if (true) return getEntityCount(oclass); //Paper - short circuit to cached method -+ int i = 0; Iterator iterator = this.entityList.iterator(); - @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose return i; } + // Paper start - entity count cache -+ private int countEntityType(Class oclass) { -+ int i = 0; -+ Iterator iterator = this.entityList.iterator(); ++ public int getCreatureCount(EnumCreatureType typ) { ++ Integer count = countCache.get(typ); + -+ while (iterator.hasNext()) { -+ Entity entity = (Entity) iterator.next(); ++ if (count == null) { ++ count = getEntityCount(typ.a()); + -+ if (shouldIgnoreForCount(entity)) continue; -+ if (oclass.isAssignableFrom(entity.getClass())) i++; ++ countCache.put(typ, count); + } + -+ return i; -+ } -+ -+ public int getEntityCount(Class oclass) { -+ Integer count = countCache.get(oclass); -+ -+ if (count != null) return count; -+ -+ count = countEntityType(oclass); -+ -+ countCache.put(oclass, count); -+ + return count; + } + -+ public boolean shouldIgnoreForCount(Entity entity) { -+ if (entity == null) return true; -+ -+ if (entity instanceof EntityInsentient) { -+ EntityInsentient entityinsentient = (EntityInsentient) entity; -+ return entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent(); -+ } -+ -+ return false; ++ void clearEntityCountCache() { ++ countCache.clear(); + } + -+ protected void updateEntityCount(Class clazz, boolean incr) { -+ Integer countObject = countCache.get(clazz); ++ protected void updateEntityCount(EnumCreatureType typ, boolean incr) { ++ Integer countObject = countCache.get(typ); + + if (countObject == null) return; + @@ -127,19 +185,30 @@ index 004c3ec47..c392595c0 100644 + if (incr) count++; + else count--; + -+ if(count < 0) { ++ if (count < 0) { + e.warn("Entity count cache has gone negative"); + count = 0; + } + -+ countCache.put(clazz, count); ++ countCache.put(typ, count); + } + + protected void updateEntityCount(Entity entity, boolean incr) { -+ if (shouldIgnoreForCount(entity)) return; ++ if (entity == null || !(entity instanceof IAnimal)) return; + -+ for (Class clazz = entity.getClass() ; !clazz.equals(Object.class) ; clazz = clazz.getSuperclass()) { -+ updateEntityCount(clazz, incr); ++ if (entity instanceof EntityInsentient) { ++ EntityInsentient entityinsentient = (EntityInsentient) entity; ++ if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { ++ return; ++ } ++ } ++ ++ Class clazz = entity.getClass(); ++ ++ for (EnumCreatureType typ : EnumCreatureType.values()) { ++ if (typ.a().isAssignableFrom(clazz)) { ++ updateEntityCount(typ, incr); ++ } + } + } + // Paper end diff --git a/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch b/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch deleted file mode 100644 index 4dd7ba5c1e..0000000000 --- a/Spigot-Server-Patches/Configurable-speed-for-water-flowing-over-lava.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Colin Godsey -Date: Wed, 8 Aug 2018 11:33:21 -0600 -Subject: [PATCH] Configurable speed for water flowing over lava - - -diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -index 61c8b58b1..ab3f59ad7 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java -@@ -0,0 +0,0 @@ public class PaperWorldConfig { - } - } - -+ public int waterOverLavaFlowSpeed; -+ private void waterOverLavaFlowSpeed() { -+ waterOverLavaFlowSpeed = getInt("water-over-lava-flow-speed", 5); -+ log("Water over lava flow speed: " + waterOverLavaFlowSpeed); -+ } -+ - public enum DuplicateUUIDMode { - SAFE_REGEN, REGEN, DELETE, NOTHING, WARN - } -diff --git a/src/main/java/net/minecraft/server/BlockFluids.java b/src/main/java/net/minecraft/server/BlockFluids.java -index 6ecc1f84e..637f6580b 100644 ---- a/src/main/java/net/minecraft/server/BlockFluids.java -+++ b/src/main/java/net/minecraft/server/BlockFluids.java -@@ -0,0 +0,0 @@ public class BlockFluids extends Block implements IFluidSource { - - public void onPlace(IBlockData iblockdata, World world, BlockPosition blockposition, IBlockData iblockdata1) { - if (this.a(world, blockposition, iblockdata)) { -- world.H().a(blockposition, iblockdata.s().c(), this.a((IWorldReader) world)); -+ world.H().a(blockposition, iblockdata.s().c(), this.getFlowSpeed(world, blockposition)); // Paper - } - - } -+ -+ /** -+ * Paper - Get flow speed. Throttle if its water and flowing adjacent to lava -+ */ -+ public int getFlowSpeed(World world, BlockPosition blockposition) { -+ if (this.material == Material.WATER && ( -+ world.getType(blockposition.north(1)).getBlock().material == Material.LAVA || -+ world.getType(blockposition.south(1)).getBlock().material == Material.LAVA || -+ world.getType(blockposition.west(1)).getBlock().material == Material.LAVA || -+ world.getType(blockposition.east(1)).getBlock().material == Material.LAVA)) { -+ return world.paperConfig.waterOverLavaFlowSpeed; -+ } -+ return this.a(world); -+ } - - public IBlockData updateState(IBlockData iblockdata, EnumDirection enumdirection, IBlockData iblockdata1, GeneratorAccess generatoraccess, BlockPosition blockposition, BlockPosition blockposition1) { - if (iblockdata.s().d() || iblockdata1.s().d()) { -@@ -0,0 +0,0 @@ public class BlockFluids extends Block implements IFluidSource { - - public void doPhysics(IBlockData iblockdata, World world, BlockPosition blockposition, Block block, BlockPosition blockposition1) { - if (this.a(world, blockposition, iblockdata)) { -- world.H().a(blockposition, iblockdata.s().c(), this.a((IWorldReader) world)); -+ world.H().a(blockposition, iblockdata.s().c(), this.getFlowSpeed(world, blockposition)); // Paper - } - - } --- -2.15.2 (Apple Git-101.1) - From 0cb2135823464740ea6371f34d2c6786f3eeeabf Mon Sep 17 00:00:00 2001 From: Colin Godsey Date: Thu, 9 Aug 2018 06:35:13 -0600 Subject: [PATCH 5/8] clean up, pr fixes --- .../Add-entity-count-cache.patch | 159 ++++++------------ 1 file changed, 55 insertions(+), 104 deletions(-) diff --git a/Spigot-Server-Patches/Add-entity-count-cache.patch b/Spigot-Server-Patches/Add-entity-count-cache.patch index c2ce96d0cf..ee1854e4af 100644 --- a/Spigot-Server-Patches/Add-entity-count-cache.patch +++ b/Spigot-Server-Patches/Add-entity-count-cache.patch @@ -4,25 +4,40 @@ Date: Wed, 8 Aug 2018 10:10:06 -0600 Subject: [PATCH] Add entity count cache -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index d6b56d685..3d973deb7 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -0,0 +0,0 @@ public abstract class MinecraftServer implements IAsyncTaskHandler, IMojangStati - } - // CraftBukkit end */ +diff --git a/src/main/java/net/minecraft/server/EntityInsentient.java b/src/main/java/net/minecraft/server/EntityInsentient.java +index 7b64ec27c..55606756e 100644 +--- a/src/main/java/net/minecraft/server/EntityInsentient.java ++++ b/src/main/java/net/minecraft/server/EntityInsentient.java +@@ -0,0 +0,0 @@ public abstract class EntityInsentient extends EntityLiving { + public float[] dropChanceArmor; + // public boolean canPickUpLoot; // CraftBukkit - moved up to EntityLiving + public boolean persistent; ++ public boolean countsAgainstSpawnLimit = true; // Paper + private final Map bH; + private MinecraftKey bI; + private long bJ; +diff --git a/src/main/java/net/minecraft/server/EnumCreatureType.java b/src/main/java/net/minecraft/server/EnumCreatureType.java +index 79e52f7ba..288f59ed3 100644 +--- a/src/main/java/net/minecraft/server/EnumCreatureType.java ++++ b/src/main/java/net/minecraft/server/EnumCreatureType.java +@@ -0,0 +0,0 @@ public enum EnumCreatureType { + this.h = flag1; + } -+ /* -+ * Paper - clear count cache every once in a while. -+ * Cache can never be entirely trusted because -+ * an entity may become persistent or not -+ * during its lifetime. -+ */ -+ if (this.ticks % 600 == 0) worldserver.clearEntityCountCache(); ++ public Class innerClass() { return this.a(); } // Paper - OBFHELPER + public Class a() { + return this.e; + } + ++ // Paper start ++ public boolean matches(Entity entity) { ++ return innerClass().isAssignableFrom(entity.getClass()); ++ } ++ // Paper end + - this.methodProfiler.a("tick"); - - CrashReport crashreport; + public int b() { + return this.f; + } diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java index f525fd1b4..494759a1c 100644 --- a/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -37,57 +52,17 @@ index f525fd1b4..494759a1c 100644 if (k <= l1) { diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 004c3ec47..baf73a411 100644 +index 004c3ec47..dc301c6f4 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java -@@ -0,0 +0,0 @@ - package net.minecraft.server; - --import co.aikar.timings.Timings; - import com.destroystokyo.paper.event.server.ServerExceptionEvent; - import com.destroystokyo.paper.exception.ServerInternalException; - import com.google.common.base.MoreObjects; - import com.google.common.collect.Lists; --import java.util.ArrayList; --import java.util.Collection; --import java.util.Iterator; --import java.util.List; --import java.util.Random; --import java.util.UUID; -+ -+import java.util.*; +@@ -0,0 +0,0 @@ import java.util.Iterator; + import java.util.List; + import java.util.Random; + import java.util.UUID; ++import java.util.EnumMap; // Paper import java.util.function.Function; import java.util.function.Predicate; --import java.util.function.Supplier; - import javax.annotation.Nullable; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - - // CraftBukkit start - import com.google.common.collect.Maps; --import java.util.HashMap; // Paper --import java.util.Map; - import org.bukkit.Bukkit; - import org.bukkit.block.BlockState; - import org.bukkit.craftbukkit.CraftServer; -@@ -0,0 +0,0 @@ import org.bukkit.craftbukkit.CraftWorld; - import org.bukkit.craftbukkit.block.CraftBlockState; - import org.bukkit.craftbukkit.block.data.CraftBlockData; - import org.bukkit.craftbukkit.event.CraftEventFactory; --import org.bukkit.craftbukkit.util.CraftMagicNumbers; --import org.bukkit.craftbukkit.util.LongHashSet; // Paper --import org.bukkit.entity.Player; --import org.bukkit.event.block.BlockCanBuildEvent; - import org.bukkit.event.block.BlockPhysicsEvent; - import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; - import org.bukkit.generator.ChunkGenerator; - // CraftBukkit end - // Paper start --import java.util.Set; - import com.google.common.collect.Sets; - // Paper end - public abstract class World implements GeneratorAccess, IIBlockAccess, AutoCloseable { @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose // Spigot start - guard entity list from removals public final List entityList = new java.util.ArrayList() @@ -138,59 +113,33 @@ index 004c3ec47..baf73a411 100644 return super.remove( o ); } -@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose - public final Map playersByName = Maps.newHashMap(); // Paper - World EntityHuman Lookup Optimizations - public final List k = Lists.newArrayList(); - protected final IntHashMap entitiesById = new IntHashMap(); -+ private Map countCache = new EnumMap(EnumCreatureType.class); // Paper - entity count cache - private final long G = 16777215L; - private int H; public int getSkylightSubtracted() { return this.H; } public void setSkylightSubtracted(int value) { this.H = value;} // Paper - OBFHELPER - protected int m = (new Random()).nextInt(); -@@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose - - } - -+ public int getEntityCount(Class oclass) { return a(oclass); } // Paper - OBFHELPER - public int a(Class oclass) { - int i = 0; - Iterator iterator = this.entityList.iterator(); @@ -0,0 +0,0 @@ public abstract class World implements GeneratorAccess, IIBlockAccess, AutoClose return i; } + // Paper start - entity count cache -+ public int getCreatureCount(EnumCreatureType typ) { -+ Integer count = countCache.get(typ); ++ private Map countCache = new EnumMap(EnumCreatureType.class); + -+ if (count == null) { -+ count = getEntityCount(typ.a()); ++ public int getCreatureCount(EnumCreatureType type) { ++ Integer count = countCache.get(type); + -+ countCache.put(typ, count); -+ } -+ -+ return count; ++ return count == null ? 0 : count; + } + -+ void clearEntityCountCache() { -+ countCache.clear(); -+ } ++ protected void updateEntityCount(EnumCreatureType type, boolean incr) { ++ Integer countObject = countCache.get(type); + -+ protected void updateEntityCount(EnumCreatureType typ, boolean incr) { -+ Integer countObject = countCache.get(typ); -+ -+ if (countObject == null) return; -+ -+ int count = countObject; ++ int count = countObject == null ? 0 : countObject; + + if (incr) count++; + else count--; + + if (count < 0) { -+ e.warn("Entity count cache has gone negative"); ++ e.warn("Paper - Entity count cache has gone negative"); + count = 0; + } + -+ countCache.put(typ, count); ++ countCache.put(type, count); + } + + protected void updateEntityCount(Entity entity, boolean incr) { @@ -198,16 +147,18 @@ index 004c3ec47..baf73a411 100644 + + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; -+ if (entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { ++ if (incr && entityinsentient.isTypeNotPersistent() && entityinsentient.isPersistent()) { ++ entityinsentient.countsAgainstSpawnLimit = false; ++ ++ return; ++ } else if (!incr && !entityinsentient.countsAgainstSpawnLimit) { + return; + } + } + -+ Class clazz = entity.getClass(); -+ -+ for (EnumCreatureType typ : EnumCreatureType.values()) { -+ if (typ.a().isAssignableFrom(clazz)) { -+ updateEntityCount(typ, incr); ++ for (EnumCreatureType type : EnumCreatureType.values()) { ++ if (type.matches(entity)) { ++ updateEntityCount(type, incr); + } + } + } From 67fb7e9f66f20bf7a3a3f033fe92bba3968bd27d Mon Sep 17 00:00:00 2001 From: Colin Godsey Date: Wed, 15 Aug 2018 15:07:30 -0600 Subject: [PATCH 8/8] pr changes, flat array --- Spigot-Server-Patches/Add-entity-count-cache.patch | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Spigot-Server-Patches/Add-entity-count-cache.patch b/Spigot-Server-Patches/Add-entity-count-cache.patch index ee1854e4af..e41589d0ce 100644 --- a/Spigot-Server-Patches/Add-entity-count-cache.patch +++ b/Spigot-Server-Patches/Add-entity-count-cache.patch @@ -52,7 +52,7 @@ index f525fd1b4..494759a1c 100644 if (k <= l1) { diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java -index 004c3ec47..dc301c6f4 100644 +index 004c3ec47..e2d591f8f 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -0,0 +0,0 @@ import java.util.Iterator; @@ -118,18 +118,14 @@ index 004c3ec47..dc301c6f4 100644 } + // Paper start - entity count cache -+ private Map countCache = new EnumMap(EnumCreatureType.class); ++ private final int[] countCache = new int[EnumCreatureType.values().length]; + + public int getCreatureCount(EnumCreatureType type) { -+ Integer count = countCache.get(type); -+ -+ return count == null ? 0 : count; ++ return countCache[type.ordinal()]; + } + + protected void updateEntityCount(EnumCreatureType type, boolean incr) { -+ Integer countObject = countCache.get(type); -+ -+ int count = countObject == null ? 0 : countObject; ++ int count = countCache[type.ordinal()]; + + if (incr) count++; + else count--; @@ -139,7 +135,7 @@ index 004c3ec47..dc301c6f4 100644 + count = 0; + } + -+ countCache.put(type, count); ++ countCache[type.ordinal()] = count; + } + + protected void updateEntityCount(Entity entity, boolean incr) {