/* This file is part of Project-Zed. Project-Zed is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Project-Zed is * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along * with Project-Zed. If not, see <http://www.gnu.org/licenses/> */ package com.projectzed.mod.tileentity.generator; import com.hockeyhurd.hcorelib.api.block.AbstractHCoreBlock; import com.hockeyhurd.hcorelib.api.math.Vector3; import com.hockeyhurd.hcorelib.api.math.VectorHelper; import com.hockeyhurd.hcorelib.api.util.BlockUtils; import com.hockeyhurd.hcorelib.api.util.SidedHelper; import com.projectzed.api.block.AbstractBlockNuclearComponent; import com.projectzed.api.block.IMetaUpdate; import com.projectzed.api.energy.source.EnumType; import com.projectzed.api.energy.source.Source; import com.projectzed.api.heat.HeatLogic; import com.projectzed.api.heat.IHeatable; import com.projectzed.api.tileentity.IMultiBlockable; import com.projectzed.api.tileentity.IMultiBlockableController; import com.projectzed.api.tileentity.generator.AbstractTileEntityGenerator; import com.projectzed.mod.ProjectZed; import com.projectzed.mod.handler.PacketHandler; import com.projectzed.mod.handler.message.MessageTileEntityGenerator; import com.projectzed.mod.handler.message.MessageTileEntityNuclearController; import com.projectzed.mod.registry.CoolantRegistry; import com.projectzed.mod.tileentity.TileEntityNuclearControlPort; import com.projectzed.mod.tileentity.container.TileEntityNuclearIOPort; import com.projectzed.mod.util.Coolant; import com.projectzed.mod.util.Reference; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import net.minecraftforge.fluids.BlockFluidBase; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Class used to calculate and generate power through * nuclear fission/fusion. * * @author hockeyhurd * @version Nov 24, 2014 */ public class TileEntityNuclearController extends AbstractTileEntityGenerator implements IMultiBlockableController<AbstractTileEntityGenerator>, IHeatable { /** Variable tracking whether to use fusion or fission. */ private boolean fusionMode; private boolean poweredLastUpdate = false; private boolean poweredThisUpdate = false; @SideOnly(Side.CLIENT) private int burnTime; private int lastStored; private byte placeDir, size, rel; private boolean isMaster, hasMaster; private Vector3<Integer> masterVec = Vector3.zero.getVector3i(); private Vector3<Integer> minVec = Vector3.zero.getVector3i(); private Vector3<Integer> maxVec = Vector3.zero.getVector3i(); private HashMap<Block, Integer> mbMap; private HashMap<Block, List<Vector3<Integer>>> mbMapVec; private List<Coolant> coolantList; private TileEntityNuclearIOPort inputPort, outputPort; private HeatLogic heatLogic; public TileEntityNuclearController() { super("nuclearController"); this.maxStored = (int) 1e8; heatLogic = new HeatLogic(2500, 0.05f); // heatLogic = new HeatLogic(2500000, 0.05f); } @Override public HeatLogic getHeatLogic() { return heatLogic; } @Override public boolean isOverheated() { return heatLogic.getHeat() == heatLogic.getMaxHeat(); } /** * Sets direction of placed nuclear controller. * * @param dir direction. * @param size expected size of chamber. * @param rel relative size. */ public void setPlaceDir(byte dir, byte size, byte rel) { this.placeDir = dir; this.size = size; this.rel = rel; heatLogic.setMaxHeat(HeatLogic.getHeatFromValues(maxStored, getReactorVolume())); } /** * Gets the reactor's current volume. * * @return Integer volume of nuclear reactor. */ public int getReactorVolume() { return size * size * size; } /** * @return placed direction. */ public byte getPlaceDir() { return this.placeDir; } /** * @return expected chamber size. */ public byte getChamberSize() { return this.size; } @Override public int getSizeInventory() { return 0; } @Override public int getInventoryStackLimit() { return 0; } @Override protected void initContentsArray() { } @Override protected void initSlotsArray() { } @Override public boolean isItemValidForSlot(int slot, ItemStack stack) { return false; } @Override public int[] getSlotsForFace(EnumFacing side) { return null; } @Override public boolean canInsertItem(int slot, ItemStack stack, EnumFacing side) { return false; } @Override public boolean canExtractItem(int slot, ItemStack stack, EnumFacing side) { return false; } @Override public void defineSource() { this.source = new Source(EnumType.FISSION); } /** * Handles setting the proper source of this te. * @param type type of source. */ public void setSource(EnumType type) { setSource(type, 1.0f); } /** * Handles setting the proper source of this te. * @param type type of source. * @param modifier modifier amount to offset energy output. */ public void setSource(EnumType type, float modifier) { this.source = new Source(type, modifier); } @Override public boolean canProducePower() { if (worldObj.isRemote) return false; return checkMultiBlockForm() && checkCorners(); } /** * Gets the burn time of the reactor. * <br><bold>NOTE: </bold>This is side dependent. * * @return Int burn time left in the reactor. */ public int getBurnTime() { final boolean isServer = SidedHelper.isServer(); return isServer && inputPort != null ? inputPort.getBurnTime() : !isServer ? burnTime : 0; } /** * Sets the burn time in the client. * * @param burnTime Int burn time to set. */ @SideOnly(Side.CLIENT) public void setBurnTime(int burnTime) { this.burnTime = burnTime; } /** * Function to check if size of multiblock structure is valid. * * @return true if valid, else returns false. */ private boolean isSizeValid() { return this.size >= 3 && this.size <= 9; } /** * Get the counter map of all blocks. * * @return mapping. */ public HashMap<Block, Integer> getMap() { return mbMap; } /** * Get the vector map of all blocks. * * @return mapping. */ public HashMap<Block, List<Vector3<Integer>>> getMapVec() { return mbMapVec; } @Override public void generatePower() { // if (poweredLastUpdate && this.stored + this.source.getEffectiveSize() <= this.maxStored && inputPort.getBurnTime() > 0) { if (poweredLastUpdate && inputPort.getBurnTime() > 0) { final int preStored = this.stored; // int anmoutToGen = HeatLogic.getEnergyFromTemp(heatLogic.getHeat(), getReactorVolume()); int anmoutToGen = this.source.getEffectiveSize(); // anmoutToGen = Math.min(anmoutToGen, source.getEffectiveSize()); // ProjectZed.logHelper.info("anmoutToGen:", anmoutToGen, "Current Heat:", heatLogic.getHeat()); // if (this.stored + this.source.getEffectiveSize() <= this.maxStored) this.stored += this.source.getEffectiveSize(); if (this.stored + anmoutToGen <= this.maxStored) this.stored += anmoutToGen; else this.stored = this.maxStored; // if (preStored < this.stored) heatLogic.update(true, this.stored, this.getChamberSize()); // else heatLogic.update(false, this.stored, this.getChamberSize()); // heatLogic.update(preStored < this.stored, this.stored, this.getChamberSize()); heatLogic.update(preStored < this.stored, this.stored - this.lastStored, this.getReactorVolume()); this.lastStored = this.stored; } if (this.stored > this.maxStored) this.stored = this.maxStored; // Redundancy check. } /** * Gets the 'first' input nuclear io part in mapping. * * @return nuclear io port object if found, else returns false. */ private TileEntityNuclearIOPort getInputDataFromIO() { TileEntityNuclearIOPort te = null; if (mbMapVec != null && mbMapVec.size() > 0 && mbMapVec.containsKey(ProjectZed.nuclearIOPort)) { for (Vector3<Integer> vec : mbMapVec.get(ProjectZed.nuclearIOPort)) { // byte meta = (byte) worldObj.getBlockMetadata(vec.x, vec.y, vec.z); int meta = BlockUtils.getBlockMetadata(worldObj, vec); // it is input! final TileEntity tileEntity = worldObj.getTileEntity(VectorHelper.toBlockPos(vec)); if (meta == 1 && tileEntity instanceof TileEntityNuclearIOPort) { te = (TileEntityNuclearIOPort) tileEntity; break; } } } return te; } /** * Gets the 'first' ouput nuclear io part in mapping. * * @return nuclear io port object if found, else returns false. */ private TileEntityNuclearIOPort getOutputDataFromIO() { TileEntityNuclearIOPort te = null; if (mbMapVec != null && mbMapVec.size() > 0 && mbMapVec.containsKey(ProjectZed.nuclearIOPort)) { for (Vector3<Integer> vec : mbMapVec.get(ProjectZed.nuclearIOPort)) { // byte meta = (byte) worldObj.getBlockMetadata(vec.x, vec.y, vec.z); int meta = BlockUtils.getBlockMetadata(worldObj, vec); final TileEntity tileEntity = worldObj.getTileEntity(VectorHelper.toBlockPos(vec)); if (meta == 2 && tileEntity instanceof TileEntityNuclearIOPort) { te = (TileEntityNuclearIOPort) tileEntity; break; } } } return te; } /** * Checks and consumes input port fuel. * * @param controlPort flag whether control port is appropriately set. * @return true if successful, else returns false. */ public boolean checksAndConsumptions(boolean controlPort) { return inputPort != null && poweredLastUpdate && controlPort && this.stored < this.maxStored && inputPort.runCycle(outputPort); /*boolean flag = false; if (inputPort != null) flag = poweredLastUpdate && controlPort && this.stored < this.maxStored && inputPort.runCycle(outputPort); return flag;*/ } /** * Checks the coolants in the reactor and reports data to the HeatLogic system * if successful, else if an error has occured, we will return 'FALSE'. * * @return True if successful, else may return false. */ public boolean checkFluids() { // If no fluids, something went wrong... if (coolantList == null || coolantList.isEmpty()) return false; // Only 1 coolant, makes life easier! else if (coolantList.size() == 1) { final float effectiveEfficiency = coolantList.get(0).getEffectiveEfficiency(size, size, size, 1); heatLogic.setResistance(effectiveEfficiency); } // We'll see what we can do... else { // For now, we will just go with the lowest efficiency coolant. // TODO: Implement variable efficiency based on percentages of coolants. float lowestEff = Float.MAX_VALUE; for (Coolant coolant : coolantList) { float currentEff = coolant.getEffectiveEfficiency(size, size, size, 1); if (currentEff < lowestEff) lowestEff = currentEff; } heatLogic.setResistance(lowestEff); } return true; } /** * Method to handle cooling of Nuclear Reactor. */ public void doCooling() { if (worldObj.isRemote || worldObj.getTotalWorldTime() % 5 != 0) return; // Used to 'slow cooling process' final int dif = stored - lastStored; heatLogic.update(powerMode, dif != 0 ? dif : -1, getReactorVolume()); } @Override public void update() { if (this.worldObj != null && !this.worldObj.isRemote) { // Small, yet significant optimization to call checking of multiblock structure 1/sec instead of 20/sec. if (this.worldObj.getTotalWorldTime() % 20L == 0) { inputPort = getInputDataFromIO(); if (inputPort == null) return; outputPort = getOutputDataFromIO(); poweredLastUpdate = canProducePower(); } // if (inputPort == null) return; final boolean controlPort = checkControlPort(); final boolean consumptions = checksAndConsumptions(controlPort); final boolean checkFluids = checkFluids(); // if (coolantList != null && !coolantList.isEmpty()) ProjectZed.logHelper.info(coolantList.size()); // if (coolantList != null && !coolantList.isEmpty()) ProjectZed.logHelper.info(coolantList.get(0).getAmount()); if (this.worldObj.getTotalWorldTime() % 20L == 0 && poweredThisUpdate != poweredLastUpdate) resetStructure(); poweredThisUpdate = poweredLastUpdate; this.powerMode = inputPort != null && inputPort.getBurnTime() > 0; if (this.powerMode && controlPort) { generatePower(); inputPort.tickBurnTime(); } // Machine is off! else if (!this.powerMode) doCooling(); PacketHandler.INSTANCE.sendToAll(new MessageTileEntityGenerator(this)); PacketHandler.INSTANCE.sendToAll(new MessageTileEntityNuclearController(this)); this.markDirty(); // if (this.worldObj.getTotalWorldTime() % 20L == 0) ProjectZed.logHelper.info("Heat:", heatLogic.getHeat()); // ProjectZed.logHelper.info("Max heat:", heatLogic.getMaxHeat()); } } @Override public void readNBT(NBTTagCompound comp) { super.readNBT(comp); this.lastStored = this.stored; byte dir = comp.getByte("ProjectZedNuclearDir"); this.placeDir = (byte) (dir >= 0 && dir < 6 ? dir : this.getBlockMetadata()); byte rel = comp.getByte("ProjectZedNuclearRel"); this.rel = rel > -5 && rel < 5 ? rel : 0; byte size = comp.getByte("ProjectZedNuclearSize"); this.size = size > 0 && size <= 9 ? size : 0; // multiblock stuffs: isMaster = comp.getBoolean("ProjectZedIsMaster"); hasMaster = comp.getBoolean("ProjectZedHasMaster"); if (masterVec == null) masterVec = Vector3.zero.getVector3i(); masterVec.x = comp.getInteger("ProjectZedMasterX"); masterVec.y = comp.getInteger("ProjectZedMasterY"); masterVec.z = comp.getInteger("ProjectZedMasterZ"); heatLogic.readNBT(comp); } @Override public void saveNBT(NBTTagCompound comp) { super.saveNBT(comp); this.lastStored = this.stored; comp.setByte("ProjectZedNuclearDir", this.placeDir); comp.setByte("ProjectZedNuclearRel", this.rel); comp.setByte("ProjectZedNuclearSize", this.size); // multiblock stuffs: comp.setBoolean("ProjectZedIsMaster", isMaster); comp.setBoolean("ProjectZedHasMaster", hasMaster); comp.setInteger("ProjectZedMasterX", masterVec.x); comp.setInteger("ProjectZedMasterY", masterVec.y); comp.setInteger("ProjectZedMasterZ", masterVec.z); heatLogic.saveNBT(comp); } /*@Override public Packet getDescriptionPacket() { super.getDescriptionPacket(); return PacketHandler.INSTANCE.getPacketFrom(new MessageTileEntityNuclearController(this)); }*/ @Override public NBTTagCompound getUpdateTag() { final NBTTagCompound comp = super.getUpdateTag(); saveNBT(comp); return comp; } /** * Simple getter function to check whether the control rod permits energy generation. * * @return true if permittable, else returns false. */ private boolean checkControlPort() { boolean flag = true; if (mbMapVec != null && mbMapVec.size() > 0 && mbMapVec.containsKey(ProjectZed.nuclearControlPort)) { Vector3<Integer> vec = mbMapVec.get(ProjectZed.nuclearControlPort).get(0); TileEntityNuclearControlPort te = (TileEntityNuclearControlPort) worldObj.getTileEntity(VectorHelper.toBlockPos(vec)); if (te != null && te.hasRedstoneSignal()) flag = false; } return flag; } @Override public AbstractTileEntityGenerator getInstance() { return this; } @Override public AbstractHCoreBlock getBlock() { return (AbstractHCoreBlock) (!this.fusionMode ? ProjectZed.fissionController : ProjectZed.fusionController); } /** * Function to create a fake instance of IMultiBlockable TE. * * @param block block to reference. * @return object if valid, else returns false. */ private IMultiBlockable<?> createFakeTE(Block block) { IMultiBlockable<?> mb = null; if (block != null && block != Blocks.AIR && block instanceof AbstractBlockNuclearComponent) { if (((AbstractBlockNuclearComponent) block).getTileEntity() instanceof IMultiBlockable<?>) { mb = (IMultiBlockable<?>) ((AbstractBlockNuclearComponent) block).getTileEntity(); } } return mb; } /** * Function to check if reference mappings match expected mappings. * * @param ref reference map with number of TE's. * @param refVec reference map with coordinate of each TE. * @return true if mapping is valid, else returns false. */ private boolean isMappingValid(HashMap<Block, Integer> ref, HashMap<Block, List<Vector3<Integer>>> refVec) { if (ref == null || ref.size() == 0 || this.size < 3 || refVec == null || refVec.size() == 0) return false; boolean flag = true; IMultiBlockable tile; for (Block b : ref.keySet()) { if (ref.containsKey(b) && refVec.containsKey(b)) { for (Vector3<Integer> vec : refVec.get(b)) { tile = (IMultiBlockable) worldObj.getTileEntity(VectorHelper.toBlockPos(vec)); if (tile != null) { if (!tile.getMasterVec().x.equals(worldVec().x) || !tile.getMasterVec().y.equals(worldVec().y) || !tile.getMasterVec().z.equals(worldVec().z) || !tile.hasMaster()) { flag = false; break; } if (tile.isSubstitutable()) { boolean subListContained = false; int amount = 0; int maxTarget = Integer.MIN_VALUE; IMultiBlockable instance = null; for (int i = 0; i < tile.getSubList().size(); i++) { instance = (IMultiBlockable) tile.getSubList().get(i); if (instance != null && instance.getBlock() != null && ref.containsKey(instance.getBlock())) { subListContained = true; maxTarget = Math.max(maxTarget, instance.getAmountFromSize(size, size, size)); amount += ref.get(instance.getBlock()); } } // amount += tile.getAmountFromSize(size, size, size); amount += ref.get(b); if (!subListContained && maxTarget <= 0) { maxTarget = tile.getAmountFromSize(size, size, size); if (amount != maxTarget) { flag = false; break; } } else if (subListContained && maxTarget > 0) { maxTarget = Math.max(maxTarget, tile.getAmountFromSize(size, size, size)); if (amount != maxTarget) { flag = false; break; } } /*if (!subListContained || (amount != maxTarget && maxTarget > 0)) { flag = false; break; }*/ } else { if (tile.getAmountFromSize(size, size, size) != ref.get(b)) { flag = false; break; } } } } } if (!flag) break; } return flag; } @Override public boolean isUnique() { return true; } @Override public boolean isSubstitutable() { return false; } @Override public List<IMultiBlockable> getSubList() { return null; } @Override public int getAmountFromSize(int width, int height, int depth) { return 1; } @Override public boolean isMaster() { return isMaster; } @Override public void setIsMaster(boolean master) { this.isMaster = master; } @Override public boolean hasMaster() { return hasMaster; } @Override public void setHasMaster(boolean master) { this.hasMaster = master; } @Override public void setMasterVec(Vector3<Integer> vec) { this.masterVec = vec; } @Override public Vector3<Integer> getMasterVec() { return masterVec; } @Override public boolean checkMultiBlockForm() { boolean flag = false; if (!worldObj.isRemote) { // TODO: Remove lazy way of checking for all chamber locks, but will do for now. if (!isSizeValid()) return false; if (minVec == null) minVec = Vector3.zero.getVector3i(); if (maxVec == null) maxVec = Vector3.zero.getVector3i(); // int xp = this.xCoord - (placeDir == 1 ? 2 : (placeDir == 3 ? 0 : 1)); minVec.x = pos.getX() - (placeDir == 1 ? size - 1 : (placeDir == 3 ? 0 : size / 2)); minVec.y = pos.getY() + ((size - 1) / 2); // int zp = this.zCoord - (placeDir == 3 ? 1 : (placeDir == 2 ? 2 : (placeDir == 1 ? 1 : 0))); minVec.z = pos.getZ() - (placeDir == 3 ? size / 2 : (placeDir == 2 ? size - 1 : (placeDir == 1 ? size / 2 : 0))); maxVec.x = minVec.x + size - 1; maxVec.y = minVec.y - size + 1; maxVec.z = minVec.z + size - 1; int counterMaster = 0; Vector3<Integer> currentVec; BlockPos currentBlockPos; Block currentBlock; int counter = 0; if (mbMap == null) mbMap = new HashMap<Block, Integer>(); else if (!mbMap.isEmpty()) mbMap.clear(); if (mbMapVec == null) mbMapVec = new HashMap<Block, List<Vector3<Integer>>>(); else if (!mbMapVec.isEmpty()) mbMapVec.clear(); if (coolantList == null) coolantList = new ArrayList<Coolant>(Coolant.calculateChamberSize(size, size, size, 1)); else if (!coolantList.isEmpty()) coolantList.clear(); TileEntity te; Block b; Fluid fluid; /*if (ProjectZed.configHandler.isDebugMode()) { // System.out.println(size / 2 - 1); System.out.println(placeDir); System.out.println("1: (" + (minVec.x) + ", " + (minVec.y) + ", " + (minVec.z) + ")"); System.out.println("2: (" + (minVec.x + size - 1) + ", " + (minVec.y - size + 1) + ", " + (minVec.z + size - 1) + ")"); }*/ List<Vector3<Integer>> list; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { for (int z = 0; z < size; z++) { currentVec = new Vector3<Integer>(minVec.x + x, minVec.y - y, minVec.z + z); currentBlockPos = VectorHelper.toBlockPos(currentVec); // currentBlock = worldObj.getBlock(currentBlockPos); currentBlock = BlockUtils.getBlock(worldObj, currentBlockPos).getBlock(); // ProjectZed.logHelper.info(currentBlock.getUnlocalizedName()); if ( (y > 0 && y < size - 1) && (x > 0 && x < size - 1) && (z > 0 && z < size - 1) ) { if ( !((y == (size - 1) / 2) && (x == (size - 1) / 2) && (z == (size - 1) / 2)) ) { if (!(currentBlock instanceof BlockFluidBase) && !(currentBlock instanceof BlockLiquid) && currentBlock != Blocks.AIR) return false; // fluid = FluidRegistry.lookupFluidForBlock(currentBlock); // if (fluid != null && !coolantList.containsKey(fluid)) coolantList.put(fluid, false); // if (/*fluid == null*/ !coolantList.containsKey(fluid) && currentBlock != Blocks.air) return false; if (currentBlock instanceof BlockFluidBase) { fluid = ((BlockFluidBase) currentBlock).getFluid(); if (CoolantRegistry.instance().isFluidInRegistry(fluid)) { Coolant coolant = CoolantRegistry.instance().getCoolantByFluid(fluid); coolant.setAmount(Reference.Constants.MILLI_BUCKETS_PER_BLOCK_SPACE); if (coolantList.isEmpty()) coolantList.add(coolant); else { for (Coolant currentCoolant : coolantList) { if (currentCoolant.isFluidEqual(coolant)) { currentCoolant.addAmount(coolant.getAmount()); break; } } } } } // Typically water for lava in vanilla. else if (currentBlock instanceof BlockLiquid) { // If block is water, set fluid to water, else treat it like lava and watch it burn!!! fluid = currentBlock == Blocks.WATER ? FluidRegistry.WATER : FluidRegistry.LAVA; if (CoolantRegistry.instance().isFluidInRegistry(fluid)) { Coolant coolant = CoolantRegistry.instance().getCoolantByFluid(fluid); coolant.setAmount(Reference.Constants.MILLI_BUCKETS_PER_BLOCK_SPACE); if (coolantList.isEmpty()) coolantList.add(coolant); else { for (Coolant currentCoolant : coolantList) { if (currentCoolant.isFluidEqual(coolant)) { currentCoolant.addAmount(coolant.getAmount()); break; } } } } } // If block is air, deal with it! else if (currentBlock == Blocks.AIR) { Coolant airCoolant = Coolant.AIR; airCoolant.setAmount(Reference.Constants.MILLI_BUCKETS_PER_BLOCK_SPACE); if (coolantList.isEmpty()) coolantList.add(airCoolant); else { for (Coolant currentCoolant : coolantList) { if (currentCoolant.isFluidEqual(airCoolant)) { currentCoolant.addAmount(airCoolant.getAmount()); break; } } } } } } te = worldObj.getTileEntity(currentBlockPos); if (te != null && te instanceof IMultiBlockable && te.getBlockType() != null && te.getBlockType() != Blocks.AIR) { counter++; b = te.getBlockType(); if (!mbMap.containsKey(b)) mbMap.put(b, 1); else mbMap.put(b, mbMap.get(b) + 1); if (!mbMapVec.containsKey(b)) { list = new ArrayList<Vector3<Integer>>(); list.add(currentVec); mbMapVec.put(b, list); } else { list = mbMapVec.get(b); list.add(currentVec); mbMapVec.put(b, list); } if (/* !((IMultiBlockable) te).isMaster() && */!((IMultiBlockable) te).hasMaster()) { ((IMultiBlockable) te).setHasMaster(true); ((IMultiBlockable) te).setMasterVec(worldVec()); if (currentBlock != null && currentBlock instanceof IMetaUpdate) ((IMetaUpdate) currentBlock).updateMeta(poweredLastUpdate, worldObj, currentVec); } else if (((IMultiBlockable) te).isMaster()) counterMaster++; } } } } // ProjectZed.logHelper.info(counter, (size * size * size) - ((size - 2) * (size - 2) * (size - 2)) + 1); flag = isMappingValid(mbMap, mbMapVec) && counterMaster == 1 && counter == (size * size * size) - ((size - 2) * (size - 2) * (size - 2)) + 1; // ProjectZed.logHelper.info(counterMaster); // ProjectZed.logHelper.info(flag ? "working!" : "not working.."); } return flag; } private boolean checkCorners() { boolean flag = false; if (mbMapVec != null && mbMapVec.size() > 0 && mbMapVec.containsKey(ProjectZed.nuclearChamberLock) && mbMapVec.get(ProjectZed.nuclearChamberLock).size() > 0) { flag = true; IMultiBlockable current; for (Vector3<Integer> vec : mbMapVec.get(ProjectZed.nuclearChamberLock)) { if (vec.equals(minVec)) continue; else if (vec.equals(maxVec)) continue; else if (vec.y.equals(minVec.y) && vec.x.equals(minVec.x) && vec.z.equals(maxVec.z)) continue; else if (vec.y.equals(maxVec.y) && vec.x.equals(minVec.x) && vec.z.equals(maxVec.z)) continue; else if (vec.y.equals(minVec.y) && vec.x.equals(maxVec.x) && vec.z.equals(minVec.z)) continue; else if (vec.y.equals(maxVec.y) && vec.x.equals(maxVec.x) && vec.z.equals(minVec.z)) continue; else if (vec.y.equals(minVec.y) && vec.x.equals(maxVec.x) && vec.z.equals(maxVec.z)) continue; else if (vec.y.equals(maxVec.y) && vec.x.equals(minVec.x) && vec.z.equals(minVec.z)) continue; else { flag = false; break; } } } return flag; } @Override public boolean checkForMaster() { return this.isMaster; } @Override public void resetStructure() { if (mbMapVec != null && mbMapVec.size() > 0) { TileEntity te; for (Block b : mbMapVec.keySet()) { for (Vector3<Integer> vec : mbMapVec.get(b)) { te = worldObj.getTileEntity(VectorHelper.toBlockPos(vec)); if (te != null && te instanceof IMultiBlockable && !(te instanceof TileEntityNuclearController)) ((IMultiBlockable) te).reset(); } } } } @Override public void reset() { this.isMaster = false; this.hasMaster = false; this.masterVec = Vector3.zero.getVector3i(); } }