perf: a tank looks each neighbour tile up once per tick #32
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