aboutsummaryrefslogtreecommitdiffhomepage
path: root/Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch
diff options
context:
space:
mode:
authorvemacs <[email protected]>2015-09-12 23:29:23 -0500
committerZach Brown <[email protected]>2015-09-14 20:37:51 -0500
commit502ffa083300ab6645f9f16143ab2bfc9732db89 (patch)
treecbc1d123c1827a4fde7e365834a4fc9cf3c50ea3 /Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch
parentf243a4024d13787f151e11a1fed326ae1aaf2219 (diff)
downloadPaper-502ffa083300ab6645f9f16143ab2bfc9732db89.tar.gz
Paper-502ffa083300ab6645f9f16143ab2bfc9732db89.zip
Re-add entity/tile entity tick limiters
Diffstat (limited to 'Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch')
-rw-r--r--Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch351
1 files changed, 351 insertions, 0 deletions
diff --git a/Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch b/Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch
new file mode 100644
index 0000000000..5b4599dfc4
--- /dev/null
+++ b/Spigot-Server-Patches/0022-Optimize-TileEntity-Ticking.patch
@@ -0,0 +1,351 @@
+From aa2e76930579e08f02deb52ab784371c7bad93fa Mon Sep 17 00:00:00 2001
+From: Aikar <[email protected]>
+Date: Sun, 8 Mar 2015 01:56:22 -0600
+Subject: [PATCH] Optimize TileEntity Ticking
+
+
+diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
+index c268a40..1971941 100644
+--- a/src/main/java/net/minecraft/server/TileEntity.java
++++ b/src/main/java/net/minecraft/server/TileEntity.java
+@@ -21,6 +21,12 @@ public abstract class TileEntity {
+ private int h;
+ protected Block e;
+
++ // PaperSpigot start - Optimized TileEntity tick changes
++ private static int tileEntityCounter = 0;
++ public boolean isAdded = false;
++ public int tileId = tileEntityCounter++;
++ // PaperSpigot end
++
+ public TileEntity() {
+ this.position = BlockPosition.ZERO;
+ this.h = -1;
+diff --git a/src/main/java/net/minecraft/server/TileEntityBeacon.java b/src/main/java/net/minecraft/server/TileEntityBeacon.java
+index 4f280dd..3ea1b62 100644
+--- a/src/main/java/net/minecraft/server/TileEntityBeacon.java
++++ b/src/main/java/net/minecraft/server/TileEntityBeacon.java
+@@ -48,7 +48,7 @@ public class TileEntityBeacon extends TileEntityContainer implements IUpdatePlay
+ public TileEntityBeacon() {}
+
+ public void c() {
+- if (this.world.getTime() % 80L == 0L) {
++ if (true || this.world.getTime() % 80L == 0L) { // PaperSpigot - Controlled by improved tick handling
+ this.m();
+ }
+
+diff --git a/src/main/java/net/minecraft/server/TileEntityChest.java b/src/main/java/net/minecraft/server/TileEntityChest.java
+index 5eb55e5..b31973a 100644
+--- a/src/main/java/net/minecraft/server/TileEntityChest.java
++++ b/src/main/java/net/minecraft/server/TileEntityChest.java
+@@ -246,7 +246,7 @@ public class TileEntityChest extends TileEntityContainer implements IUpdatePlaye
+ ++this.n;
+ float f;
+
+- if (!this.world.isClientSide && this.l != 0 && (this.n + i + j + k) % 200 == 0) {
++ if (!this.world.isClientSide && this.l != 0 && (this.n + i + j + k) % 10 == 0) { // PaperSpigot - Reduced 200 -> 10 due to reduced interval from improved tick handling
+ this.l = 0;
+ f = 5.0F;
+ List list = this.world.a(EntityHuman.class, new AxisAlignedBB((double) ((float) i - f), (double) ((float) j - f), (double) ((float) k - f), (double) ((float) (i + 1) + f), (double) ((float) (j + 1) + f), (double) ((float) (k + 1) + f)));
+diff --git a/src/main/java/net/minecraft/server/TileEntityEnderChest.java b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
+index 794cdc8..f712885 100644
+--- a/src/main/java/net/minecraft/server/TileEntityEnderChest.java
++++ b/src/main/java/net/minecraft/server/TileEntityEnderChest.java
+@@ -10,7 +10,7 @@ public class TileEntityEnderChest extends TileEntity implements IUpdatePlayerLis
+ public TileEntityEnderChest() {}
+
+ public void c() {
+- if (++this.h % 20 * 4 == 0) {
++ if (++this.h % 4 == 0) { // PaperSpigot - Reduced (20 * 4) -> 4 interval due to reduced tick rate from improved tick handling
+ this.world.playBlockAction(this.position, Blocks.ENDER_CHEST, 1, this.g);
+ }
+
+diff --git a/src/main/java/net/minecraft/server/TileEntityLightDetector.java b/src/main/java/net/minecraft/server/TileEntityLightDetector.java
+index f75e2de..7119612 100644
+--- a/src/main/java/net/minecraft/server/TileEntityLightDetector.java
++++ b/src/main/java/net/minecraft/server/TileEntityLightDetector.java
+@@ -5,7 +5,7 @@ public class TileEntityLightDetector extends TileEntity implements IUpdatePlayer
+ public TileEntityLightDetector() {}
+
+ public void c() {
+- if (this.world != null && !this.world.isClientSide && this.world.getTime() % 20L == 0L) {
++ if (this.world != null && !this.world.isClientSide /*&& this.world.getTime() % 20L == 0L*/) { // PaperSpigot - interval controlled by improved tick handling
+ this.e = this.w();
+ if (this.e instanceof BlockDaylightDetector) {
+ ((BlockDaylightDetector) this.e).f(this.world, this.position);
+diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
+index 641db2a..22237c9 100644
+--- a/src/main/java/net/minecraft/server/World.java
++++ b/src/main/java/net/minecraft/server/World.java
+@@ -28,6 +28,19 @@ public abstract class World implements IBlockAccess {
+ // Spigot start - guard entity list from removals
+ public final List<Entity> entityList = new java.util.ArrayList<Entity>()
+ {
++ // PaperSpigot start - move always activated entities to top of tick list
++ @Override
++ public boolean add(Entity e)
++ {
++ if (e.defaultActivationState) {
++ super.add(0, e);
++ return true;
++ } else {
++ return super.add(e);
++ }
++ }
++ // PaperSpigot end
++
+ @Override
+ public Entity remove(int index)
+ {
+@@ -53,7 +66,7 @@ public abstract class World implements IBlockAccess {
+ // Spigot end
+ protected final List<Entity> g = Lists.newArrayList();
+ public final List<TileEntity> h = Lists.newArrayList();
+- public final List<TileEntity> tileEntityList = Lists.newArrayList();
++ public final Set<TileEntity> tileEntityList = new org.github.paperspigot.WorldTileEntityList(this); // PaperSpigot
+ private final List<TileEntity> b = Lists.newArrayList();
+ private final List<TileEntity> c = Lists.newArrayList();
+ public final List<EntityHuman> players = Lists.newArrayList();
+@@ -219,7 +232,7 @@ public abstract class World implements IBlockAccess {
+ this.getServer().addWorld(this.world);
+ // CraftBukkit end
+ this.keepSpawnInMemory = this.paperSpigotConfig.keepSpawnInMemory; // PaperSpigot
+- timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
++ timings = new SpigotTimings.WorldTimingsHandler(this); // Spigot - code below can generate new world and access timings
+ this.entityLimiter = new org.spigotmc.TickLimiter(spigotConfig.entityMaxTickTime);
+ this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime);
+ }
+@@ -1394,9 +1407,21 @@ public abstract class World implements IBlockAccess {
+ guardEntityList = true; // Spigot
+ // CraftBukkit start - Use field for loop variable
+ int entitiesThisCycle = 0;
++
++ // PaperSpigot start - Compute minimum tick index
++ int minTickIndex = -1;
++ ListIterator<Entity> e = entityList.listIterator();
++ while (e.hasNext()) {
++ if (!e.next().defaultActivationState) {
++ minTickIndex = e.previousIndex();
++ break;
++ }
++ }
++ // PaperSpigot end
++
+ if (tickPosition < 0) tickPosition = 0;
+ for (entityLimiter.initTick();
+- entitiesThisCycle < entityList.size() && (entitiesThisCycle % 10 == 0 || entityLimiter.shouldContinue());
++ entitiesThisCycle < entityList.size() && (tickPosition <= minTickIndex || entitiesThisCycle % 10 == 0 || entityLimiter.shouldContinue()); // PaperSpigot
+ tickPosition++, entitiesThisCycle++) {
+ tickPosition = (tickPosition < entityList.size()) ? tickPosition : 0;
+ entity = (Entity) this.entityList.get(this.tickPosition);
+@@ -1454,19 +1479,13 @@ public abstract class World implements IBlockAccess {
+ this.c.clear();
+ }
+ // CraftBukkit end
++ Iterator iterator = this.tileEntityList.iterator();
+
+- // Spigot start
+- int tilesThisCycle = 0;
+- for (tileLimiter.initTick();
+- tilesThisCycle < tileEntityList.size() && (tilesThisCycle % 10 == 0 || tileLimiter.shouldContinue());
+- tileTickPosition++, tilesThisCycle++) {
+- tileTickPosition = (tileTickPosition < tileEntityList.size()) ? tileTickPosition : 0;
+- TileEntity tileentity = (TileEntity) this.tileEntityList.get(tileTickPosition);
+- // Spigot start
++ while (iterator.hasNext()) {
++ TileEntity tileentity = (TileEntity) iterator.next();
+ if (tileentity == null) {
+ getServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash");
+- tilesThisCycle--;
+- this.tileEntityList.remove(tileTickPosition--);
++ iterator.remove();
+ continue;
+ }
+ // Spigot end
+@@ -1494,8 +1513,7 @@ public abstract class World implements IBlockAccess {
+ }
+
+ if (tileentity.x()) {
+- tilesThisCycle--;
+- this.tileEntityList.remove(tileTickPosition--);
++ iterator.remove();
+ this.h.remove(tileentity);
+ if (this.isLoaded(tileentity.getPosition())) {
+ this.getChunkAtWorldCoords(tileentity.getPosition()).e(tileentity.getPosition());
+diff --git a/src/main/java/org/github/paperspigot/WorldTileEntityList.java b/src/main/java/org/github/paperspigot/WorldTileEntityList.java
+new file mode 100644
+index 0000000..66b6af0
+--- /dev/null
++++ b/src/main/java/org/github/paperspigot/WorldTileEntityList.java
+@@ -0,0 +1,168 @@
++package org.github.paperspigot;
++
++import com.google.common.collect.ArrayListMultimap;
++import com.google.common.collect.Maps;
++import com.google.common.collect.Multimap;
++import net.minecraft.server.*;
++import gnu.trove.map.hash.TObjectIntHashMap;
++
++import java.util.Collection;
++import java.util.HashSet;
++import java.util.Iterator;
++import java.util.Map;
++
++public class WorldTileEntityList extends HashSet<TileEntity> {
++ private static final TObjectIntHashMap<Class<? extends TileEntity>> tileEntityTickIntervals =
++ new TObjectIntHashMap<Class<? extends TileEntity>>() {{
++ // Use -1 for no ticking
++ // These TE's have empty tick methods, doing nothing. Never bother ticking them.
++ for (Class<? extends TileEntity> ignored : new Class[]{
++ BlockJukeBox.TileEntityRecordPlayer.class,
++ TileEntityDispenser.class,
++ TileEntityDropper.class,
++ TileEntitySign.class,
++ TileEntityNote.class,
++ TileEntityEnderPortal.class,
++ TileEntityCommand.class,
++ TileEntitySkull.class,
++ TileEntityComparator.class,
++ TileEntityFlowerPot.class
++ }) {
++ put(ignored, -1);
++ }
++
++ // does findPlayer lookup, so this helps performance to slow down
++ put(TileEntityEnchantTable.class, 20);
++
++ // Vanilla controlled values - These are checks already done in vanilla, so don't tick on ticks we know
++ // won't do anything anyways
++ put(TileEntityBeacon.class, 80);
++ put(TileEntityLightDetector.class, 20);
++ }};
++
++ private static int getInterval(Class<? extends TileEntity> cls) {
++ int tickInterval = tileEntityTickIntervals.get(cls);
++ return tickInterval != 0 ? tickInterval : 1;
++ }
++
++ private static int getBucketId(TileEntity entity, Integer interval) {
++ return entity.tileId % interval;
++ }
++
++ private final Map<Integer, Multimap<Integer, TileEntity>> tickList = Maps.newHashMap();
++ private final WorldServer world;
++
++ public WorldTileEntityList(World world) {
++ this.world = (WorldServer) world;
++ }
++
++
++ private Multimap<Integer, TileEntity> getBucket(int interval) {
++ Multimap<Integer, TileEntity> intervalBucket = tickList.get(interval);
++ if (intervalBucket == null) {
++ intervalBucket = ArrayListMultimap.create();
++ tickList.put(interval, intervalBucket);
++ }
++ return intervalBucket;
++ }
++
++ /**
++ * Adds the TileEntity to the tick list only if it is expected to tick
++ */
++ @Override
++ public boolean add(TileEntity entity) {
++ if (entity.isAdded) {
++ return false;
++ }
++
++ int interval = getInterval(entity.getClass());
++ if (interval > 0) {
++ entity.isAdded = true;
++ int bucket = getBucketId(entity, interval);
++ Multimap<Integer, TileEntity> typeBucket = getBucket(interval);
++ return typeBucket.put(bucket, entity);
++ }
++ return false;
++ }
++
++ @Override
++ public boolean remove(Object o) {
++ if (!(o instanceof TileEntity)) {
++ return false;
++ }
++ TileEntity entity = (TileEntity) o;
++ if (!entity.isAdded) {
++ return false;
++ }
++ entity.isAdded = false;
++ int interval = getInterval(entity.getClass());
++ int bucket = getBucketId(entity, interval);
++ Multimap<Integer, TileEntity> typeBucket = getBucket(interval);
++ return typeBucket.remove(bucket, entity);
++ }
++
++ @Override
++ public Iterator iterator() {
++ return new WorldTileEntityIterator();
++ }
++
++ @Override
++ public boolean contains(Object o) {
++ return o instanceof TileEntity && ((TileEntity) o).isAdded;
++ }
++
++ private class WorldTileEntityIterator implements Iterator<TileEntity> {
++ private final Iterator<Map.Entry<Integer, Multimap<Integer, TileEntity>>> intervalIterator;
++ private Map.Entry<Integer, Multimap<Integer, TileEntity>> intervalMap = null;
++ private Iterator<TileEntity> listIterator = null;
++
++ protected WorldTileEntityIterator() {
++ intervalIterator = tickList.entrySet().iterator();
++ nextInterval();
++ }
++
++ private boolean nextInterval() {
++ listIterator = null;
++ if (intervalIterator.hasNext()) {
++ intervalMap = intervalIterator.next();
++
++ final Integer interval = intervalMap.getKey();
++ final Multimap<Integer, TileEntity> buckets = intervalMap.getValue();
++
++ int bucket = (int) (world.getTime() % interval);
++
++ if (!buckets.isEmpty() && buckets.containsKey(bucket)) {
++ final Collection<TileEntity> tileList = buckets.get(bucket);
++
++ if (tileList != null && !tileList.isEmpty()) {
++ listIterator = tileList.iterator();
++ return true;
++ }
++ }
++ }
++
++ return false;
++
++ }
++
++ @Override
++ public boolean hasNext() {
++ do {
++ if (listIterator != null && listIterator.hasNext()) {
++ return true;
++ }
++ } while (nextInterval());
++ return false;
++ }
++
++ @Override
++ public TileEntity next() {
++ return listIterator.next();
++ }
++
++ @Override
++ public void remove() {
++ listIterator.remove();
++ }
++ }
++}
+--
+2.5.2
+