345 lines
15 KiB
Diff
345 lines
15 KiB
Diff
From a54f2fe608b2d5ccbc117dec28be3531eda48ca5 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Fri, 28 Nov 2014 04:14:14 -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 7cf38ea..76cdc7e 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntity.java
|
|
@@ -56,6 +56,12 @@ public abstract class TileEntity {
|
|
}
|
|
// Spigot end
|
|
|
|
+ // 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 6bfde41..35d82ab 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 7444f4f..0f29365 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.isStatic && this.l != 0 && (this.n + i + j + k) % 200 == 0) {
|
|
+ if (!this.world.isStatic && this.l != 0 && (this.n + i + j + k) % 10 == 0) { // PaperSpigot Reduced 200 -> 10 interval due to reduced tick rate 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..218b801 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 7b6f8ae..c6b593f 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.isStatic && this.world.getTime() % 20L == 0L) {
|
|
+ if (this.world != null && !this.world.isStatic /*&& this.world.getTime() % 20L == 0L*/) { // PaperSpigot - interval controlled by Improved Tick Handling
|
|
this.e = this.w();
|
|
if (this.e instanceof BlockDaylightDetector) {
|
|
((BlockDaylightDetector) this.e).d(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 26f4d96..7730e2c 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -3,13 +3,7 @@ package net.minecraft.server;
|
|
import com.google.common.base.Predicate;
|
|
import com.google.common.collect.Lists;
|
|
|
|
-import java.util.ArrayList;
|
|
-import java.util.Calendar;
|
|
-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.concurrent.Callable;
|
|
|
|
// CraftBukkit start
|
|
@@ -59,7 +53,7 @@ public abstract class World implements IBlockAccess {
|
|
// Spigot end
|
|
protected final List g = Lists.newArrayList();
|
|
public final List h = Lists.newArrayList();
|
|
- public final List tileEntityList = Lists.newArrayList();
|
|
+ public final Set tileEntityList = new org.github.paperspigot.WorldTileEntityList(this); // PaperSpigot
|
|
private final List a = Lists.newArrayList();
|
|
private final List b = Lists.newArrayList();
|
|
public final List players = Lists.newArrayList();
|
|
@@ -133,8 +127,8 @@ public abstract class World implements IBlockAccess {
|
|
public static String blockLocation;
|
|
public List<TileEntity> triggerHoppersList = new ArrayList<TileEntity>(); // Spigot, When altHopperTicking, tile entities being added go through here.
|
|
private org.spigotmc.TickLimiter entityLimiter;
|
|
- private org.spigotmc.TickLimiter tileLimiter;
|
|
- private int tileTickPosition;
|
|
+ //private org.spigotmc.TickLimiter tileLimiter; // PaperSpigot - Disable Spigot's TE handling in favor of our own
|
|
+ //private int tileTickPosition; // PaperSpigot - Disable Spigot's TE handling in favor of our own
|
|
|
|
public static long chunkToKey(int x, int z)
|
|
{
|
|
@@ -240,7 +234,7 @@ public abstract class World implements IBlockAccess {
|
|
this.getServer().addWorld(this.world); // CraftBukkit
|
|
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);
|
|
+ //this.tileLimiter = new org.spigotmc.TickLimiter(spigotConfig.tileMaxTickTime); // PaperSpigot - Disable Spigot's TE handling in favor of our own
|
|
}
|
|
|
|
public World b() {
|
|
@@ -1462,7 +1456,12 @@ public abstract class World implements IBlockAccess {
|
|
// CraftBukkit end
|
|
|
|
this.initializeHoppers(); // Spigot - Initializes hoppers which have been added recently.
|
|
+ // PaperSpigot Start - Return to previous behavior, theoretically tile entity ticks should no longer be long enough for this to be an issue
|
|
+ Iterator iterator = this.tileEntityList.iterator();
|
|
|
|
+ while (iterator.hasNext()) {
|
|
+ TileEntity tileentity = (TileEntity) iterator.next();
|
|
+ /*
|
|
// Spigot start
|
|
int tilesThisCycle = 0;
|
|
for (tileLimiter.initTick();
|
|
@@ -1470,10 +1469,12 @@ public abstract class World implements IBlockAccess {
|
|
tileTickPosition++, tilesThisCycle++) {
|
|
tileTickPosition = (tileTickPosition < tileEntityList.size()) ? tileTickPosition : 0;
|
|
TileEntity tileentity = (TileEntity) this.tileEntityList.get(tileTickPosition);
|
|
+ */
|
|
+ // PaperSpigot end
|
|
// Spigot start
|
|
if (tileentity == null) {
|
|
getServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash");
|
|
- this.tileEntityList.remove(tileTickPosition--);
|
|
+ iterator.remove(); // PaperSpigot - Remove Spigot's TE handling in favor of our own
|
|
continue;
|
|
}
|
|
// Spigot end
|
|
@@ -1501,7 +1502,7 @@ public abstract class World implements IBlockAccess {
|
|
}
|
|
|
|
if (tileentity.x()) {
|
|
- this.tileEntityList.remove(tileTickPosition--);
|
|
+ iterator.remove(); // PaperSpigot - Remove Spigot's TE handling in favor of our own
|
|
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..1a53e94
|
|
--- /dev/null
|
|
+++ b/src/main/java/org/github/paperspigot/WorldTileEntityList.java
|
|
@@ -0,0 +1,175 @@
|
|
+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[]{
|
|
+ TileEntityChest.class, // PaperSpigot - Don't tick chests either
|
|
+ TileEntityEnderChest.class, // PaperSpigot - Don't tick chests either
|
|
+ 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);
|
|
+
|
|
+ // Slow things down that players won't notice due to craftbukkit "wall time" patches.
|
|
+ // These need to be investigated further before they can be safely used here
|
|
+ //put(TileEntityFurnace.class, 20);
|
|
+ //put(TileEntityBrewingStand.class, 10);
|
|
+
|
|
+ // 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();
|
|
+ }
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
--
|
|
1.9.5.msysgit.0
|
|
|