perf: a tank looks each neighbour tile up once per tick
updateEntity asked the world for the tile above up to three times and the tile below up to two times per tick; the blocks around cannot change between those calls (a taint explosion earlier in the tick is handled before the first lookup), so each is read once. Results identical, pinned by a test that runs the old lookup sequence next to the new one. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
579c7064e2
commit
3b4bc76cc6
2 files changed
+160
-4
No files matched your search
@@ -46,14 +46,17 @@ public class TileTankBasic extends TileThaumcraft implements ITubable {
|
||||
}
|
||||
}
|
||||
|
||||
boolean var4 = this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord) instanceof TileTankBasic && this.vis + this.taint < this.capacity;
|
||||
// each neighbour tile is looked up once; nothing between here and the uses changes the blocks around
|
||||
net.minecraft.tileentity.TileEntity aboveTile = this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord);
|
||||
boolean var4 = aboveTile instanceof TileTankBasic && this.vis + this.taint < this.capacity;
|
||||
if(var4 && this.taint + this.vis > this.capacity - 5) {
|
||||
MagicType var5 = Math.max(this.taint, this.vis) == this.vis?MagicType.VIS:MagicType.TAINT;
|
||||
this.ejectVis(var5, ((ITubable)this.worldObj.getTileEntity(this.xCoord, this.yCoord + 1, this.zCoord)).acceptVis(var5, var5 == MagicType.VIS?this.vis:this.taint, ForgeDirection.DOWN), ForgeDirection.UP);
|
||||
this.ejectVis(var5, ((ITubable)aboveTile).acceptVis(var5, var5 == MagicType.VIS?this.vis:this.taint, ForgeDirection.DOWN), ForgeDirection.UP);
|
||||
}
|
||||
|
||||
if(this.worldObj.getTileEntity(this.xCoord, this.yCoord - 1, this.zCoord) instanceof TileTankBasic) {
|
||||
TileTankBasic var6 = (TileTankBasic)this.worldObj.getTileEntity(this.xCoord, this.yCoord - 1, this.zCoord);
|
||||
net.minecraft.tileentity.TileEntity belowTile = this.worldObj.getTileEntity(this.xCoord, this.yCoord - 1, this.zCoord);
|
||||
if(belowTile instanceof TileTankBasic) {
|
||||
TileTankBasic var6 = (TileTankBasic)belowTile;
|
||||
if(var6.vis + var6.taint < var6.capacity - 5) {
|
||||
for(int i = 5; i > 0; --i) {
|
||||
if(this.vis >= i && var6.vis + var6.taint + i <= this.capacity - 5) {
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.pengu.thaumcraft.additions.tileentity;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldProviderSurface;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import org.junit.Test;
|
||||
|
||||
/** TDLM/thaumicadditions#20: a tank looks each neighbour tile up once per tick and moves vis/taint exactly as before. */
|
||||
public class TileTankBasicLookupTest {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T allocate(Class<T> type) throws Exception {
|
||||
Constructor<?> ctor = sun.reflect.ReflectionFactory.getReflectionFactory()
|
||||
.newConstructorForSerialization(type, Object.class.getDeclaredConstructor());
|
||||
return (T) ctor.newInstance();
|
||||
}
|
||||
|
||||
public static class CountingWorld extends WorldServer {
|
||||
|
||||
Map<Long, TileEntity> tiles;
|
||||
int tileLookups;
|
||||
int blockLookups;
|
||||
|
||||
CountingWorld() {
|
||||
super(null, null, "tanks", 0, null, null);
|
||||
}
|
||||
|
||||
static long key(int x, int y, int z) {
|
||||
return ((long) x << 40) ^ ((long) y << 20) ^ z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getTileEntity(int x, int y, int z) {
|
||||
this.tileLookups++;
|
||||
return this.tiles.get(key(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(int x, int y, int z) {
|
||||
this.blockLookups++;
|
||||
return null; // equals Blocks.air, which is unset without a Minecraft bootstrap
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockMetadata(int x, int y, int z) {
|
||||
this.blockLookups++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static CountingWorld world() throws Exception {
|
||||
CountingWorld world = allocate(CountingWorld.class);
|
||||
world.rand = new Random(1);
|
||||
Field provider = World.class.getDeclaredField("provider");
|
||||
provider.setAccessible(true);
|
||||
provider.set(world, new WorldProviderSurface());
|
||||
world.isRemote = true; // no taint explosion branch
|
||||
world.tiles = new HashMap<Long, TileEntity>();
|
||||
return world;
|
||||
}
|
||||
|
||||
private static TileTankBasic tank(CountingWorld world, int y, int vis, int taint) throws Exception {
|
||||
TileTankBasic tank = allocate(TileTankBasic.class);
|
||||
tank.setWorldObj(world);
|
||||
tank.xCoord = 3;
|
||||
tank.yCoord = y;
|
||||
tank.zCoord = 5;
|
||||
tank.capacity = 1005;
|
||||
tank.vis = vis;
|
||||
tank.taint = taint;
|
||||
world.tiles.put(CountingWorld.key(3, y, 5), tank);
|
||||
return tank;
|
||||
}
|
||||
|
||||
/** The lookups of the old method, in order, on the same fields. */
|
||||
private static void referenceUpdate(TileTankBasic t) {
|
||||
World w = t.getWorldObj();
|
||||
w.getBlock(t.xCoord, t.yCoord + 1, t.zCoord);
|
||||
w.getBlock(t.xCoord, t.yCoord - 1, t.zCoord);
|
||||
w.getBlockMetadata(t.xCoord, t.yCoord, t.zCoord);
|
||||
boolean var4 = w.getTileEntity(t.xCoord, t.yCoord + 1, t.zCoord) instanceof TileTankBasic && t.vis + t.taint < t.capacity;
|
||||
if (var4 && t.taint + t.vis > t.capacity - 5) {
|
||||
TileTankBasic above = (TileTankBasic) w.getTileEntity(t.xCoord, t.yCoord + 1, t.zCoord);
|
||||
int type = Math.max(t.taint, t.vis) == t.vis ? 0 : 1;
|
||||
int q = above.acceptVis(type == 0 ? com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.VIS : com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.TAINT,
|
||||
type == 0 ? t.vis : t.taint, net.minecraftforge.common.util.ForgeDirection.DOWN);
|
||||
t.ejectVis(type == 0 ? com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.VIS : com.pengu.api.thaumicadditions.tubesyst.ITubable.MagicType.TAINT, q,
|
||||
net.minecraftforge.common.util.ForgeDirection.UP);
|
||||
}
|
||||
if (w.getTileEntity(t.xCoord, t.yCoord - 1, t.zCoord) instanceof TileTankBasic) {
|
||||
TileTankBasic var6 = (TileTankBasic) w.getTileEntity(t.xCoord, t.yCoord - 1, t.zCoord);
|
||||
if (var6.vis + var6.taint < var6.capacity - 5) {
|
||||
for (int i = 5; i > 0; --i) {
|
||||
if (t.vis >= i && var6.vis + var6.taint + i <= t.capacity - 5) {
|
||||
var6.vis += i;
|
||||
t.vis -= i;
|
||||
}
|
||||
if (t.taint >= i && var6.vis + var6.taint + i <= t.capacity - 5) {
|
||||
var6.taint += i;
|
||||
t.taint -= i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] state(TileTankBasic... tanks) {
|
||||
int[] out = new int[tanks.length * 2];
|
||||
for (int i = 0; i < tanks.length; i++) {
|
||||
out[2 * i] = tanks[i].vis;
|
||||
out[2 * i + 1] = tanks[i].taint;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void aStackOfTanksEndsInTheSameStateWithFewerLookups() throws Exception {
|
||||
Random rnd = new Random(9);
|
||||
for (int round = 0; round < 40; round++) {
|
||||
int[] seedValues = new int[6];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
seedValues[i] = rnd.nextInt(1000);
|
||||
}
|
||||
CountingWorld oldWorld = world();
|
||||
CountingWorld newWorld = world();
|
||||
TileTankBasic[] oldTanks = new TileTankBasic[3];
|
||||
TileTankBasic[] newTanks = new TileTankBasic[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
oldTanks[i] = tank(oldWorld, 64 + i, seedValues[2 * i], seedValues[2 * i + 1] % 500);
|
||||
newTanks[i] = tank(newWorld, 64 + i, seedValues[2 * i], seedValues[2 * i + 1] % 500);
|
||||
}
|
||||
for (int tick = 0; tick < 30; tick++) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
referenceUpdate(oldTanks[i]);
|
||||
newTanks[i].updateEntity();
|
||||
}
|
||||
org.junit.Assert.assertArrayEquals("round " + round + " tick " + tick, state(oldTanks), state(newTanks));
|
||||
}
|
||||
org.junit.Assert.assertTrue("the old method looks up at least as often", oldWorld.tileLookups >= newWorld.tileLookups);
|
||||
assertEquals("new: two tile lookups per tank per tick", 2 * 3 * 30, newWorld.tileLookups);
|
||||
assertEquals(oldWorld.blockLookups, newWorld.blockLookups);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user