// Rotor bearing must calculate outwards dir, as this is normally only calculated in onMachineAssembled().
rotorPart.recalculateOutwardsDirection(getMinimumCoord(), getMaximumCoord());
// Find out which way the rotor runs. Obv, this is inwards from the bearing.
ForgeDirection rotorDir = rotorPart.getOutwardsDir().getOpposite();
CoordTriplet rotorCoord = rotorPart.getWorldLocation();
CoordTriplet minRotorCoord = getMinimumCoord();
CoordTriplet maxRotorCoord = getMaximumCoord();
// Constrain min/max rotor coords to where the rotor bearing is and the block opposite it
if(rotorDir.offsetX == 0) {
minRotorCoord.x = maxRotorCoord.x = rotorCoord.x;
}
if(rotorDir.offsetY == 0) {
minRotorCoord.y = maxRotorCoord.y = rotorCoord.y;
}
if(rotorDir.offsetZ == 0) {
minRotorCoord.z = maxRotorCoord.z = rotorCoord.z;
}
// Figure out where the rotor ends and which directions are normal to the rotor's 4 faces (this is where blades emit from)
CoordTriplet endRotorCoord = rotorCoord.equals(minRotorCoord) ? maxRotorCoord : minRotorCoord;
endRotorCoord.translate(rotorDir.getOpposite());
ForgeDirection[] bladeDirections;
if(rotorDir.offsetY != 0) {
bladeDirections = StaticUtils.CardinalDirections;
}
else if(rotorDir.offsetX != 0) {
bladeDirections = RotorXBladeDirections;
}
else {
bladeDirections = RotorZBladeDirections;
}
Set<CoordTriplet> rotorShafts = new HashSet<CoordTriplet>(attachedRotorShafts.size());
Set<CoordTriplet> rotorBlades = new HashSet<CoordTriplet>(attachedRotorBlades.size());
for(TileEntityTurbineRotorPart part : attachedRotorShafts) {
rotorShafts.add(part.getWorldLocation());
}
for(TileEntityTurbineRotorPart part : attachedRotorBlades) {
rotorBlades.add(part.getWorldLocation());
}
// Move along the length of the rotor, 1 block at a time
boolean encounteredCoils = false;
while(!rotorShafts.isEmpty() && !rotorCoord.equals(endRotorCoord)) {
rotorCoord.translate(rotorDir);
// Ensure we find a rotor block along the length of the entire rotor
if(!rotorShafts.remove(rotorCoord)) {
throw new MultiblockValidationException(String.format("%s - This block must contain a rotor. The rotor must begin at the bearing and run the entire length of the turbine", rotorCoord));
}
// Now move out in the 4 rotor normals, looking for blades and coils
CoordTriplet checkCoord = rotorCoord.copy();
boolean encounteredBlades = false;
for(ForgeDirection bladeDir : bladeDirections) {
checkCoord.copy(rotorCoord);
boolean foundABlade = false;
checkCoord.translate(bladeDir);
// If we find 1 blade, we can keep moving along the normal to find more blades
while(rotorBlades.remove(checkCoord)) {
// We found a coil already?! NOT ALLOWED.
if(encounteredCoils) {
throw new MultiblockValidationException(String.format("%s - Rotor blades must be placed closer to the rotor bearing than all other parts inside a turbine", checkCoord));
}
foundABlade = encounteredBlades = true;
checkCoord.translate(bladeDir);
}
// If this block wasn't a blade, check to see if it was a coil
if(!foundABlade) {
if(foundCoils.remove(checkCoord)) {
encounteredCoils = true;
// We cannot have blades and coils intermix. This prevents intermixing, depending on eval order.
if(encounteredBlades) {
throw new MultiblockValidationException(String.format("%s - Metal blocks must by placed further from the rotor bearing than all rotor blades", checkCoord));
}
// Check the two coil spots in the 'corners', which are permitted if they're connected to the main rotor coil somehow
CoordTriplet coilCheck = checkCoord.copy();
coilCheck.translate(bladeDir.getRotation(rotorDir));
foundCoils.remove(coilCheck);
coilCheck.copy(checkCoord);
coilCheck.translate(bladeDir.getRotation(rotorDir.getOpposite()));
foundCoils.remove(coilCheck);
}
// Else: It must have been air.
}
}