Paper/CraftBukkit-Patches/0146-Alternative-Hopper-Ticking.patch

480 lines
20 KiB
Diff
Raw Normal View History

From e8b30c53ce2cd6e2be450d6d03f8977c79bcc231 Mon Sep 17 00:00:00 2001
From: "Evan A. Haskell" <eah2119@gmail.com>
Date: Sat, 19 Apr 2014 16:58:26 -0400
Subject: [PATCH] Alternative Hopper Ticking
diff --git a/src/main/java/net/minecraft/server/BlockHopper.java b/src/main/java/net/minecraft/server/BlockHopper.java
index 9e64702..36682df 100644
--- a/src/main/java/net/minecraft/server/BlockHopper.java
+++ b/src/main/java/net/minecraft/server/BlockHopper.java
@@ -87,6 +87,14 @@ public class BlockHopper extends BlockContainer {
if (flag != flag1) {
world.setData(i, j, k, i1 | (flag ? 0 : 8), 4);
+ // Spigot start - When this hopper becomes unpowered, make it active.
+ if (world.spigotConfig.altHopperTicking) {
+ TileEntityHopper hopper = e((IBlockAccess) world, i, j, k);
+ if (flag && hopper != null) {
+ hopper.makeTick();
+ }
+ }
+ // Spigot end
}
}
@@ -163,4 +171,16 @@ public class BlockHopper extends BlockContainer {
public static TileEntityHopper e(IBlockAccess iblockaccess, int i, int j, int k) {
return (TileEntityHopper) iblockaccess.getTileEntity(i, j, k);
}
+
+ // Spigot start - Use random block updates to make hoppers active.
+ @Override
+ public void a(World world, int i, int j, int k, Random random) {
+ if (world.spigotConfig.altHopperTicking) {
+ TileEntityHopper hopper = e((IBlockAccess) world, i, j, k);
+ if (hopper != null) {
+ hopper.makeTick();
+ }
+ }
+ }
+ // Spigot end
}
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
index 364df1d..5771fbd 100644
--- a/src/main/java/net/minecraft/server/Chunk.java
+++ b/src/main/java/net/minecraft/server/Chunk.java
@@ -722,6 +722,11 @@ public class Chunk {
tileentity.t();
this.tileEntities.put(chunkposition, tileentity);
+ // Spigot start - We have a world, now we can be sure hoppers are born ticking.
+ if (this.world.spigotConfig.altHopperTicking) {
+ this.world.triggerHoppersList.add(tileentity);
+ }
+ // Spigot end
// CraftBukkit start
} else {
System.out.println("Attempted to place a tile entity (" + tileentity + ") at " + tileentity.x + "," + tileentity.y + "," + tileentity.z
diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java
index 5eb893f..f9e16ac 100644
--- a/src/main/java/net/minecraft/server/EntityItem.java
+++ b/src/main/java/net/minecraft/server/EntityItem.java
@@ -102,6 +102,26 @@ public class EntityItem extends Entity {
if (this.onGround) {
this.motY *= -0.5D;
}
+ // Spigot start - Make the hopper below this item active.
+ if (this.world.spigotConfig.altHopperTicking) {
+ int xi = MathHelper.floor(this.boundingBox.a);
+ int yi = MathHelper.floor(this.boundingBox.b) - 1;
+ int zi = MathHelper.floor(this.boundingBox.c);
+ int xf = MathHelper.floor(this.boundingBox.d);
+ int yf = MathHelper.floor(this.boundingBox.e) - 1;
+ int zf = MathHelper.floor(this.boundingBox.f);
+ for (int a = xi; a <= xf; a++) {
+ for (int c = zi; c <= zf; c++) {
+ for (int b = yi; b <= yf; b++) {
+ TileEntity tileEntity = this.world.getTileEntity(a, b, c);
+ if (tileEntity instanceof TileEntityHopper) {
+ ((TileEntityHopper) tileEntity).makeTick();
+ }
+ }
+ }
+ }
+ }
+ // Spigot end
// ++this.age; // CraftBukkit - Moved up
if (!this.world.isStatic && this.age >= world.spigotConfig.itemDespawnRate) { // Spigot
diff --git a/src/main/java/net/minecraft/server/EntityMinecartAbstract.java b/src/main/java/net/minecraft/server/EntityMinecartAbstract.java
index 166206c..1305526 100644
--- a/src/main/java/net/minecraft/server/EntityMinecartAbstract.java
+++ b/src/main/java/net/minecraft/server/EntityMinecartAbstract.java
@@ -342,6 +342,26 @@ public abstract class EntityMinecartAbstract extends Entity {
this.passenger = null;
}
+ // Spigot start - Make hoppers adjacent to this container minecart active.
+ if (this.world.spigotConfig.altHopperTicking && this instanceof EntityMinecartContainer) {
+ int xi = MathHelper.floor(this.boundingBox.a) - 1;
+ int yi = MathHelper.floor(this.boundingBox.b) - 1;
+ int zi = MathHelper.floor(this.boundingBox.c) - 1;
+ int xf = MathHelper.floor(this.boundingBox.d) + 1;
+ int yf = MathHelper.floor(this.boundingBox.e) + 1;
+ int zf = MathHelper.floor(this.boundingBox.f) + 1;
+ for (int a = xi; a <= xf; a++) {
+ for (int b = yi; b <= yf; b++) {
+ for (int c = zi; c <= zf; c++) {
+ TileEntity tileEntity = this.world.getTileEntity(a, b, c);
+ if (tileEntity instanceof TileEntityHopper) {
+ ((TileEntityHopper) tileEntity).makeTick();
+ }
+ }
+ }
+ }
+ }
+ // Spigot end
}
}
diff --git a/src/main/java/net/minecraft/server/EntityOcelot.java b/src/main/java/net/minecraft/server/EntityOcelot.java
index 603e53d..b5fe441 100644
--- a/src/main/java/net/minecraft/server/EntityOcelot.java
+++ b/src/main/java/net/minecraft/server/EntityOcelot.java
@@ -27,6 +27,29 @@ public class EntityOcelot extends EntityTameableAnimal {
this.datawatcher.a(18, Byte.valueOf((byte) 0));
}
+ // Spigot start - When this ocelot begins standing, any chests below this ocelot must be
+ // updated as if its contents have changed.
+ @Override
+ public void h() {
+ if (this.world.spigotConfig.altHopperTicking && this.isSitting()) {
+ int xi = MathHelper.floor(this.boundingBox.a);
+ int yi = MathHelper.floor(this.boundingBox.b) - 1;
+ int zi = MathHelper.floor(this.boundingBox.c);
+ int xf = MathHelper.floor(this.boundingBox.d);
+ int yf = MathHelper.floor(this.boundingBox.e) - 1;
+ int zf = MathHelper.floor(this.boundingBox.f);
+ for (int a = xi; a <= xf; a++) {
+ for (int c = zi; c <= zf; c++) {
+ for (int b = yi; b <= yf; b++) {
+ this.world.updateChestAndHoppers(a, b, c);
+ }
+ }
+ }
+ }
+ super.h();
+ }
+ // Spigot end
+
public void bo() {
if (this.getControllerMove().a()) {
double d0 = this.getControllerMove().b();
diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
index 19d008c..4a0ca46 100644
--- a/src/main/java/net/minecraft/server/TileEntity.java
+++ b/src/main/java/net/minecraft/server/TileEntity.java
@@ -24,6 +24,36 @@ public class TileEntity {
public int g = -1;
public Block h;
+ // Spigot start
+ // Used for alternative ticking. If the hopper at x0, y0, z0 is pointed at this tile entity, make it active.
+ private void scheduleTick(int x0, int y0, int z0) {
+ TileEntity tileEntity = this.world.getTileEntity(x0, y0, z0);
+ if (tileEntity instanceof TileEntityHopper && tileEntity.world != null) {
+ int i = BlockHopper.b(tileEntity.p());
+ if (tileEntity.x + Facing.b[i] == this.x && tileEntity.y + Facing.c[i] == this.y && tileEntity.z + Facing.d[i] == this.z) {
+ ((TileEntityHopper) tileEntity).makeTick();
+ }
+ }
+ }
+
+ // Contents have changed, so hoppers need ticking. Check all 6 faces.
+ public void scheduleTicks() {
+ if (this.world != null && this.world.spigotConfig.altHopperTicking) {
+ // check the top
+ this.scheduleTick(this.x, this.y + 1, this.z);
+ // check the sides
+ for (int i = 2; i < 6; i++) {
+ this.scheduleTick(this.x + Facing.b[i], this.y, this.z + Facing.d[i]);
+ }
+ // check the bottom
+ TileEntity tileEntity = this.world.getTileEntity(this.x, this.y - 1, this.z);
+ if (tileEntity instanceof TileEntityHopper && tileEntity.world != null) {
+ ((TileEntityHopper) tileEntity).makeTick();
+ }
+ }
+ }
+ // Spigot end
+
public TileEntity() {}
private static void a(Class oclass, String s) {
@@ -105,6 +135,9 @@ public class TileEntity {
if (this.q() != Blocks.AIR) {
this.world.f(this.x, this.y, this.z, this.q());
}
+ // Spigot start - The contents have changed, so make the hoppers pointed at this inventory active.
+ this.scheduleTicks();
+ // Spigot end
}
}
diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java
index b620394..02c07cd 100644
--- a/src/main/java/net/minecraft/server/TileEntityHopper.java
+++ b/src/main/java/net/minecraft/server/TileEntityHopper.java
@@ -17,6 +17,42 @@ public class TileEntityHopper extends TileEntity implements IHopper {
private String i;
private int j = -1;
+ // Spigot start
+ private long nextTick = -1; // Next tick this hopper will be ticked
+ private long lastTick = -1; // Last tick this hopper was polled
+
+ // To be used only with the alternative ticking. If this hopper is not cooling down, assaign a visible tick for next time.
+ public void makeTick() {
+ if (!this.j()) {
+ this.c(0);
+ }
+ }
+
+ // Contents changed, so make this hopper active.
+ public void scheduleHopperTick() {
+ if (this.world != null && this.world.spigotConfig.altHopperTicking) {
+ this.makeTick();
+ }
+ }
+
+ // We can't use config or c() if we don't have a world, so this is called when this hopper is assaigned a world.
+ // Is also called when alt hopper ticking is turned on from the reload command
+ public void convertToScheduling() {
+ this.c(this.j);
+ }
+
+ // Called when alt hopper ticking is turned off from the reload command
+ public void convertToPolling() {
+ long cooldownDiff;
+ if (this.lastTick == this.world.getTime()) {
+ cooldownDiff = this.nextTick - this.world.getTime();
+ } else {
+ cooldownDiff = this.nextTick - this.world.getTime() + 1;
+ }
+ this.c((int) Math.max(0, Math.min(cooldownDiff, Integer.MAX_VALUE)));
+ }
+ // Spigot end
+
// CraftBukkit start - add fields and methods
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
@@ -80,7 +116,19 @@ public class TileEntityHopper extends TileEntity implements IHopper {
}
nbttagcompound.set("Items", nbttaglist);
- nbttagcompound.setInt("TransferCooldown", this.j);
+ // Spigot start - Need to write the correct cooldown to disk. We convert from long to int on saving.
+ if (this.world != null && this.world.spigotConfig.altHopperTicking) {
+ long cooldownDiff;
+ if (this.lastTick == this.world.getTime()) {
+ cooldownDiff = this.nextTick - this.world.getTime();
+ } else {
+ cooldownDiff = this.nextTick - this.world.getTime() + 1;
+ }
+ nbttagcompound.setInt("TransferCooldown", (int) Math.max(0, Math.min(cooldownDiff, Integer.MAX_VALUE)));
+ } else {
+ nbttagcompound.setInt("TransferCooldown", this.j);
+ }
+ // Spigot end
if (this.k_()) {
nbttagcompound.setString("CustomName", this.i);
}
@@ -88,6 +136,9 @@ public class TileEntityHopper extends TileEntity implements IHopper {
public void update() {
super.update();
+ // Spigot start - The contents have changed, so make this hopper active.
+ this.scheduleHopperTick();
+ // Spigot end
}
public int getSize() {
@@ -167,11 +218,20 @@ public class TileEntityHopper extends TileEntity implements IHopper {
public void h() {
if (this.world != null && !this.world.isStatic) {
- --this.j;
- if (!this.j()) {
- this.c(0);
- this.i();
+ // Spigot start
+ if (this.world.spigotConfig.altHopperTicking) {
+ this.lastTick = this.world.getTime();
+ if (this.nextTick == this.world.getTime()) {
+ this.i();
+ }
+ } else {
+ --this.j;
+ if (!this.j()) {
+ this.c(0);
+ this.i();
+ }
}
+ // Spigot end
}
}
@@ -196,7 +256,7 @@ public class TileEntityHopper extends TileEntity implements IHopper {
}
// Spigot start
- if ( !this.j() )
+ if ( !world.spigotConfig.altHopperTicking && !this.j() )
{
this.c( world.spigotConfig.hopperCheck );
}
@@ -584,10 +644,34 @@ public class TileEntityHopper extends TileEntity implements IHopper {
}
public void c(int i) {
- this.j = i;
+ // Spigot start - i is the delay for which this hopper will be ticked next.
+ // i of 1 or below implies a tick next tick.
+ if (this.world != null && this.world.spigotConfig.altHopperTicking) {
+ if (i <= 0) {
+ i = 1;
+ }
+ if (this.lastTick == this.world.getTime()) {
+ this.nextTick = this.world.getTime() + i;
+ } else {
+ this.nextTick = this.world.getTime() + i - 1;
+ }
+ } else {
+ this.j = i;
+ }
+ // Spigot end
}
public boolean j() {
- return this.j > 0;
+ // Spigot start - Return whether this hopper is cooling down.
+ if (this.world != null && this.world.spigotConfig.altHopperTicking) {
+ if (this.lastTick == this.world.getTime()) {
+ return this.nextTick > this.world.getTime();
+ } else {
+ return this.nextTick >= this.world.getTime();
+ }
+ } else {
+ return this.j > 0;
+ }
+ // Spigot end
}
}
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
index a879ae3..3559bfc 100644
--- a/src/main/java/net/minecraft/server/World.java
+++ b/src/main/java/net/minecraft/server/World.java
@@ -113,6 +113,7 @@ public abstract class World implements IBlockAccess {
private final byte chunkTickRadius;
public static boolean haveWeSilencedAPhysicsCrash;
public static String blockLocation;
+ public List<TileEntity> triggerHoppersList = new ArrayList<TileEntity>(); // Spigot
public static long chunkToKey(int x, int z)
{
@@ -130,6 +131,40 @@ public abstract class World implements IBlockAccess {
{
return (int) ( ( ( k >> 32 ) & 0xFFFF0000L ) | ( ( k >> 16 ) & 0x0000FFFF ) );
}
+
+ // Spigot Start
+ private void initializeHoppers() {
+ if (this.spigotConfig.altHopperTicking) {
+ for (TileEntity o : this.triggerHoppersList) {
+ o.scheduleTicks();
+ if (o instanceof TileEntityHopper) {
+ ((TileEntityHopper) o).convertToScheduling();
+ ((TileEntityHopper) o).scheduleHopperTick();
+ }
+ }
+ }
+ triggerHoppersList.clear();
+ }
+
+ // To be used only with alt hopper ticking
+ public void updateChestAndHoppers(int a, int b, int c) {
+ Block block = this.getType(a, b, c);
+ if (block instanceof BlockChest) {
+ TileEntity tile = this.getTileEntity(a, b, c);
+ if (tile instanceof TileEntityChest) {
+ tile.scheduleTicks();
+ }
+ for (int i = 2; i < 6; i++) {
+ if (this.getType(a + Facing.b[i], b, c + Facing.d[i]) == block) {
+ tile = this.getTileEntity(a + Facing.b[i], b, c + Facing.d[i]);
+ if (tile instanceof TileEntityChest) {
+ tile.scheduleTicks();
+ }
+ break;
+ }
+ }
+ }
+ }
// Spigot end
public BiomeBase getBiome(int i, int j) {
@@ -404,6 +439,12 @@ public abstract class World implements IBlockAccess {
this.notifyAndUpdatePhysics(i, j, k, chunk, block1, block, i1);
// CraftBukkit end
}
+ // Spigot start - If this block is changing to that which a chest beneath it
+ // becomes able to be opened, then said chest must be updated
+ if (this.spigotConfig.altHopperTicking && block1 != null && block1.r() && !block.r()) {
+ this.updateChestAndHoppers(i, j - 1, k);
+ }
+ // Spigot end
return flag;
}
@@ -1455,6 +1496,7 @@ public abstract class World implements IBlockAccess {
}
// Spigot End
this.M = true;
+ this.initializeHoppers(); // Spigot - hopper ticking
Iterator iterator = this.tileEntityList.iterator();
while (iterator.hasNext()) {
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 3e6b1e6..a81b7c9 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -166,11 +166,35 @@ public class SpigotWorldConfig
log( "Entity Tracking Range: Pl " + playerTrackingRange + " / An " + animalTrackingRange + " / Mo " + monsterTrackingRange + " / Mi " + miscTrackingRange + " / Other " + otherTrackingRange );
}
+ public boolean altHopperTicking;
public int hopperTransfer;
public int hopperCheck;
public int hopperAmount;
private void hoppers()
{
+ // Alternate ticking method. Uses inventory changes, redstone updates etc.
+ // to update hoppers. Hopper-check is disabled when this is true.
+ boolean prev = altHopperTicking;
+ altHopperTicking = getBoolean( "hopper-alt-ticking", false );
+ // Necessary for the reload command
+ if (prev != altHopperTicking) {
+ net.minecraft.server.World world = (net.minecraft.server.World) Bukkit.getWorld(this.worldName);
+ if (world != null) {
+ if (altHopperTicking) {
+ for (Object o : world.tileEntityList) {
+ if (o instanceof net.minecraft.server.TileEntityHopper) {
+ ((net.minecraft.server.TileEntityHopper) o).convertToScheduling();
+ }
+ }
+ } else {
+ for (Object o : world.tileEntityList) {
+ if (o instanceof net.minecraft.server.TileEntityHopper) {
+ ((net.minecraft.server.TileEntityHopper) o).convertToPolling();
+ }
+ }
+ }
+ }
+ }
// Set the tick delay between hopper item movements
hopperTransfer = getInt( "ticks-per.hopper-transfer", 8 );
// Set the tick delay between checking for items after the associated
@@ -178,6 +202,7 @@ public class SpigotWorldConfig
// hopper sorting machines from becoming out of sync.
hopperCheck = getInt( "ticks-per.hopper-check", hopperTransfer );
hopperAmount = getInt( "hopper-amount", 1 );
+ log( "Alternative Hopper Ticking: " + altHopperTicking );
log( "Hopper Transfer: " + hopperTransfer + " Hopper Check: " + hopperCheck + " Hopper Amount: " + hopperAmount );
}
--
1.9.1