diff --git a/mechanical/src/main/scala/resonantinduction/mechanical/gear/GearNode.java b/mechanical/src/main/scala/resonantinduction/mechanical/gear/GearNode.java new file mode 100644 index 000000000..86994d24f --- /dev/null +++ b/mechanical/src/main/scala/resonantinduction/mechanical/gear/GearNode.java @@ -0,0 +1,290 @@ +package resonantinduction.mechanical.gear; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.ForgeDirection; +import resonant.api.IMechanicalNode; +import resonant.api.grid.INodeProvider; +import resonantinduction.mechanical.energy.grid.MechanicalNode; +import codechicken.lib.vec.Rotation; +import codechicken.multipart.TMultiPart; +import codechicken.multipart.TileMultipart; + +/** Node for the gear + * + * @author Calclavia, Edited by: Darkguardsman */ +public class GearNode extends MechanicalNode +{ + public GearNode(PartGear parent) + { + super(parent); + } + + protected PartGear gear() + { + return (PartGear) this.parent; + } + + @Override + public void onUpdate() + { + if (!gear().getMultiBlock().isPrimary()) + { + torque = 0; + angularVelocity = 0; + } + else + { + if (gear().tier == 10) + { + torque = 100; + angularVelocity = 100; + } + } + } + + @Override + public double getTorqueLoad() + { + // Decelerate the gear based on tier. + switch (gear().tier) + { + default: + return 0.3; + case 1: + return 0.2; + case 2: + return 0.1; + case 10: + return 0; + } + } + + @Override + public double getAngularVelocityLoad() + { + // Decelerate the gear based on tier. + switch (gear().tier) + { + default: + return 0.03; + case 1: + return 0.02; + case 2: + return 0.01; + case 10: + return 0; + } + } + + @Override + public void doRecache() + { + connections.clear(); + + /** Only call refresh if this is the main block of a multiblock gear or a single gear block. */ + if (!gear().getMultiBlock().isPrimary() || world() == null) + { + return; + } + + /** Look for gears that are back-to-back with this gear. Equate torque. */ + TileEntity tileBehind = new universalelectricity.api.vector.Vector3(gear().tile()).translate(gear().placementSide).getTileEntity(world()); + + if (tileBehind instanceof INodeProvider) + { + MechanicalNode instance = (MechanicalNode) ((INodeProvider) tileBehind).getNode(MechanicalNode.class, gear().placementSide.getOpposite()); + + if (instance != null && instance != this && !(instance.parent instanceof PartGearShaft) && instance.canConnect(gear().placementSide.getOpposite(), this)) + { + connections.put(instance, gear().placementSide); + } + } + + /** Look for gears that are internal and adjacent to this gear. (The 4 sides + the internal + * center) */ + for (int i = 0; i < 6; i++) + { + ForgeDirection checkDir = ForgeDirection.getOrientation(i); + + TileEntity tile = gear().tile(); + + if (gear().getMultiBlock().isConstructed() && checkDir != gear().placementSide && checkDir != gear().placementSide.getOpposite()) + { + tile = new universalelectricity.api.vector.Vector3(gear().tile()).translate(checkDir).getTileEntity(world()); + } + + if (tile instanceof INodeProvider) + { + /** If we're checking for the block that is opposite to the gear's placement side + * (the center), then we try to look for a gear shaft in the center. */ + MechanicalNode instance = (MechanicalNode) ((INodeProvider) tile).getNode(MechanicalNode.class, checkDir == gear().placementSide.getOpposite() ? ForgeDirection.UNKNOWN : checkDir); + + if (!connections.containsValue(checkDir) && instance != this && checkDir != gear().placementSide && instance != null && instance.canConnect(checkDir.getOpposite(), this)) + { + connections.put(instance, checkDir); + } + } + } + + int displaceCheck = 1; + + if (gear().getMultiBlock().isPrimary() && gear().getMultiBlock().isConstructed()) + { + displaceCheck = 2; + } + + /** Look for gears outside this block space, the relative UP, DOWN, LEFT, RIGHT */ + for (int i = 0; i < 4; i++) + { + ForgeDirection checkDir = ForgeDirection.getOrientation(Rotation.rotateSide(gear().placementSide.ordinal(), i)); + TileEntity checkTile = new universalelectricity.api.vector.Vector3(gear().tile()).translate(checkDir, displaceCheck).getTileEntity(world()); + + if (!connections.containsValue(checkDir) && checkTile instanceof INodeProvider) + { + MechanicalNode instance = (MechanicalNode) ((INodeProvider) checkTile).getNode(MechanicalNode.class, gear().placementSide); + + if (instance != null && instance != this && instance.canConnect(checkDir.getOpposite(), this) && !(instance.parent instanceof PartGearShaft)) + { + connections.put(instance, checkDir); + } + } + } + } + + /** Can this gear be connected BY the source? + * + * @param from - Direction source is coming from. + * @param with - The source of the connection. + * @return True is so. */ + @Override + public boolean canConnect(ForgeDirection from, Object with) + { + if (!gear().getMultiBlock().isPrimary()) + { + return false; + } + + if (with instanceof MechanicalNode) + { + INodeProvider parent = ((MechanicalNode) with).parent; + + /** Check for flat connections (gear face on gear face) to make sure it's actually on + * this gear block. */ + if (from == gear().placementSide.getOpposite()) + { + if (parent instanceof PartGear || parent instanceof PartGearShaft) + { + if (parent instanceof PartGearShaft) + { + PartGearShaft shaft = (PartGearShaft) parent; + return shaft.tile().partMap(from.getOpposite().ordinal()) == gear() && Math.abs(shaft.placementSide.offsetX) == Math.abs(gear().placementSide.offsetX) && Math.abs(shaft.placementSide.offsetY) == Math.abs(gear().placementSide.offsetY) && Math.abs(shaft.placementSide.offsetZ) == Math.abs(gear().placementSide.offsetZ); + } + else if (parent instanceof PartGear) + { + if (((PartGear) parent).tile() == gear().tile() && !gear().getMultiBlock().isConstructed()) + { + return true; + } + + if (((PartGear) parent).placementSide != gear().placementSide) + { + TMultiPart part = gear().tile().partMap(((PartGear) parent).placementSide.ordinal()); + + if (part instanceof PartGear) + { + /** Case when we connect gears via edges internally. Large gear + * attempt to connect to small gear. */ + PartGear sourceGear = (PartGear) part; + + if (sourceGear.isCenterMultiBlock() && !sourceGear.getMultiBlock().isPrimary()) + { + // For large gear to small gear on edge connection. + return true; + } + } + else + { + /** Small gear attempting to connect to large gear. */ + if (gear().getMultiBlock().isConstructed()) + { + TMultiPart checkPart = ((PartGear) parent).tile().partMap(gear().placementSide.ordinal()); + + if (checkPart instanceof PartGear) + { + ForgeDirection requiredDirection = ((PartGear) checkPart).getPosition().subtract(position()).toForgeDirection(); + return ((PartGear) checkPart).isCenterMultiBlock() && ((PartGear) parent).placementSide == requiredDirection; + } + } + } + } + } + } + + /** Face to face stick connection. */ + TileEntity sourceTile = position().translate(from.getOpposite()).getTileEntity(world()); + + if (sourceTile instanceof INodeProvider) + { + MechanicalNode sourceInstance = (MechanicalNode) ((INodeProvider) sourceTile).getNode(MechanicalNode.class, from); + return sourceInstance == with; + } + } + else if (from == gear().placementSide) + { + /** Face to face stick connection. */ + TileEntity sourceTile = position().translate(from).getTileEntity(world()); + + if (sourceTile instanceof INodeProvider) + { + MechanicalNode sourceInstance = (MechanicalNode) ((INodeProvider) sourceTile).getNode(MechanicalNode.class, from.getOpposite()); + return sourceInstance == with; + } + } + else + { + TileEntity destinationTile = ((MechanicalNode) with).position().translate(from.getOpposite()).getTileEntity(world()); + + if (destinationTile instanceof INodeProvider && destinationTile instanceof TileMultipart) + { + TMultiPart destinationPart = ((TileMultipart) destinationTile).partMap(gear().placementSide.ordinal()); + + if (destinationPart instanceof PartGear) + { + if (gear() != destinationPart) + { + return ((PartGear) destinationPart).isCenterMultiBlock(); + } + else + { + return true; + } + } + else + { + return true; + } + } + } + } + + return false; + } + + @Override + public float getRatio(ForgeDirection dir, IMechanicalNode with) + { + universalelectricity.api.vector.Vector3 deltaPos = with.position().subtract(position()); + + boolean caseX = gear().placementSide.offsetX != 0 && deltaPos.y == 0 && deltaPos.z == 0; + boolean caseY = gear().placementSide.offsetY != 0 && deltaPos.x == 0 && deltaPos.z == 0; + boolean caseZ = gear().placementSide.offsetZ != 0 && deltaPos.x == 0 && deltaPos.y == 0; + + if (caseX || caseY || caseZ) + { + return super.getRatio(dir, with); + } + + return gear().getMultiBlock().isConstructed() ? 1.5f : super.getRatio(dir, with); + } + +} diff --git a/mechanical/src/main/scala/resonantinduction/mechanical/gear/PartGear.java b/mechanical/src/main/scala/resonantinduction/mechanical/gear/PartGear.java index 5219482a2..f8078622f 100644 --- a/mechanical/src/main/scala/resonantinduction/mechanical/gear/PartGear.java +++ b/mechanical/src/main/scala/resonantinduction/mechanical/gear/PartGear.java @@ -59,272 +59,8 @@ public class PartGear extends PartMechanical implements IMultiBlockStructure nodes = Collections.newSetFromMap(new WeakHashMap()); private final Set generators = Collections.newSetFromMap(new WeakHashMap()); private boolean doRemap = false; + private boolean isDead = false; /** Called by a gear when its added to the world */ public void onAdded(NodeGear gear) @@ -60,13 +64,111 @@ public class GearNetwork implements IUpdate @Override public boolean canUpdate() { - return true; + return !isDead; } @Override public boolean continueUpdate() { - return true; + return canUpdate(); + } + + /** Called to merge this network with another network. Creates a new network in the process and + * empties the old networks */ + public GearNetwork merge(GearNetwork network) + { + if (network != null && network.getClass().isAssignableFrom(getClass()) && network != this) + { + synchronized (this) + { + GearNetwork newNetwork = new GearNetwork(); + //Add all nodes to new network from old ones + newNetwork.nodes.addAll(nodes); + newNetwork.nodes.addAll(network.nodes); + //Add all generator nodes + newNetwork.generators.addAll(generators); + newNetwork.generators.addAll(network.generators); + + //Destroy the old networks + network.deconstruct(); + deconstruct(); + + newNetwork.doRemap = true; + return newNetwork; + } + } + + return null; + } + + public void split(NodeGear splitPoint) + { + /** Loop through the connected blocks and attempt to see if there are connections between the + * two points elsewhere. */ + Object[] connectedBlocks = getConnectionsFor(splitPoint); + removeConnector(splitPoint); + + for (int i = 0; i < connectedBlocks.length; i++) + { + Object connectedA = connectedBlocks[i]; + + if (connectedA != null && isValidConnector(connectedA)) + { + for (int ii = 0; ii < connectedBlocks.length; ii++) + { + final Object connectedB = connectedBlocks[ii]; + + if (connectedB != null && connectedA != connectedB && isValidConnector(connectedB)) + { + ConnectionPathfinder finder = new ConnectionPathfinder(getConnectorClass(), (C) connectedB, splitPoint); + finder.findNodes((C) connectedA); + + if (finder.results.size() <= 0) + { + try + { + /** The connections A and B are not connected anymore. Give them both + * a new common network. */ + N newNetwork = newInstance(); + + for (C node : finder.closedSet) + { + if (node != splitPoint) + { + newNetwork.addConnector(node); + removeConnector(node); + onSplit(newNetwork); + } + } + newNetwork.reconstruct(); + } + catch (Exception e) + { + e.printStackTrace(); + } + + } + } + } + } + } + + reconstruct(); + } + + /** Called to rebuild the network */ + protected void reconstruct() + { + + } + + /** Called to destroy or rather clean up the network. Make sure to do your cleanup in this + * method. */ + protected void deconstruct() + { + this.nodes.clear(); + this.generators.clear(); + this.isDead = true; } }