Added accelerator data structures
This commit is contained in:
parent
e2d963c071
commit
e269118b1e
2 changed files with 1220 additions and 0 deletions
550
src/main/java/cr0s/warpdrive/data/AcceleratorSetup.java
Normal file
550
src/main/java/cr0s/warpdrive/data/AcceleratorSetup.java
Normal file
|
@ -0,0 +1,550 @@
|
|||
package cr0s.warpdrive.data;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import cr0s.warpdrive.Commons;
|
||||
import cr0s.warpdrive.LocalProfiler;
|
||||
import cr0s.warpdrive.WarpDrive;
|
||||
import cr0s.warpdrive.block.atomic.BlockAcceleratorControlPoint;
|
||||
import cr0s.warpdrive.block.atomic.BlockChiller;
|
||||
import cr0s.warpdrive.block.atomic.BlockElectromagnetPlain;
|
||||
import cr0s.warpdrive.block.atomic.BlockParticlesCollider;
|
||||
import cr0s.warpdrive.block.atomic.BlockParticlesInjector;
|
||||
import cr0s.warpdrive.block.atomic.BlockVoidShellPlain;
|
||||
import cr0s.warpdrive.block.atomic.TileEntityParticlesInjector;
|
||||
import cr0s.warpdrive.block.energy.BlockEnergyBank;
|
||||
import cr0s.warpdrive.block.energy.TileEntityEnergyBank;
|
||||
import cr0s.warpdrive.config.WarpDriveConfig;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.AxisAlignedBB;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
import cpw.mods.fml.common.FMLCommonHandler;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
public class AcceleratorSetup extends GlobalPosition {
|
||||
private static final int ACCELERATOR_MAX_RANGE_SQUARED = 192 * 192;
|
||||
|
||||
// raw data
|
||||
private HashMap<VectorI, TrajectoryPoint> trajectoryAccelerator;
|
||||
private HashMap<VectorI, TrajectoryPoint> trajectoryTransfer;
|
||||
|
||||
// computed values
|
||||
private int[] countMagnets = new int[3];
|
||||
private int[] countChillers = new int[3];
|
||||
private final HashMap<VectorI, Integer> controlPoints = new HashMap<>();
|
||||
|
||||
public final HashMap<VectorI, Byte> chillers = new HashMap<>();
|
||||
public final Set<TileEntityEnergyBank> energyBanks = new HashSet<>();
|
||||
public final int energy_maxStorage;
|
||||
public final TreeMap<Integer, VectorI> mapInjectors = new TreeMap<>();
|
||||
public final Integer[] keyInjectors;
|
||||
public final ArrayList<TrajectoryPoint> listColliders = new ArrayList<>();
|
||||
|
||||
private VectorI vMin;
|
||||
private VectorI vMax;
|
||||
|
||||
// Cooldown duration
|
||||
// increase with number of electromagnets ^0.5
|
||||
// increase with tier (0.75 + 0.25 * x)
|
||||
// decrease with number of cooling vents ^0.6
|
||||
// has a minimum duration function of number of electromagnets per cooling vent
|
||||
// Cooldown energy
|
||||
// increase with tier (0.25 > 1.0 > 4.0)
|
||||
// increase with number of cooling vents
|
||||
|
||||
public double[] temperatures_cooling_K_perTick = new double[3];
|
||||
public double temperature_coolingEnergyCost_perTick;
|
||||
public double[] temperatures_sustainEnergyCost_perTick = new double[3];
|
||||
public double particleEnergy_energyCost_perTick;
|
||||
|
||||
public AcceleratorSetup(final int dimensionId, final int x, final int y, final int z) {
|
||||
super(dimensionId, x, y, z);
|
||||
LocalProfiler.start(String.format("[AcceleratorSetup] Scanning @ DIM%d (%d %d %d)", dimensionId, x, y, z));
|
||||
|
||||
refresh();
|
||||
|
||||
// cache energy stats
|
||||
if (energyBanks.isEmpty()) {
|
||||
energy_maxStorage = 0;
|
||||
} else {
|
||||
int maxStorage = 0;
|
||||
for(TileEntityEnergyBank tileEntityEnergyBank : energyBanks) {
|
||||
maxStorage += tileEntityEnergyBank.energy_getMaxStorage();
|
||||
}
|
||||
energy_maxStorage = maxStorage;
|
||||
}
|
||||
|
||||
// sort injectors by their video channels
|
||||
if (mapInjectors.isEmpty()) {
|
||||
keyInjectors = null;
|
||||
} else {
|
||||
keyInjectors = mapInjectors.keySet().toArray(new Integer[0]);
|
||||
}
|
||||
|
||||
if (WarpDriveConfig.LOGGING_FORCEFIELD) {
|
||||
WarpDrive.logger.info(String.format("Accelerator length: %d + %d including %d + %d + %d magnets, %d chillers and %d energy banks"
|
||||
+ " cooldown: %.3f %.3f %.3f /t %.3f EU/t"
|
||||
+ " sustain: %.3f %.3f %.3f EU/t"
|
||||
+ " acceleration: %.3f /particle",
|
||||
trajectoryAccelerator.size(), trajectoryTransfer.size(),
|
||||
countMagnets[0], countMagnets[1], countMagnets[2], chillers.size(), energyBanks.size(),
|
||||
temperatures_cooling_K_perTick[0], temperatures_cooling_K_perTick[1], temperatures_cooling_K_perTick[2],
|
||||
temperature_coolingEnergyCost_perTick,
|
||||
temperatures_sustainEnergyCost_perTick[0], temperatures_sustainEnergyCost_perTick[1], temperatures_sustainEnergyCost_perTick[2],
|
||||
particleEnergy_energyCost_perTick));
|
||||
}
|
||||
|
||||
LocalProfiler.stop();
|
||||
}
|
||||
|
||||
// add the vector with it's surrounding block so we can catch 'added' blocks
|
||||
private void addToBoundingBox(final VectorI vector) {
|
||||
vMin.x = Math.min(vMin.x, vector.x - 1);
|
||||
vMin.y = Math.min(vMin.y, vector.y - 1);
|
||||
vMin.z = Math.min(vMin.z, vector.z - 1);
|
||||
vMax.x = Math.max(vMax.x, vector.x + 1);
|
||||
vMax.y = Math.max(vMax.y, vector.y + 1);
|
||||
vMax.z = Math.max(vMax.z, vector.z + 1);
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
WorldServer world = getWorldServerIfLoaded();
|
||||
if (world == null) {
|
||||
if (WarpDriveConfig.LOGGING_ACCELERATOR) {
|
||||
WarpDrive.logger.warn(String.format("Accelerator scan cancelled: Dimension %d isn't loaded", dimensionId));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT) {
|
||||
WarpDrive.logger.warn("Accelerator scan cancelled: client side");
|
||||
return;
|
||||
}
|
||||
|
||||
// get all accelerator and transfer trajectory points
|
||||
fillTrajectoryPoints(world);
|
||||
if (trajectoryAccelerator == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scan the accelerators
|
||||
computeCountsAndBoundingBox();
|
||||
computeVectorArrays(world);
|
||||
|
||||
// compute values
|
||||
double coolingFactor = 10.0 / (countMagnets[0] + countMagnets[1] + countMagnets[2]);
|
||||
temperatures_cooling_K_perTick[0] = (countChillers[0] * 1.00 + countChillers[1] * 0.75 + countChillers[2] * 0.5) * coolingFactor;
|
||||
temperatures_cooling_K_perTick[1] = (countChillers[1] * 1.00 + countChillers[2] * 0.75) * coolingFactor;
|
||||
temperatures_cooling_K_perTick[2] = (countChillers[2] * 1.00) * coolingFactor;
|
||||
|
||||
temperature_coolingEnergyCost_perTick = countChillers[0] * 10.0 + countChillers[1] * 20.0 + countChillers[2] * 40.0;
|
||||
|
||||
temperatures_sustainEnergyCost_perTick[0] = countChillers[0] * 1.00 + countChillers[1] * 2.0 + countChillers[2] * 2.0;
|
||||
temperatures_sustainEnergyCost_perTick[1] = countChillers[0] * 0.50 + countChillers[1] * 2.0 + countChillers[2] * 3.0;
|
||||
temperatures_sustainEnergyCost_perTick[2] = countChillers[0] * 0.25 + countChillers[1] * 1.0 + countChillers[2] * 4.0;
|
||||
|
||||
particleEnergy_energyCost_perTick = countMagnets[0] * 1.00 + countMagnets[1] * 2.00 + countMagnets[2] * 3.00;
|
||||
}
|
||||
|
||||
private void fillTrajectoryPoints(WorldServer world) {
|
||||
// find closest connected VoidShell
|
||||
Set<Block> whitelist = ImmutableSet.of(
|
||||
WarpDrive.blockElectromagnetPlain[0],
|
||||
WarpDrive.blockElectromagnetGlass[0],
|
||||
WarpDrive.blockElectromagnetPlain[1],
|
||||
WarpDrive.blockElectromagnetGlass[1],
|
||||
WarpDrive.blockElectromagnetPlain[2],
|
||||
WarpDrive.blockElectromagnetGlass[2],
|
||||
WarpDrive.blockVoidShellPlain,
|
||||
WarpDrive.blockVoidShellGlass);
|
||||
Set<VectorI> connections = Commons.getConnectedBlocks(world, new VectorI(x, y, z), ForgeDirection.VALID_DIRECTIONS, whitelist, 3);
|
||||
VectorI firstVoidShell = null;
|
||||
for (VectorI connection : connections) {
|
||||
Block block = connection.getBlock(world);
|
||||
if (block instanceof BlockVoidShellPlain) {
|
||||
firstVoidShell = connection.clone();
|
||||
break;
|
||||
}
|
||||
}
|
||||
WarpDrive.logger.info("First void shell is " + firstVoidShell);
|
||||
if (firstVoidShell == null) {
|
||||
WarpDrive.logger.warn("No void shell connection found");
|
||||
return;
|
||||
}
|
||||
|
||||
// find initial direction
|
||||
whitelist = ImmutableSet.of(
|
||||
WarpDrive.blockVoidShellPlain,
|
||||
WarpDrive.blockVoidShellGlass);
|
||||
TrajectoryPoint trajectoryPoint = null;
|
||||
for(ForgeDirection direction : Commons.HORIZONTAL_DIRECTIONS) {
|
||||
VectorI next = firstVoidShell.clone(direction);
|
||||
if (whitelist.contains(next.getBlock_noChunkLoading(world))) {
|
||||
trajectoryPoint = new TrajectoryPoint(world, firstVoidShell.translate(direction), direction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (WarpDriveConfig.LOGGING_ACCELERATOR) {
|
||||
WarpDrive.logger.info("First one is " + trajectoryPoint);
|
||||
}
|
||||
if (trajectoryPoint == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scan all connected void shells
|
||||
trajectoryAccelerator = new HashMap<>();
|
||||
trajectoryTransfer = new HashMap<>();
|
||||
|
||||
HashSet<TrajectoryPoint> acceleratorToAdd = new HashSet<>();
|
||||
acceleratorToAdd.add(trajectoryPoint.clone());
|
||||
trajectoryPoint = new TrajectoryPoint(world, trajectoryPoint.translate(trajectoryPoint.directionBackward), trajectoryPoint.directionBackward);
|
||||
acceleratorToAdd.add(trajectoryPoint);
|
||||
|
||||
HashSet<TrajectoryPoint> transferToAdd = new HashSet<>();
|
||||
while(!acceleratorToAdd.isEmpty()) {
|
||||
// add all accelerators found
|
||||
for (TrajectoryPoint trajectoryToAdd : acceleratorToAdd) {
|
||||
trajectoryPoint = trajectoryToAdd;
|
||||
while ( trajectoryPoint.hasNoMissingVoidShells()
|
||||
&& isInRange(trajectoryPoint)
|
||||
&& !trajectoryAccelerator.containsKey(trajectoryPoint)) {
|
||||
if (WarpDriveConfig.LOGGING_ACCELERATOR) {
|
||||
WarpDrive.logger.info("Adding accelerator " + trajectoryPoint);
|
||||
}
|
||||
TrajectoryPoint trajectoryPointToAdd = trajectoryPoint.clone();
|
||||
trajectoryAccelerator.put(trajectoryPointToAdd, trajectoryPointToAdd);
|
||||
if (trajectoryPoint.vJunctionForward != null) {
|
||||
transferToAdd.add(new TrajectoryPoint(world, trajectoryPoint, true));
|
||||
}
|
||||
if (trajectoryPoint.vJunctionBackward != null) {
|
||||
transferToAdd.add(new TrajectoryPoint(world, trajectoryPoint, false));
|
||||
}
|
||||
trajectoryPoint = new TrajectoryPoint(world, trajectoryPoint.translate(trajectoryPoint.directionForward), trajectoryPoint.directionForward);
|
||||
}
|
||||
}
|
||||
acceleratorToAdd.clear();
|
||||
|
||||
// add all transfer found
|
||||
for (TrajectoryPoint trajectoryToAdd : transferToAdd) {
|
||||
trajectoryPoint = trajectoryToAdd;
|
||||
while ( trajectoryPoint.hasNoMissingVoidShells()
|
||||
&& isInRange(trajectoryPoint)
|
||||
&& !trajectoryTransfer.containsKey(trajectoryPoint)
|
||||
&& !trajectoryPoint.needsReevaluation()) {
|
||||
if (WarpDriveConfig.LOGGING_ACCELERATOR) {
|
||||
WarpDrive.logger.info("Adding transfer " + trajectoryPoint);
|
||||
}
|
||||
TrajectoryPoint trajectoryPointToAdd = trajectoryPoint.clone();
|
||||
trajectoryTransfer.put(trajectoryPointToAdd, trajectoryPointToAdd);
|
||||
trajectoryPoint = new TrajectoryPoint(world, trajectoryPoint, true);
|
||||
}
|
||||
if (trajectoryPoint.needsReevaluation()) {
|
||||
// rebuild as an accelerator point from the next one forward
|
||||
trajectoryPoint = new TrajectoryPoint(world, trajectoryPoint.translate(trajectoryPoint.directionForward), trajectoryPoint.directionForward);
|
||||
acceleratorToAdd.add(trajectoryPoint.clone());
|
||||
// also go backward in case it's broken
|
||||
trajectoryPoint = new TrajectoryPoint(world, trajectoryPoint.translate(trajectoryPoint.directionBackward), trajectoryPoint.directionBackward);
|
||||
acceleratorToAdd.add(trajectoryPoint);
|
||||
}
|
||||
}
|
||||
transferToAdd.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInRange(final TrajectoryPoint trajectoryPoint) {
|
||||
double distanceSquared = trajectoryPoint.distance2To(new VectorI(x, y, z));
|
||||
return distanceSquared <= ACCELERATOR_MAX_RANGE_SQUARED;
|
||||
}
|
||||
|
||||
private void computeCountsAndBoundingBox() {
|
||||
boolean isFirst = true;
|
||||
for (TrajectoryPoint trajectoryPoint : trajectoryAccelerator.values()) {
|
||||
// check bounding area
|
||||
if (isFirst) {
|
||||
vMin = trajectoryPoint.getVectorI();
|
||||
vMax = trajectoryPoint.getVectorI();
|
||||
isFirst = false;
|
||||
}
|
||||
addToBoundingBox(trajectoryPoint);
|
||||
|
||||
// count main magnets
|
||||
int indexTier = trajectoryPoint.type & TrajectoryPoint.MASK_TIERS - 1;
|
||||
if ((trajectoryPoint.type & TrajectoryPoint.MAGNETS_HORIZONTAL) != 0) {
|
||||
countMagnets[indexTier] += 2;
|
||||
}
|
||||
if ((trajectoryPoint.type & TrajectoryPoint.MAGNETS_VERTICAL) != 0) {
|
||||
countMagnets[indexTier] += 2;
|
||||
}
|
||||
|
||||
// count input/output magnets
|
||||
if ((trajectoryPoint.type & TrajectoryPoint.MASK_IS_INPUT) != 0 && indexTier > 0) {
|
||||
countMagnets[indexTier - 1] += 12;
|
||||
}
|
||||
if ((trajectoryPoint.type & TrajectoryPoint.MASK_IS_OUTPUT) != 0 && indexTier < 2) {
|
||||
countMagnets[indexTier + 1] += 12;
|
||||
}
|
||||
}
|
||||
WarpDrive.logger.info("Bounding box is " + vMin + " to " + vMax);
|
||||
}
|
||||
|
||||
private void computeVectorArrays(WorldServer world) {
|
||||
// check for chillers, injectors and colliders blocks
|
||||
for (TrajectoryPoint trajectoryPoint : trajectoryAccelerator.values()) {
|
||||
// check for injectors
|
||||
VectorI vectorToAdd = trajectoryPoint.clone(trajectoryPoint.directionForward.getOpposite());
|
||||
Block blockForward = vectorToAdd.getBlock(world);
|
||||
if (blockForward instanceof BlockParticlesInjector) {
|
||||
final int controlChannel = ((TileEntityParticlesInjector) vectorToAdd.getTileEntity(world)).getControlChannel();
|
||||
mapInjectors.put(controlChannel, vectorToAdd);
|
||||
addToBoundingBox(vectorToAdd);
|
||||
} else {
|
||||
vectorToAdd = trajectoryPoint.clone(trajectoryPoint.directionBackward.getOpposite());
|
||||
Block blockBackward = vectorToAdd.getBlock(world);
|
||||
if (blockBackward instanceof BlockParticlesInjector) {
|
||||
final int controlChannel = ((TileEntityParticlesInjector) vectorToAdd.getTileEntity(world)).getControlChannel();
|
||||
mapInjectors.put(controlChannel, vectorToAdd);
|
||||
addToBoundingBox(vectorToAdd);
|
||||
}
|
||||
}
|
||||
|
||||
// collect control points and colliders
|
||||
if (trajectoryPoint.vControlPoint != null) {
|
||||
controlPoints.put(trajectoryPoint.vControlPoint, trajectoryPoint.type);
|
||||
addToBoundingBox(trajectoryPoint.vControlPoint);
|
||||
if (trajectoryPoint.isCollider()) {
|
||||
listColliders.add(trajectoryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
// check corners when there's at least 1 set of main magnets and no control point
|
||||
if (trajectoryPoint.vControlPoint == null && (trajectoryPoint.type & TrajectoryPoint.MASK_MAGNETS_BOTH) != 0) {
|
||||
scanCorners(world, trajectoryPoint, trajectoryPoint.directionForward);
|
||||
if (trajectoryPoint.directionForward != trajectoryPoint.directionBackward.getOpposite()) {
|
||||
scanCorners(world, trajectoryPoint, trajectoryPoint.directionBackward);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void scanCorners(WorldServer world, final VectorI vCenter, final ForgeDirection forgeDirection) {
|
||||
ForgeDirection directionLeft = forgeDirection.getRotation(ForgeDirection.UP);
|
||||
ForgeDirection directionRight = forgeDirection.getRotation(ForgeDirection.DOWN);
|
||||
for (int indexCorner = 0; indexCorner < 4; indexCorner++) {
|
||||
VectorI vector = new VectorI(
|
||||
vCenter.x + ((indexCorner & 1) != 0 ? directionLeft.offsetX : directionRight.offsetX),
|
||||
vCenter.y + ((indexCorner & 2) != 0 ? 1 : -1),
|
||||
vCenter.z + ((indexCorner & 1) != 0 ? directionLeft.offsetZ : directionRight.offsetZ));
|
||||
Block block = vector.getBlock(world);
|
||||
if (block instanceof BlockChiller) {
|
||||
chillers.put(vector, ((BlockChiller)block).tier);
|
||||
countChillers[((BlockChiller)block).tier - 1]++;
|
||||
} else if (block instanceof BlockEnergyBank) {
|
||||
TileEntity tileEntity = vector.getTileEntity(world);
|
||||
if (tileEntity instanceof TileEntityEnergyBank) {
|
||||
energyBanks.add((TileEntityEnergyBank) tileEntity);
|
||||
} else {
|
||||
WarpDrive.logger.error("Invalid tile entity detected for energy bank at " + vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getMass() {
|
||||
if (trajectoryAccelerator == null) {
|
||||
return 0;
|
||||
}
|
||||
return trajectoryAccelerator.size() + trajectoryTransfer.size() + energyBanks.size() + controlPoints.size()
|
||||
+ countMagnets[0] + countMagnets[1] + countMagnets[2]
|
||||
+ countChillers[0] + countChillers[1] + countChillers[2];
|
||||
}
|
||||
|
||||
public boolean isMajorChange(final AcceleratorSetup acceleratorSetup) {
|
||||
return trajectoryAccelerator.size() != acceleratorSetup.trajectoryAccelerator.size()
|
||||
|| trajectoryTransfer.size() != acceleratorSetup.trajectoryTransfer.size()
|
||||
|| countMagnets[0] != acceleratorSetup.countMagnets[0]
|
||||
|| countMagnets[1] != acceleratorSetup.countMagnets[1]
|
||||
|| countMagnets[2] != acceleratorSetup.countMagnets[2]
|
||||
|| countChillers[0] != acceleratorSetup.countChillers[0]
|
||||
|| countChillers[1] != acceleratorSetup.countChillers[1]
|
||||
|| countChillers[2] != acceleratorSetup.countChillers[2];
|
||||
}
|
||||
|
||||
public boolean isBlockUpdated(World world, final VectorI vector, final Block block) {
|
||||
boolean checkDirectConnection = false;
|
||||
boolean checkRangedConnection = false;
|
||||
boolean checkCornerConnection = false;
|
||||
// check explicit inclusions
|
||||
if (block instanceof BlockChiller) {
|
||||
if (chillers.containsKey(vector)) {
|
||||
return true;
|
||||
}
|
||||
checkCornerConnection = true;
|
||||
|
||||
} else if (block instanceof BlockVoidShellPlain) {
|
||||
if (isTrajectoryPoint(vector)) {
|
||||
return true;
|
||||
}
|
||||
checkDirectConnection = true;
|
||||
|
||||
} else if (block instanceof BlockParticlesInjector) {
|
||||
checkDirectConnection = true;
|
||||
|
||||
} else if (block instanceof BlockElectromagnetPlain) {
|
||||
checkDirectConnection = true;
|
||||
checkCornerConnection = true;
|
||||
|
||||
} else if (block instanceof BlockParticlesCollider) {
|
||||
checkCornerConnection = true;
|
||||
|
||||
} else if (block instanceof BlockAcceleratorControlPoint) {
|
||||
checkRangedConnection = true;
|
||||
|
||||
} else if (block instanceof BlockEnergyBank) {
|
||||
TileEntity tileEntity = vector.getTileEntity(world);
|
||||
if (tileEntity instanceof TileEntityEnergyBank) {
|
||||
if (energyBanks.contains(tileEntity)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
checkCornerConnection = true;
|
||||
}
|
||||
|
||||
// check connections
|
||||
if (checkDirectConnection || checkCornerConnection) {
|
||||
for (ForgeDirection forgeDirection : ForgeDirection.VALID_DIRECTIONS) {
|
||||
Block blockConnected = vector.translate(forgeDirection).getBlock(world);
|
||||
if (blockConnected instanceof BlockVoidShellPlain) {
|
||||
if (isTrajectoryPoint(vector)) {
|
||||
return true;
|
||||
}
|
||||
} else if (checkCornerConnection && blockConnected instanceof BlockElectromagnetPlain) {
|
||||
for (ForgeDirection forgeDirection2 : ForgeDirection.VALID_DIRECTIONS) {
|
||||
Block blockSubConnected = vector.translate(forgeDirection2).getBlock(world);
|
||||
if (blockSubConnected instanceof BlockVoidShellPlain) {
|
||||
if (isTrajectoryPoint(vector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (checkRangedConnection) {
|
||||
for (ForgeDirection forgeDirection : ForgeDirection.VALID_DIRECTIONS) {
|
||||
Block blockConnected = vector.translate(forgeDirection, 2).getBlock(world);
|
||||
if (blockConnected instanceof BlockVoidShellPlain) {
|
||||
if (isTrajectoryPoint(vector)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTrajectoryPoint(final VectorI vectorI) {
|
||||
return trajectoryAccelerator.containsKey(vectorI) || trajectoryTransfer.containsKey(vectorI);
|
||||
}
|
||||
|
||||
public TrajectoryPoint getTrajectoryPoint(final VectorI vectorI) {
|
||||
TrajectoryPoint trajectoryPoint = trajectoryAccelerator.get(vectorI);
|
||||
if (trajectoryPoint != null) {
|
||||
return trajectoryPoint;
|
||||
}
|
||||
return trajectoryTransfer.get(vectorI);
|
||||
}
|
||||
|
||||
public AxisAlignedBB getBoundingBox() {
|
||||
if (vMin == null || vMax == null) {
|
||||
return null;
|
||||
}
|
||||
return AxisAlignedBB.getBoundingBox(
|
||||
vMin.x, vMin.y, vMin.z,
|
||||
vMax.x, vMax.y, vMax.z);
|
||||
}
|
||||
|
||||
// sanity check
|
||||
public boolean isValid() {
|
||||
if (trajectoryAccelerator == null) {
|
||||
return false;
|
||||
}
|
||||
for(TileEntityEnergyBank tileEntityEnergyBank : energyBanks) {
|
||||
if (tileEntityEnergyBank.isInvalid()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Pseudo-API for energy
|
||||
public int energy_getEnergyStored() {
|
||||
int energyStored = 0;
|
||||
for(TileEntityEnergyBank tileEntityEnergyBank : energyBanks) {
|
||||
energyStored += tileEntityEnergyBank.energy_getEnergyStored();
|
||||
}
|
||||
return energyStored;
|
||||
}
|
||||
|
||||
public int energy_getPotentialOutput() {
|
||||
long potentialOutput = 0;
|
||||
for(TileEntityEnergyBank tileEntityEnergyBank : energyBanks) {
|
||||
potentialOutput = Math.min(potentialOutput + tileEntityEnergyBank.energy_getPotentialOutput(), Integer.MAX_VALUE);
|
||||
}
|
||||
return (int) potentialOutput;
|
||||
}
|
||||
|
||||
public int energy_getMaxStorage() {
|
||||
return energy_maxStorage;
|
||||
}
|
||||
|
||||
public void energy_consume(final int amount_internal) {
|
||||
// first, draw average from all
|
||||
final int energyMean = amount_internal / energyBanks.size();
|
||||
int energyConsumed = 0;
|
||||
int energyLeft = amount_internal - energyMean * energyBanks.size();
|
||||
assert(energyConsumed + energyLeft == amount_internal);
|
||||
for(TileEntityEnergyBank tileEntityEnergyBank : energyBanks) {
|
||||
final int energyToConsume = Math.min(tileEntityEnergyBank.energy_getPotentialOutput(), energyMean + energyLeft);
|
||||
tileEntityEnergyBank.energy_consume(energyToConsume);
|
||||
energyConsumed += energyToConsume;
|
||||
energyLeft += (energyMean - energyConsumed);
|
||||
}
|
||||
assert(energyConsumed + energyLeft == amount_internal);
|
||||
// then, draw remaining in no special order
|
||||
if (energyLeft > 0) {
|
||||
for(TileEntityEnergyBank tileEntityEnergyBank : energyBanks) {
|
||||
final int energyToConsume = Math.min(tileEntityEnergyBank.energy_getPotentialOutput(), energyLeft);
|
||||
tileEntityEnergyBank.energy_consume(energyToConsume);
|
||||
energyConsumed += energyToConsume;
|
||||
energyLeft -= energyConsumed;
|
||||
}
|
||||
}
|
||||
assert(energyConsumed == amount_internal);
|
||||
assert(energyLeft == 0);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (vMin == null || vMax == null) {
|
||||
return String.format("%s @ DIM%d (%d %d %d) (-null-) -> (-null)",
|
||||
getClass().getSimpleName(), dimensionId,
|
||||
x, y, z);
|
||||
}
|
||||
return String.format("%s @ DIM%d (%d %d %d) (%d %d %d) -> (%d %d %d)",
|
||||
getClass().getSimpleName(), dimensionId,
|
||||
x, y, z,
|
||||
vMin.x, vMin.y, vMin.z,
|
||||
vMax.x, vMax.y, vMax.z);
|
||||
}
|
||||
}
|
670
src/main/java/cr0s/warpdrive/data/TrajectoryPoint.java
Normal file
670
src/main/java/cr0s/warpdrive/data/TrajectoryPoint.java
Normal file
|
@ -0,0 +1,670 @@
|
|||
package cr0s.warpdrive.data;
|
||||
|
||||
import cr0s.warpdrive.block.atomic.BlockAcceleratorControlPoint;
|
||||
import cr0s.warpdrive.block.atomic.BlockElectromagnetPlain;
|
||||
import cr0s.warpdrive.block.atomic.BlockParticlesCollider;
|
||||
import cr0s.warpdrive.block.atomic.BlockParticlesInjector;
|
||||
import cr0s.warpdrive.block.atomic.BlockVoidShellPlain;
|
||||
import cr0s.warpdrive.block.atomic.TileEntityAcceleratorControlPoint;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
/**
|
||||
* @author LemADEC
|
||||
*/
|
||||
public class TrajectoryPoint extends VectorI {
|
||||
|
||||
// 'type' is a bit-mask to cache surrounding blocks
|
||||
public static final int NO_TYPE = 0x00000000;
|
||||
public static final int TIER_NORMAL = 0x00000001;
|
||||
public static final int TIER_ADVANCED = 0x00000002;
|
||||
public static final int TIER_SUPERIOR = 0x00000003;
|
||||
public static final int MASK_TIERS = 0x00000003;
|
||||
public static final int MAGNETS_HORIZONTAL = 0x00000004;
|
||||
public static final int MAGNETS_VERTICAL = 0x00000008;
|
||||
public static final int MASK_MAGNETS_BOTH = 0x0000000C;
|
||||
|
||||
public static final int IS_INPUT_FORWARD = 0x00000010;
|
||||
public static final int IS_INPUT_BACKWARD = 0x00000020;
|
||||
public static final int MASK_IS_INPUT = 0x00000030;
|
||||
public static final int IS_OUTPUT_FORWARD = 0x00000040;
|
||||
public static final int IS_OUTPUT_BACKWARD = 0x00000080;
|
||||
public static final int MASK_IS_OUTPUT = 0x000000C0;
|
||||
|
||||
public static final int IS_COLLIDER = 0x00000100;
|
||||
public static final int IS_TRANSFER_PIPE = 0x00000200;
|
||||
public static final int NEEDS_REEVALUATION = 0x00000400;
|
||||
// reserved 0x00000800
|
||||
// reserved 0x00001000
|
||||
// reserved 0x00002000
|
||||
// reserved 0x00004000
|
||||
// reserved 0x00008000
|
||||
public static final int ERROR_NONE = 0x00000000;
|
||||
public static final int ERROR_DOUBLE_JUNCTION = 0x00010000; // invalid void shell (double junction)
|
||||
public static final int ERROR_VERTICAL_JUNCTION = 0x00020000; // invalid void shell (vertical movement)
|
||||
public static final int ERROR_MISSING_TURNING_MAGNET = 0x00040000; // missing main magnets at turning point
|
||||
public static final int ERROR_MISSING_MAIN_MAGNET = 0x00080000; // missing main magnets at control point
|
||||
public static final int ERROR_MISSING_CORNER_MAGNET = 0x00100000; // missing corner magnets at control point
|
||||
public static final int ERROR_MISSING_COLLIDER = 0x00200000;
|
||||
public static final int ERROR_MISSING_VOID_SHELL = 0x00400000; // too many void shells
|
||||
public static final int ERROR_TOO_MANY_VOID_SHELLS = 0x00800000; // not enough void shells
|
||||
// public static final int ERROR_OUT_OF_RANGE = 0x01000000;
|
||||
// public static final int ERROR_TBD2 = 0x02000000;
|
||||
// public static final int ERROR_TBD4 = 0x04000000;
|
||||
// public static final int ERROR_TBD8 = 0x08000000;
|
||||
// public static final int ERROR_TBD10 = 0x10000000;
|
||||
// public static final int ERROR_TBD20 = 0x20000000;
|
||||
// public static final int ERROR_TBD40 = 0x40000000;
|
||||
// public static final int ERROR_TBD80 = 0x80000000;
|
||||
public static final int MASK_ERRORS = 0xFFFF0000;
|
||||
|
||||
public final int type;
|
||||
|
||||
public final VectorI vControlPoint;
|
||||
public final int controlChannel;
|
||||
|
||||
// next block direction in positive movement
|
||||
public final ForgeDirection directionForward;
|
||||
public final ForgeDirection directionBackward;
|
||||
public final VectorI vJunctionForward;
|
||||
public final VectorI vJunctionBackward;
|
||||
|
||||
public TrajectoryPoint(World world, final VectorI vPosition, final ForgeDirection directionForward) {
|
||||
this(world, vPosition.x, vPosition.y, vPosition.z, directionForward);
|
||||
}
|
||||
|
||||
public TrajectoryPoint(final int x, final int y, final int z,
|
||||
final int type,
|
||||
final VectorI vControlPoint,
|
||||
final int controlChannel,
|
||||
final ForgeDirection directionForward,
|
||||
final ForgeDirection directionBackward,
|
||||
final VectorI vJunctionForward,
|
||||
final VectorI vJunctionBackward) {
|
||||
super(x, y, z);
|
||||
this.type = type;
|
||||
this.vControlPoint = vControlPoint;
|
||||
this.controlChannel = controlChannel;
|
||||
this.directionForward = directionForward;
|
||||
this.directionBackward = directionBackward;
|
||||
this.vJunctionForward = vJunctionForward;
|
||||
this.vJunctionBackward = vJunctionBackward;
|
||||
}
|
||||
|
||||
// get next point on an acceleration pipe
|
||||
private TrajectoryPoint(World world, final int x, final int y, final int z, final ForgeDirection directionMain) {
|
||||
super(x, y, z);
|
||||
int typeNew = NO_TYPE;
|
||||
|
||||
// check the core
|
||||
Block blockCore = world.getBlock(x, y , z);
|
||||
if (!(blockCore instanceof BlockVoidShellPlain)) {
|
||||
typeNew |= ERROR_MISSING_VOID_SHELL;
|
||||
}
|
||||
|
||||
// get main blocks
|
||||
ForgeDirection directionLeft = directionMain.getRotation(ForgeDirection.UP);
|
||||
ForgeDirection directionRight = directionMain.getRotation(ForgeDirection.DOWN);
|
||||
Block blockForward = world.getBlock(x + directionMain.offsetX, y, z + directionMain.offsetZ);
|
||||
Block blockUp = world.getBlock(x, y + 1, z);
|
||||
Block blockDown = world.getBlock(x, y - 1, z);
|
||||
Block blockLeft = world.getBlock(x + directionLeft .offsetX, y, z + directionLeft .offsetZ);
|
||||
Block blockRight = world.getBlock(x + directionRight.offsetX, y, z + directionRight.offsetZ);
|
||||
int tier = 0;
|
||||
|
||||
// check main magnets
|
||||
if (blockUp instanceof BlockElectromagnetPlain && blockDown instanceof BlockElectromagnetPlain) {
|
||||
int tierUp = ((BlockElectromagnetPlain) blockUp).tier;
|
||||
if (tierUp == ((BlockElectromagnetPlain) blockDown).tier) {
|
||||
tier = tier == 0 || tier == tierUp ? tierUp : -1;
|
||||
typeNew |= MAGNETS_VERTICAL;
|
||||
}
|
||||
}
|
||||
if (blockLeft instanceof BlockElectromagnetPlain && blockRight instanceof BlockElectromagnetPlain) {
|
||||
int tierLeft = ((BlockElectromagnetPlain) blockLeft).tier;
|
||||
if (tierLeft == ((BlockElectromagnetPlain) blockRight).tier) {
|
||||
tier = tier == 0 || tier == tierLeft ? tierLeft : -1;
|
||||
typeNew |= MAGNETS_HORIZONTAL;
|
||||
}
|
||||
}
|
||||
|
||||
// checking turning
|
||||
TurnEvaluator turnEvaluator = new TurnEvaluator(world, x, y, z, directionMain, typeNew,
|
||||
directionLeft, directionRight,
|
||||
blockForward, blockUp, blockDown, blockLeft, blockRight,
|
||||
tier);
|
||||
typeNew = turnEvaluator.typeNew;
|
||||
boolean isShellValid = turnEvaluator.isShellValid;
|
||||
boolean isTurning = turnEvaluator.isTurning;
|
||||
boolean isForward = turnEvaluator.isForward;
|
||||
directionForward = turnEvaluator.directionForward;
|
||||
directionBackward = turnEvaluator.directionBackward;
|
||||
|
||||
// check control point
|
||||
// (requires a valid shell and at least one set of main magnets)
|
||||
VectorI new_vControlPoint = null;
|
||||
int new_controlChannel = -1;
|
||||
if (isShellValid) {
|
||||
for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) {
|
||||
Block block = world.getBlock(
|
||||
x + 2 * direction.offsetX,
|
||||
y + 2 * direction.offsetY,
|
||||
z + 2 * direction.offsetZ);
|
||||
if (block instanceof BlockAcceleratorControlPoint && !(block instanceof BlockParticlesInjector)) {
|
||||
if ((typeNew & MASK_MAGNETS_BOTH) == 0) {
|
||||
typeNew |= ERROR_MISSING_MAIN_MAGNET;
|
||||
} else {
|
||||
new_vControlPoint = new VectorI(
|
||||
x + 2 * direction.offsetX,
|
||||
y + 2 * direction.offsetY,
|
||||
z + 2 * direction.offsetZ);
|
||||
new_controlChannel = ((TileEntityAcceleratorControlPoint) new_vControlPoint.getTileEntity(world)).getControlChannel();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vControlPoint = new_vControlPoint;
|
||||
controlChannel = new_controlChannel;
|
||||
|
||||
// evaluate 3x3x3 blocks centered here
|
||||
boolean isInput = false;
|
||||
boolean isOutput = false;
|
||||
if (isShellValid) {
|
||||
NodeEvaluator nodeEvaluator = new NodeEvaluator(world, x, y, z, typeNew, tier, isTurning);
|
||||
// report errors found
|
||||
typeNew = nodeEvaluator.typeNew;
|
||||
|
||||
// require control node for collider and output
|
||||
if (nodeEvaluator.isCollider && vControlPoint != null) {
|
||||
typeNew |= IS_COLLIDER;
|
||||
}
|
||||
|
||||
// require control node for output
|
||||
isOutput = nodeEvaluator.isOutput && vControlPoint != null;
|
||||
|
||||
// no control node required for input
|
||||
isInput = nodeEvaluator.isInput;
|
||||
}
|
||||
|
||||
// compute junction vectors
|
||||
if (!isInput && !isOutput) {
|
||||
vJunctionBackward = null;
|
||||
vJunctionForward = null;
|
||||
} else {
|
||||
if (isTurning) {
|
||||
if (isForward) {
|
||||
typeNew |= isInput ? IS_INPUT_FORWARD : IS_OUTPUT_FORWARD;
|
||||
vJunctionBackward = null;
|
||||
vJunctionForward = new VectorI(directionMain);
|
||||
} else {
|
||||
typeNew |= isInput ? IS_INPUT_BACKWARD : IS_OUTPUT_BACKWARD;
|
||||
vJunctionForward = null;
|
||||
if (directionForward == directionRight) {
|
||||
vJunctionBackward = new VectorI(directionLeft);
|
||||
} else {
|
||||
vJunctionBackward = new VectorI(directionRight);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
typeNew |= isInput ? IS_INPUT_FORWARD : IS_OUTPUT_FORWARD; // @TODO code review, probably inverted somewhere
|
||||
Block blockForwardLeft = world.getBlock(
|
||||
x + directionMain.offsetX + directionLeft.offsetX,
|
||||
y,
|
||||
z + directionMain.offsetZ + directionLeft.offsetZ);
|
||||
Block blockForwardRight = world.getBlock(
|
||||
x + directionMain.offsetX + directionRight.offsetX,
|
||||
y,
|
||||
z + directionMain.offsetZ + directionRight.offsetZ);
|
||||
Block blockBackwardLeft = world.getBlock(
|
||||
x - directionMain.offsetX + directionLeft.offsetX,
|
||||
y,
|
||||
z - directionMain.offsetZ + directionLeft.offsetZ);
|
||||
Block blockBackwardRight = world.getBlock(
|
||||
x - directionMain.offsetX + directionRight.offsetX,
|
||||
y,
|
||||
z - directionMain.offsetZ + directionRight.offsetZ);
|
||||
if (blockForwardLeft instanceof BlockVoidShellPlain) {
|
||||
typeNew |= isInput ? IS_INPUT_FORWARD : IS_OUTPUT_FORWARD;
|
||||
vJunctionForward = new VectorI(directionLeft).translate(directionMain);
|
||||
if (blockBackwardLeft instanceof BlockVoidShellPlain) {
|
||||
typeNew |= isInput ? IS_INPUT_BACKWARD : IS_OUTPUT_BACKWARD;
|
||||
vJunctionBackward = new VectorI(directionLeft).translate(directionMain, -1);
|
||||
} else {
|
||||
vJunctionBackward = null;
|
||||
}
|
||||
} else if (blockForwardRight instanceof BlockVoidShellPlain) {
|
||||
typeNew |= isInput ? IS_INPUT_FORWARD : IS_OUTPUT_FORWARD;
|
||||
vJunctionForward = new VectorI(directionRight).translate(directionMain);
|
||||
if (blockBackwardRight instanceof BlockVoidShellPlain) {
|
||||
typeNew |= isInput ? IS_INPUT_BACKWARD : IS_OUTPUT_BACKWARD;
|
||||
vJunctionBackward = new VectorI(directionRight).translate(directionMain, -1);
|
||||
} else {
|
||||
vJunctionBackward = null;
|
||||
}
|
||||
} else {
|
||||
vJunctionForward = null;
|
||||
if (blockBackwardLeft instanceof BlockVoidShellPlain) {
|
||||
typeNew |= isInput ? IS_INPUT_BACKWARD : IS_OUTPUT_BACKWARD;
|
||||
vJunctionBackward = new VectorI(directionLeft).translate(directionMain, -1);
|
||||
} else if (blockBackwardRight instanceof BlockVoidShellPlain) {
|
||||
typeNew |= isInput ? IS_INPUT_BACKWARD : IS_OUTPUT_BACKWARD;
|
||||
vJunctionBackward = new VectorI(directionRight).translate(directionMain, -1);
|
||||
} else {
|
||||
vJunctionBackward = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// save the results
|
||||
if (tier == 1) {
|
||||
typeNew |= TIER_NORMAL;
|
||||
} else if (tier == 2) {
|
||||
typeNew |= TIER_ADVANCED;
|
||||
} else if (tier == 3) {
|
||||
typeNew |= TIER_SUPERIOR;
|
||||
}
|
||||
type = typeNew;
|
||||
}
|
||||
|
||||
// get next point on a transfer pipe
|
||||
public TrajectoryPoint(World world, final TrajectoryPoint trajectoryPoint, final boolean isForward) {
|
||||
int typeNew = IS_TRANSFER_PIPE;
|
||||
// get first/next transfer pipe
|
||||
this.x = trajectoryPoint.x + (isForward ? trajectoryPoint.vJunctionForward.x : trajectoryPoint.vJunctionBackward.x);
|
||||
this.y = trajectoryPoint.y + (isForward ? trajectoryPoint.vJunctionForward.y : trajectoryPoint.vJunctionBackward.y);
|
||||
this.z = trajectoryPoint.z + (isForward ? trajectoryPoint.vJunctionForward.z : trajectoryPoint.vJunctionBackward.z);
|
||||
// adjust to forward orientation
|
||||
this.directionForward = isForward ? trajectoryPoint.directionBackward.getOpposite() : trajectoryPoint.directionForward.getOpposite();
|
||||
this.directionBackward = directionForward.getOpposite();
|
||||
this.vJunctionForward = isForward ? trajectoryPoint.vJunctionForward : trajectoryPoint.vJunctionBackward;
|
||||
this.vJunctionBackward = null;
|
||||
// get expected tier
|
||||
int tier = (trajectoryPoint.type & MASK_TIERS)
|
||||
+ (((trajectoryPoint.type & MASK_IS_INPUT ) != 0) ? -1 : 0)
|
||||
+ (((trajectoryPoint.type & MASK_IS_OUTPUT) != 0) ? 1 : 0);
|
||||
if (tier <= 0 || tier > 3) {
|
||||
tier = 0;
|
||||
}
|
||||
|
||||
// check support shells
|
||||
boolean isStraightLine = (vJunctionForward.x == -directionBackward.offsetX) && (vJunctionForward.z == -directionBackward.offsetZ);
|
||||
Block blockForward = world.getBlock(x + vJunctionForward.x, y, z + vJunctionForward.z);
|
||||
Block blockBack = world.getBlock(x + directionBackward.offsetX, y, z + directionBackward.offsetZ);
|
||||
Block blockUp = world.getBlock(x, y + 1, z);
|
||||
Block blockDown = world.getBlock(x, y - 1, z);
|
||||
|
||||
// check main magnets to trigger node evaluation
|
||||
// (up and down magnets should have same tier, but different from current one)
|
||||
boolean hasVerticalMagnets = false;
|
||||
if (blockUp instanceof BlockElectromagnetPlain && blockDown instanceof BlockElectromagnetPlain) {
|
||||
int tierUp = ((BlockElectromagnetPlain) blockUp).tier;
|
||||
if (tierUp == ((BlockElectromagnetPlain) blockDown).tier) {
|
||||
hasVerticalMagnets = tier == tierUp;
|
||||
}
|
||||
}
|
||||
|
||||
// check forward movement
|
||||
boolean isForwardOk = blockForward instanceof BlockVoidShellPlain;
|
||||
boolean isBackOk = blockBack instanceof BlockVoidShellPlain;
|
||||
boolean isShellValid = !(blockUp instanceof BlockVoidShellPlain) // no vertical transfer
|
||||
&& !(blockDown instanceof BlockVoidShellPlain) // no vertical transfer
|
||||
&& isForwardOk && isBackOk && tier != 0;
|
||||
if (blockUp instanceof BlockVoidShellPlain || blockDown instanceof BlockVoidShellPlain) {
|
||||
typeNew |= ERROR_VERTICAL_JUNCTION;
|
||||
}
|
||||
if (!isForwardOk || !isBackOk) {
|
||||
typeNew |= ERROR_MISSING_VOID_SHELL;
|
||||
}
|
||||
|
||||
// assuming it's a transfer node, we need to check if the void shells are turning
|
||||
boolean isTurning = false;
|
||||
if (hasVerticalMagnets) {
|
||||
// when transfer line is at 45deg, we can't input/output in a turning corner, so we skip that case
|
||||
if (isStraightLine) {
|
||||
// we just do a basic check of void shells, the full validation of magnets is done in the node evaluator
|
||||
ForgeDirection directionMain = directionBackward.getOpposite();
|
||||
ForgeDirection directionLeft = directionMain.getRotation(ForgeDirection.UP);
|
||||
ForgeDirection directionRight = directionMain.getRotation(ForgeDirection.DOWN);
|
||||
Block blockLeft = world.getBlock(x + directionLeft .offsetX, y, z + directionLeft .offsetZ);
|
||||
Block blockRight = world.getBlock(x + directionRight.offsetX, y, z + directionRight.offsetZ);
|
||||
isTurning = blockLeft instanceof BlockVoidShellPlain || blockRight instanceof BlockVoidShellPlain;
|
||||
}
|
||||
}
|
||||
|
||||
// ignore control point
|
||||
vControlPoint = null;
|
||||
controlChannel = -1;
|
||||
|
||||
// look for an input or output node
|
||||
if (isShellValid && hasVerticalMagnets) {
|
||||
NodeEvaluator nodeEvaluator = new NodeEvaluator(world, x, y, z, typeNew, tier, isTurning);
|
||||
typeNew = nodeEvaluator.typeNew;
|
||||
if (nodeEvaluator.isInput || nodeEvaluator.isOutput) {
|
||||
// it's a transfer node, mark it for re-evaluation
|
||||
typeNew |= NEEDS_REEVALUATION;
|
||||
}
|
||||
}
|
||||
|
||||
// save the results
|
||||
if (tier == 1) {
|
||||
typeNew |= TIER_NORMAL;
|
||||
} else if (tier == 2) {
|
||||
typeNew |= TIER_ADVANCED;
|
||||
} else if (tier == 3) {
|
||||
typeNew |= TIER_SUPERIOR;
|
||||
}
|
||||
type = typeNew;
|
||||
}
|
||||
|
||||
public boolean needsReevaluation() { return (type & NEEDS_REEVALUATION) != 0; }
|
||||
|
||||
public boolean hasNoMissingVoidShells() {
|
||||
return (type & ERROR_MISSING_VOID_SHELL) == 0;
|
||||
}
|
||||
|
||||
public int getTier() {
|
||||
switch (type & MASK_TIERS) {
|
||||
case TIER_NORMAL: return 1;
|
||||
case TIER_ADVANCED: return 2;
|
||||
case TIER_SUPERIOR: return 3;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMagnetsCount() {
|
||||
switch (type & (MASK_MAGNETS_BOTH | MASK_ERRORS)) {
|
||||
case MAGNETS_HORIZONTAL: return 1;
|
||||
case MAGNETS_VERTICAL: return 1;
|
||||
case MASK_MAGNETS_BOTH: return 2;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTransferPipe() {
|
||||
return (type & IS_TRANSFER_PIPE) != 0;
|
||||
}
|
||||
|
||||
public boolean isCollider() {
|
||||
return (type & IS_COLLIDER) != 0;
|
||||
}
|
||||
|
||||
public Vector3 getJunctionOut(final ForgeDirection directionCurrent) {
|
||||
// skip erroneous setup
|
||||
if ((type & MASK_ERRORS) != ERROR_NONE) {
|
||||
return null;
|
||||
}
|
||||
// output while moving forward (i.e. while coming opposite of backward)
|
||||
if (((type & IS_OUTPUT_FORWARD) != 0) && directionCurrent.getOpposite().equals(directionBackward)) {
|
||||
return new Vector3(vJunctionForward.x, vJunctionForward.y, vJunctionForward.z).normalize();
|
||||
}
|
||||
// output while moving backward (i.e. while coming opposite of forward)
|
||||
if (((type & IS_OUTPUT_BACKWARD) != 0) && directionCurrent.getOpposite().equals(directionForward)) {
|
||||
return new Vector3(vJunctionBackward.x, vJunctionBackward.y, vJunctionBackward.z).normalize();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ForgeDirection getTurnedDirection(final ForgeDirection directionCurrent) {
|
||||
// skip erroneous setup
|
||||
if ((type & ERROR_MISSING_TURNING_MAGNET) != ERROR_NONE) {
|
||||
return null;
|
||||
}
|
||||
// skip straight line
|
||||
if (directionForward.getOpposite().equals(directionBackward)) {
|
||||
return null;
|
||||
}
|
||||
// turn forward
|
||||
if (directionCurrent.equals(directionForward.getOpposite())) {
|
||||
return directionBackward;
|
||||
}
|
||||
// turn backward
|
||||
if (directionCurrent.equals(directionBackward.getOpposite())) {
|
||||
return directionForward;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ForgeDirection getJunctionIn(final Vector3 vectorCurrent) {
|
||||
// skip erroneous setup
|
||||
if ((type & MASK_ERRORS) != ERROR_NONE) {
|
||||
return null;
|
||||
}
|
||||
// skip non-junction
|
||||
if ((type & MASK_IS_INPUT) == 0) {
|
||||
return null;
|
||||
}
|
||||
VectorI vJunctionRequired = new VectorI(
|
||||
(int) -Math.signum(vectorCurrent.x),
|
||||
(int) -Math.signum(vectorCurrent.y),
|
||||
(int) -Math.signum(vectorCurrent.z));
|
||||
// input in forward motion
|
||||
if ( ((type & IS_INPUT_FORWARD) != 0) && vJunctionRequired.equals(vJunctionBackward) ) {
|
||||
return directionForward;
|
||||
}
|
||||
// input in backward motion
|
||||
if (((type & IS_INPUT_BACKWARD) != 0) && vJunctionRequired.equals(vJunctionBackward)) {
|
||||
return directionBackward;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrajectoryPoint clone() {
|
||||
return new TrajectoryPoint(x, y, z, type, vControlPoint, controlChannel, directionForward, directionBackward, vJunctionForward, vJunctionBackward);
|
||||
}
|
||||
|
||||
public VectorI getVectorI() {
|
||||
return new VectorI(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (object instanceof VectorI) {
|
||||
VectorI vector = (VectorI) object;
|
||||
return (x == vector.x) && (y == vector.y) && (z == vector.z);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("TrajectoryPoint [%d %d %d] %8x %5s %5s %s %s %s tier%d %s",
|
||||
x, y, z,
|
||||
type,
|
||||
directionForward == null ? "-null-" : directionForward.toString(),
|
||||
directionBackward == null ? "-null-" : directionBackward.toString(),
|
||||
vJunctionForward == null ? "-null-" : vJunctionForward.toString(),
|
||||
vJunctionBackward == null ? "-null-" : vJunctionBackward.toString(),
|
||||
vControlPoint == null ? "-null-" : vControlPoint.toString(),
|
||||
type & MASK_TIERS,
|
||||
hasNoMissingVoidShells());
|
||||
}
|
||||
|
||||
// validate a accelerator node
|
||||
private class NodeEvaluator {
|
||||
|
||||
public int typeNew;
|
||||
public boolean isCollider;
|
||||
public boolean isInput;
|
||||
public boolean isOutput;
|
||||
|
||||
public NodeEvaluator(World world, final int x, final int y, final int z, final int typeOriginal, final int tierMain, final boolean isTurning) {
|
||||
typeNew = typeOriginal;
|
||||
isInput = false;
|
||||
isOutput = false;
|
||||
|
||||
// all 8 corners are always present, but can be glass or plain, so we can't check strict block equality
|
||||
int countVoidShell = 0;
|
||||
int countMainMagnet = 0;
|
||||
int countLowerMagnet = 0;
|
||||
int countHigherMagnet = 0;
|
||||
int countCollider = 0;
|
||||
for (int offsetX = -1; offsetX < 2; offsetX++) {
|
||||
for (int offsetY = -1; offsetY < 2; offsetY++) {
|
||||
for (int offsetZ = -1; offsetZ < 2; offsetZ++) {
|
||||
Block blockCheck = world.getBlock(
|
||||
x + offsetX,
|
||||
y + offsetY,
|
||||
z + offsetZ);
|
||||
if (blockCheck instanceof BlockElectromagnetPlain) {
|
||||
int tierCheck = ((BlockElectromagnetPlain) blockCheck).tier;
|
||||
if (tierCheck == tierMain) {
|
||||
countMainMagnet++;
|
||||
} else if (tierCheck > tierMain) {
|
||||
countHigherMagnet++;
|
||||
} else {
|
||||
countLowerMagnet++;
|
||||
}
|
||||
} else if (blockCheck instanceof BlockVoidShellPlain) {
|
||||
countVoidShell++;
|
||||
} else if (blockCheck instanceof BlockParticlesCollider) {
|
||||
countCollider++;
|
||||
} else if (blockCheck instanceof BlockParticlesInjector) {
|
||||
int tierCheck = ((BlockParticlesInjector) blockCheck).tier;
|
||||
if (tierCheck == tierMain) {
|
||||
countMainMagnet++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check collider
|
||||
// (we can be in between 2 colliders, so we need at least 9 to report an error)
|
||||
if (countCollider > 8) {
|
||||
if (countCollider < 12) {// need at least 12 collider blocks
|
||||
typeNew |= ERROR_MISSING_COLLIDER;
|
||||
} else if (countVoidShell < 3) {// need exactly 3 void shells
|
||||
typeNew |= ERROR_MISSING_VOID_SHELL;
|
||||
} else if (countVoidShell > 3) {// need exactly 3 void shells
|
||||
typeNew |= ERROR_TOO_MANY_VOID_SHELLS;
|
||||
} else if (countMainMagnet < 12) {
|
||||
typeNew |= ERROR_MISSING_MAIN_MAGNET;
|
||||
} else {
|
||||
isCollider = true;
|
||||
}
|
||||
}
|
||||
if (countLowerMagnet > 8 || countHigherMagnet > 8) {
|
||||
if (countLowerMagnet < 12 && countHigherMagnet < 12) {// need at least 12 corner magnets
|
||||
typeNew |= ERROR_MISSING_CORNER_MAGNET;
|
||||
} else if (countLowerMagnet != 0 && countHigherMagnet != 0) {// only one type of corner magnets
|
||||
typeNew |= ERROR_MISSING_CORNER_MAGNET;
|
||||
} else if (isTurning && countVoidShell < 4) {// a turning junction requires 4 void shells
|
||||
typeNew |= ERROR_MISSING_VOID_SHELL;
|
||||
} else if (isTurning && countVoidShell > 4) {// a turning junction requires 4 void shells
|
||||
typeNew |= ERROR_TOO_MANY_VOID_SHELLS;
|
||||
} else if ((!isTurning) && countVoidShell < 5) {// a straight junction requires at least 5 void shells
|
||||
typeNew |= ERROR_MISSING_VOID_SHELL;
|
||||
} else if ((!isTurning) && countVoidShell > 6) {// a straight junction requires at most 6 void shells
|
||||
typeNew |= ERROR_TOO_MANY_VOID_SHELLS;
|
||||
} else if (countMainMagnet < 9) {// at 9 main magnets
|
||||
typeNew |= ERROR_MISSING_MAIN_MAGNET;
|
||||
} else if (countVoidShell + countMainMagnet != 15) {// exactly 15 void shells + main magnets
|
||||
typeNew |= ERROR_MISSING_MAIN_MAGNET;
|
||||
} else {
|
||||
isInput = countLowerMagnet > 0;
|
||||
isOutput = countHigherMagnet > 0;
|
||||
assert(isInput || isOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TurnEvaluator {
|
||||
|
||||
public int typeNew;
|
||||
public boolean isForward;
|
||||
public boolean isShellValid;
|
||||
public boolean isTurning;
|
||||
public ForgeDirection directionForward;
|
||||
public ForgeDirection directionBackward;
|
||||
|
||||
public TurnEvaluator(World world, final int x, final int y, final int z, final ForgeDirection directionMain, final int typeOriginal,
|
||||
final ForgeDirection directionLeft, final ForgeDirection directionRight,
|
||||
final Block blockForward, final Block blockUp, final Block blockDown, final Block blockLeft, final Block blockRight,
|
||||
final int tier) {
|
||||
this.typeNew = typeOriginal;
|
||||
|
||||
// check turning magnets
|
||||
isForward = blockForward instanceof BlockVoidShellPlain;
|
||||
boolean isLeftTurn = blockLeft instanceof BlockVoidShellPlain;
|
||||
boolean isRightTurn = blockRight instanceof BlockVoidShellPlain;
|
||||
// boolean isJunction = (isForward && (isLeftTurn || isRightTurn)) || (isLeftTurn && isRightTurn);
|
||||
isShellValid = !(blockUp instanceof BlockVoidShellPlain) // no vertical accelerators
|
||||
&& !(blockDown instanceof BlockVoidShellPlain) // no vertical accelerators
|
||||
&& (!isForward || !isLeftTurn || !isRightTurn);
|
||||
// boolean isShellEnding = (!isForward && !isLeftTurn && !isRightTurn); // dead end
|
||||
if (blockUp instanceof BlockVoidShellPlain || blockDown instanceof BlockVoidShellPlain) {
|
||||
typeNew |= ERROR_VERTICAL_JUNCTION;
|
||||
}
|
||||
if (isForward && isLeftTurn && isRightTurn) {
|
||||
typeNew |= ERROR_DOUBLE_JUNCTION;
|
||||
}
|
||||
isTurning = false;
|
||||
if (isShellValid && (isLeftTurn || isRightTurn)) {
|
||||
// validate the turning magnets
|
||||
Block blockForwardLeft = world.getBlock(
|
||||
x + directionMain.offsetX + directionLeft.offsetX,
|
||||
y,
|
||||
z + directionMain.offsetZ + directionLeft.offsetZ);
|
||||
Block blockForwardRight = world.getBlock(
|
||||
x + directionMain.offsetX + directionRight.offsetX,
|
||||
y,
|
||||
z + directionMain.offsetZ + directionRight.offsetZ);
|
||||
Block blockBackwardLeft = world.getBlock(
|
||||
x - directionMain.offsetX + directionLeft.offsetX,
|
||||
y,
|
||||
z - directionMain.offsetZ + directionLeft.offsetZ);
|
||||
Block blockBackwardRight = world.getBlock(
|
||||
x - directionMain.offsetX + directionRight.offsetX,
|
||||
y,
|
||||
z - directionMain.offsetZ + directionRight.offsetZ);
|
||||
if ( tier > 0
|
||||
&& blockForwardLeft instanceof BlockElectromagnetPlain && tier == ((BlockElectromagnetPlain) blockForwardLeft ).tier
|
||||
&& blockForwardRight instanceof BlockElectromagnetPlain && tier == ((BlockElectromagnetPlain) blockForwardRight ).tier
|
||||
&& blockBackwardLeft instanceof BlockElectromagnetPlain && tier == ((BlockElectromagnetPlain) blockBackwardLeft ).tier
|
||||
&& blockBackwardRight instanceof BlockElectromagnetPlain && tier == ((BlockElectromagnetPlain) blockBackwardRight).tier
|
||||
&& ((typeNew & MAGNETS_VERTICAL) == MAGNETS_VERTICAL) ) {
|
||||
// also validate the sided magnet
|
||||
isTurning = (isForward || blockForward instanceof BlockElectromagnetPlain || blockForward instanceof BlockParticlesInjector)
|
||||
&& (isLeftTurn || blockLeft instanceof BlockElectromagnetPlain || blockLeft instanceof BlockParticlesInjector)
|
||||
&& (isRightTurn || blockRight instanceof BlockElectromagnetPlain || blockRight instanceof BlockParticlesInjector);
|
||||
}
|
||||
if (!isTurning) {
|
||||
// check if another void shell is present on the turn side, in which case we assume it's an input/output area
|
||||
// otherwise, it's a missing turning magnet
|
||||
if (!( isLeftTurn && (blockBackwardLeft instanceof BlockVoidShellPlain || blockForwardLeft instanceof BlockVoidShellPlain)
|
||||
|| isRightTurn && (blockBackwardRight instanceof BlockVoidShellPlain || blockForwardRight instanceof BlockVoidShellPlain) ) ) {
|
||||
typeNew |= ERROR_MISSING_TURNING_MAGNET;
|
||||
}
|
||||
}
|
||||
}
|
||||
// compute forward vector
|
||||
if (!isTurning && (typeNew & ERROR_MISSING_TURNING_MAGNET) == 0) {
|
||||
directionForward = directionMain;
|
||||
} else if (isLeftTurn && !isRightTurn) {
|
||||
directionForward = directionLeft;
|
||||
} else if (!isLeftTurn && isRightTurn) {
|
||||
directionForward = directionRight;
|
||||
} else {
|
||||
assert(isLeftTurn && isRightTurn);
|
||||
// it's probably an input/output, in that case, magnets are all around, just pick one side to detect the direction
|
||||
Block blockUpRight = world.getBlock(x + directionRight.offsetX, y + 1, z + directionRight.offsetZ);
|
||||
if (blockUpRight instanceof BlockElectromagnetPlain && tier != ((BlockElectromagnetPlain) blockUpRight).tier) {
|
||||
directionForward = directionLeft;
|
||||
} else {
|
||||
directionForward = directionRight;
|
||||
}
|
||||
}
|
||||
// backward vector is where we came from
|
||||
directionBackward = directionMain.getOpposite();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue