Mechanical network optimization and caching connections

This commit is contained in:
Calclavia 2014-02-27 23:00:38 +08:00
parent ad974aab79
commit bd37a0999b
11 changed files with 166 additions and 208 deletions

View file

@ -43,7 +43,7 @@ public class BlockConveyorBelt extends BlockTile
if (t != null && t instanceof TileConveyorBelt)
{
TileConveyorBelt tileEntity = (TileConveyorBelt) t;
tileEntity.refresh();
tileEntity.getNetwork().reconstruct();
}
}
@ -55,7 +55,7 @@ public class BlockConveyorBelt extends BlockTile
if (t != null && t instanceof TileConveyorBelt)
{
TileConveyorBelt tileEntity = (TileConveyorBelt) t;
tileEntity.refresh();
tileEntity.getNetwork().reconstruct();
}
}

View file

@ -132,8 +132,7 @@ public class TileConveyorBelt extends TileMechanical implements IBelt, IRotatabl
if (id == PACKET_SLANT)
this.slantType = SlantType.values()[data.readInt()];
else if (id == PACKET_REFRESH)
refresh();
getNetwork().reconstruct();
}
public SlantType getSlant()
@ -149,7 +148,7 @@ public class TileConveyorBelt extends TileMechanical implements IBelt, IRotatabl
}
this.slantType = slantType;
refresh();
getNetwork().reconstruct();
this.worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@ -208,8 +207,9 @@ public class TileConveyorBelt extends TileMechanical implements IBelt, IRotatabl
}
@Override
public void refresh()
public Object[] getConnections()
{
Object[] connections = new Object[6];
boolean didRefresh = false;
for (int i = 2; i < 6; i++)
@ -248,7 +248,6 @@ public class TileConveyorBelt extends TileMechanical implements IBelt, IRotatabl
if (tile instanceof IBelt)
{
connections[dir.ordinal()] = tile;
getNetwork().merge(((IBelt) tile).getNetwork());
didRefresh = true;
}
}
@ -259,7 +258,6 @@ public class TileConveyorBelt extends TileMechanical implements IBelt, IRotatabl
if (mechanical != null)
{
connections[dir.ordinal()] = mechanical;
getNetwork().merge(mechanical.getNetwork());
}
}
}
@ -271,6 +269,8 @@ public class TileConveyorBelt extends TileMechanical implements IBelt, IRotatabl
markRefresh = true;
}
}
return connections;
}
@Override

View file

@ -1,6 +1,5 @@
package resonantinduction.mechanical.energy.gear;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@ -117,15 +116,10 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
@Override
public boolean activate(EntityPlayer player, MovingObjectPosition hit, ItemStack itemStack)
{
if (!world().isRemote)
System.out.println(getNetwork());
if (itemStack != null && itemStack.getItem() instanceof ItemHandCrank)
{
getMultiBlock().get().manualCrankTime = 10;
world().playSoundEffect(x() + 0.5, y() + 0.5, z() + 0.5, Reference.PREFIX + "gearCrank", 0.5f, 0.9f + world().rand.nextFloat() * 0.2f);
player.addExhaustion(0.01f);
return true;
}
if (WrenchUtility.isWrench(itemStack))
{
if (player.isSneaking())
{
@ -134,21 +128,20 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
getMultiBlock().get().angularVelocity = -getMultiBlock().get().angularVelocity;
player.addChatMessage("Flipped gear to rotate " + (angularVelocity > 0 ? "clockwise" : "anticlockwise") + ".");
}
return true;
}
else
{
getMultiBlock().toggleConstruct();
}
getMultiBlock().get().manualCrankTime = 10;
world().playSoundEffect(x() + 0.5, y() + 0.5, z() + 0.5, Reference.PREFIX + "gearCrank", 0.5f, 0.9f + world().rand.nextFloat() * 0.2f);
player.addExhaustion(0.01f);
return true;
}
else if (player.isSneaking())
if (WrenchUtility.isWrench(itemStack))
{
if (!world().isRemote)
{
getMultiBlock().get().angularVelocity = -getMultiBlock().get().angularVelocity;
player.addChatMessage("Flipped gear to rotate " + (angularVelocity > 0 ? "clockwise" : "anticlockwise") + ".");
}
getMultiBlock().toggleConstruct();
return true;
}
return super.activate(player, hit, itemStack);
@ -165,16 +158,16 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
* Refresh should be called sparingly.
*/
@Override
public void refresh()
public Object[] getConnections()
{
connections = new WeakReference[6];
Object[] connections = new Object[6];
/**
* Only call refresh if this is the main block of a multiblock gear or a single gear block.
*/
if (!getMultiBlock().isPrimary())
if (!getMultiBlock().isPrimary() || world() == null)
{
return;
return connections;
}
/** Look for gears that are back-to-back with this gear. Equate torque. */
@ -186,10 +179,8 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
if (instance != null && instance != this && !(instance instanceof PartGearShaft) && instance.canConnect(placementSide.getOpposite(), this))
{
connections[placementSide.ordinal()] = new WeakReference(instance);
getNetwork().merge(instance.getNetwork());
connections[placementSide.ordinal()] = instance;
}
}
/**
@ -217,8 +208,7 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
if (connections[checkDir.ordinal()] == null && instance != this && checkDir != placementSide && instance != null && instance.canConnect(checkDir.getOpposite(), this))
{
connections[checkDir.ordinal()] = new WeakReference(instance);
getNetwork().merge(instance.getNetwork());
connections[checkDir.ordinal()] = instance;
}
}
}
@ -242,13 +232,12 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
if (instance != null && instance != this && instance.canConnect(checkDir.getOpposite(), this) && !(instance instanceof PartGearShaft))
{
connections[checkDir.ordinal()] = new WeakReference(instance);
getNetwork().merge(instance.getNetwork());
connections[checkDir.ordinal()] = instance;
}
}
}
getNetwork().reconstruct();
return connections;
}
/**
@ -284,17 +273,6 @@ public class PartGear extends PartMechanical implements IMechanical, IMultiBlock
return false;
}
@Override
public Object[] getConnections()
{
if (!getMultiBlock().isPrimary())
{
return new Object[6];
}
return super.getConnections();
}
@Override
protected ItemStack getItem()
{

View file

@ -1,6 +1,5 @@
package resonantinduction.mechanical.energy.gear;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@ -78,9 +77,9 @@ public class PartGearShaft extends PartMechanical
* Refresh should be called sparingly.
*/
@Override
public void refresh()
public Object[] getConnections()
{
connections = new WeakReference[6];
Object[] connections = new Object[6];
/** Check for internal connections, the FRONT and BACK. */
for (int i = 0; i < 6; i++)
@ -93,8 +92,7 @@ public class PartGearShaft extends PartMechanical
if (instance != null && instance != this && instance.canConnect(checkDir.getOpposite(), this))
{
connections[checkDir.ordinal()] = new WeakReference(instance);
getNetwork().merge(instance.getNetwork());
connections[checkDir.ordinal()] = instance;
}
}
}
@ -115,14 +113,13 @@ public class PartGearShaft extends PartMechanical
// Only connect to shafts outside of this block space.
if (instance != null && instance != this && instance instanceof PartGearShaft && instance.canConnect(checkDir.getOpposite(), this))
{
connections[checkDir.ordinal()] = new WeakReference(instance);
getNetwork().merge(instance.getNetwork());
connections[checkDir.ordinal()] = instance;
}
}
}
}
getNetwork().reconstruct();
return connections;
}
@Override

View file

@ -1,15 +1,15 @@
package resonantinduction.mechanical.energy.network;
import java.util.EnumSet;
import java.util.HashMap;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.WeakHashMap;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.ForgeDirection;
import resonantinduction.api.mechanical.IMechanical;
import resonantinduction.api.mechanical.IMechanicalNetwork;
import universalelectricity.api.net.IUpdate;
import universalelectricity.api.vector.Vector3;
import universalelectricity.core.net.Network;
import universalelectricity.core.net.NetworkTickHandler;
@ -32,16 +32,16 @@ import universalelectricity.core.net.NetworkTickHandler;
public class MechanicalNetwork extends Network<IMechanicalNetwork, IMechanical> implements IMechanicalNetwork, IUpdate
{
public static final float ACCELERATION = 0.2f;
/** The current rotation of the network */
private float rotation = 0;
private long lastRotateTime;
/**
* The cached connections of the mechanical network.
*/
private final HashMap<Object, EnumSet<ForgeDirection>> connectionMap = new LinkedHashMap<Object, EnumSet<ForgeDirection>>();
private final WeakHashMap<IMechanical, WeakReference[]> connectionCache = new WeakHashMap<IMechanical, WeakReference[]>();
private boolean markUpdateRotation = true;
@ -62,42 +62,50 @@ public class MechanicalNetwork extends Network<IMechanicalNetwork, IMechanical>
@Override
public void update()
{
/**
* Update all mechanical nodes.
*/
Iterator<IMechanical> it = new LinkedHashSet<IMechanical>(getConnectors()).iterator();
while (it.hasNext())
synchronized (getConnectors())
{
IMechanical mechanical = it.next();
Object[] connections = mechanical.getConnections();
/**
* Update all mechanical nodes.
*/
Iterator<IMechanical> it = getConnectors().iterator();
for (int i = 0; i < connections.length; i++)
while (it.hasNext())
{
ForgeDirection dir = ForgeDirection.getOrientation(i);
Object adjacent = connections[i];
IMechanical mechanical = it.next();
WeakReference[] connections = connectionCache.get(mechanical);
if (adjacent instanceof IMechanical)
if (connections != null)
{
IMechanical adjacentMech = ((IMechanical) adjacent).getInstance(dir.getOpposite());
if (adjacentMech != null && adjacent != mechanical)
for (int i = 0; i < connections.length; i++)
{
// System.out.println("UPDATING: " + mechanical + " with " + adjacentMech);
float ratio = adjacentMech.getRatio(dir.getOpposite(), mechanical) / mechanical.getRatio(dir, adjacentMech);
long torque = mechanical.getTorque();
if (connections[i] != null)
{
ForgeDirection dir = ForgeDirection.getOrientation(i);
Object adjacent = connections[i].get();
boolean inverseRotation = mechanical.inverseRotation(dir, adjacentMech) && adjacentMech.inverseRotation(dir.getOpposite(), mechanical);
if (adjacent instanceof IMechanical)
{
IMechanical adjacentMech = ((IMechanical) adjacent).getInstance(dir.getOpposite());
int inversion = inverseRotation ? -1 : 1;
if (adjacentMech != null && adjacent != mechanical)
{
float ratio = adjacentMech.getRatio(dir.getOpposite(), mechanical) / mechanical.getRatio(dir, adjacentMech);
long torque = mechanical.getTorque();
if (Math.abs(torque + inversion * (adjacentMech.getTorque() / ratio * ACCELERATION)) < Math.abs(adjacentMech.getTorque() / ratio))
mechanical.setTorque((long) (torque + inversion * ((adjacentMech.getTorque() / ratio * ACCELERATION))));
boolean inverseRotation = mechanical.inverseRotation(dir, adjacentMech) && adjacentMech.inverseRotation(dir.getOpposite(), mechanical);
float velocity = mechanical.getAngularVelocity();
int inversion = inverseRotation ? -1 : 1;
if (Math.abs(velocity + inversion * (adjacentMech.getAngularVelocity() * ratio * ACCELERATION)) < Math.abs(adjacentMech.getAngularVelocity() * ratio))
mechanical.setAngularVelocity(velocity + (inversion * adjacentMech.getAngularVelocity() * ratio * ACCELERATION));
if (Math.abs(torque + inversion * (adjacentMech.getTorque() / ratio * ACCELERATION)) < Math.abs(adjacentMech.getTorque() / ratio))
mechanical.setTorque((long) (torque + inversion * ((adjacentMech.getTorque() / ratio * ACCELERATION))));
float velocity = mechanical.getAngularVelocity();
if (Math.abs(velocity + inversion * (adjacentMech.getAngularVelocity() * ratio * ACCELERATION)) < Math.abs(adjacentMech.getAngularVelocity() * ratio))
mechanical.setAngularVelocity(velocity + (inversion * adjacentMech.getAngularVelocity() * ratio * ACCELERATION));
}
}
}
}
}
}
@ -117,18 +125,75 @@ public class MechanicalNetwork extends Network<IMechanicalNetwork, IMechanical>
}
@Override
public void reconstruct()
protected void reconstructConnector(IMechanical node)
{
super.reconstruct();
node.setNetwork(this);
if (canUpdate())
NetworkTickHandler.addNetwork(this);
/**
* Cache connections.
*/
Object[] conn = node.getConnections();
if (conn == null && node instanceof TileEntity)
{
/**
* Default connection implementation
*/
conn = new Object[6];
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity tile = new Vector3((TileEntity) node).translate(dir).getTileEntity(((TileEntity) node).worldObj);
if (tile instanceof IMechanical)
{
IMechanical mech = ((IMechanical) tile).getInstance(dir.getOpposite());
if (mech != null && node.canConnect(dir, mech) && mech.canConnect(dir.getOpposite(), node))
{
conn[dir.ordinal()] = mech;
}
}
}
}
WeakReference[] connections = new WeakReference[conn.length];
for (int i = 0; i < connections.length; i++)
{
if (conn[i] != null)
{
if (conn[i] instanceof IMechanical)
{
IMechanical connected = ((IMechanical) conn[i]);
if (connected.getNetwork() != this)
{
connected.getNetwork().getConnectors().clear();
connected.setNetwork(this);
addConnector(connected);
reconstructConnector(connected);
}
}
connections[i] = new WeakReference(conn[i]);
}
}
connectionCache.put(node, connections);
}
@Override
protected void reconstructConnector(IMechanical connector)
public Object[] getConnectionsFor(IMechanical connector)
{
connector.setNetwork(this);
Object[] conn = new Object[6];
WeakReference[] connections = connectionCache.get(connector);
for (int i = 0; i < connections.length; i++)
if (connections[i] != null)
conn[i] = connections[i].get();
return conn;
}
@Override

View file

@ -28,11 +28,7 @@ public abstract class PartMechanical extends JCuboidPart implements JNormalOcclu
{
private IMechanicalNetwork network;
/** The mechanical connections this connector has made */
protected WeakReference[] connections = new WeakReference[6];
protected float prevAngularVelocity, angularVelocity;
protected long torque;
/**
@ -55,23 +51,6 @@ public abstract class PartMechanical extends JCuboidPart implements JNormalOcclu
this.tier = itemDamage;
}
@Override
public boolean activate(EntityPlayer player, MovingObjectPosition hit, ItemStack item)
{
if (!world().isRemote)
{
int i = 0;
for (Object obj : connections)
if (obj != null)
i++;
System.out.println("Connected with: " + i + ":" + getNetwork());
// refresh();
}
return false;
}
@Override
public void update()
{
@ -102,33 +81,19 @@ public abstract class PartMechanical extends JCuboidPart implements JNormalOcclu
@Override
public void onWorldJoin()
{
refresh();
getNetwork().reconstruct();
}
@Override
public void onNeighborChanged()
{
refresh();
getNetwork().reconstruct();
}
@Override
public void onPartChanged(TMultiPart part)
{
refresh();
}
protected abstract void refresh();
@Override
public Object[] getConnections()
{
Object[] actualConnections = new Object[6];
for (int i = 0; i < connections.length; i++)
if (connections[i] != null)
actualConnections[i] = connections[i].get();
return actualConnections;
getNetwork().reconstruct();
}
@Override

View file

@ -20,8 +20,6 @@ public abstract class TileMechanical extends TileAdvanced implements IMechanical
{
protected static final int PACKET_VELOCITY = Mechanical.contentRegistry.getNextPacketID();
/** The mechanical connections this connector has made */
protected Object[] connections = new Object[6];
private IMechanicalNetwork network;
protected float angularVelocity;
protected long torque;
@ -36,7 +34,7 @@ public abstract class TileMechanical extends TileAdvanced implements IMechanical
@Override
public void initiate()
{
refresh();
getNetwork().reconstruct();
}
@Override
@ -105,14 +103,6 @@ public abstract class TileMechanical extends TileAdvanced implements IMechanical
super.invalidate();
}
/**
* Refreshes all the connections of this block.
*/
public void refresh()
{
}
protected float getLoad()
{
return 0.95f;
@ -121,26 +111,7 @@ public abstract class TileMechanical extends TileAdvanced implements IMechanical
@Override
public Object[] getConnections()
{
connections = new Object[6];
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity tile = new Vector3(this).translate(dir).getTileEntity(worldObj);
if (tile instanceof IMechanical)
{
IMechanical mech = ((IMechanical) tile).getInstance(dir.getOpposite());
// Don't connect with shafts
if (mech != null && !(mech instanceof PartGearShaft) && canConnect(dir, this) && mech.canConnect(dir.getOpposite(), this))
{
connections[dir.ordinal()] = mech;
getNetwork().merge(mech.getNetwork());
}
}
}
return connections;
return null;
}
@Override

View file

@ -17,36 +17,6 @@ public class TileMechanicalTurbine extends TileTurbine implements IMechanical
energy = new EnergyStorageHandler(0);
}
/**
* Mechanical Methods
*
* @return The connections.
*/
@Override
public Object[] getConnections()
{
Object[] connections = new Object[6];
for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS)
{
TileEntity tile = new Vector3(this).translate(dir).getTileEntity(worldObj);
if (tile instanceof IMechanical)
{
IMechanical mech = ((IMechanical) tile).getInstance(dir.getOpposite());
// Don't connect with shafts
if (mech != null && canConnect(dir, this) && mech.canConnect(dir.getOpposite(), this))
{
connections[dir.ordinal()] = mech;
getNetwork().merge(mech.getNetwork());
}
}
}
return connections;
}
private IMechanicalNetwork network;
@Override
@ -120,4 +90,10 @@ public class TileMechanicalTurbine extends TileTurbine implements IMechanical
}
return false;
}
@Override
public Object[] getConnections()
{
return null;
}
}

View file

@ -58,15 +58,7 @@ public abstract class FluidNetwork extends NodeNetwork<IFluidNetwork, IFluidConn
{
this.tank = new FluidTank(0);
for (IFluidConnector connector : new HashSet<IFluidConnector>(getConnectors()))
{
if (connector.getNetwork() instanceof IFluidNetwork)
{
connector.setNetwork(this);
}
this.reconstructConnector(connector);
}
super.reconstruct();
this.reconstructTankInfo();
this.distributeConnectors();
@ -75,6 +67,9 @@ public abstract class FluidNetwork extends NodeNetwork<IFluidNetwork, IFluidConn
@Override
public void reconstructConnector(IFluidConnector connector)
{
if (connector.getNetwork() instanceof IFluidNetwork)
connector.setNetwork(this);
FluidTank tank = connector.getInternalTank();
if (tank != null)

View file

@ -1,6 +1,7 @@
package resonantinduction.core.resource;
import net.minecraft.item.Item;
import net.minecraft.world.World;
public class ItemHandCrank extends Item
{
@ -8,5 +9,9 @@ public class ItemHandCrank extends Item
{
super(id);
}
@Override
public boolean shouldPassSneakingClickToBlock(World world, int x, int y, int z)
{
return true;
}
}

View file

@ -49,9 +49,15 @@ public class ItemOreResourceBucket extends Item
{
if (getMaterialFromStack(is) != null)
{
String fluidName = FluidRegistry.getFluid(isMolten ? ResourceGenerator.materialNameToMolten(getMaterialFromStack(is)) : ResourceGenerator.materialNameToMixture(getMaterialFromStack(is))).getLocalizedName();
return (LanguageUtility.getLocal(this.getUnlocalizedName() + ".name")).replace("%v", fluidName).replace(" ", " ");
String fluidID = isMolten ? ResourceGenerator.materialNameToMolten(getMaterialFromStack(is)) : ResourceGenerator.materialNameToMixture(getMaterialFromStack(is));
if (fluidID != null)
{
String fluidName = FluidRegistry.getFluid(fluidID).getLocalizedName();
return (LanguageUtility.getLocal(this.getUnlocalizedName() + ".name")).replace("%v", fluidName).replace(" ", " ");
}
}
return null;
}