/* * This file is part of Applied Energistics 2. * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. * * Applied Energistics 2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Applied Energistics 2 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>. */ package appeng.me.cluster; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import appeng.api.util.AEPartLocation; import appeng.api.util.WorldCoord; import appeng.core.AELog; import appeng.util.Platform; public abstract class MBCalculator { private final IAEMultiBlock target; public MBCalculator( final IAEMultiBlock t ) { this.target = t; } public void calculateMultiblock( final World world, final WorldCoord loc ) { if( Platform.isClient() ) { return; } try { final WorldCoord min = loc.copy(); final WorldCoord max = loc.copy(); // find size of MB structure... while( this.isValidTileAt( world, min.x - 1, min.y, min.z ) ) { min.x--; } while( this.isValidTileAt( world, min.x, min.y - 1, min.z ) ) { min.y--; } while( this.isValidTileAt( world, min.x, min.y, min.z - 1 ) ) { min.z--; } while( this.isValidTileAt( world, max.x + 1, max.y, max.z ) ) { max.x++; } while( this.isValidTileAt( world, max.x, max.y + 1, max.z ) ) { max.y++; } while( this.isValidTileAt( world, max.x, max.y, max.z + 1 ) ) { max.z++; } if( this.checkMultiblockScale( min, max ) ) { if( this.verifyUnownedRegion( world, min, max ) ) { IAECluster c = this.createCluster( world, min, max ); try { if( !this.verifyInternalStructure( world, min, max ) ) { this.disconnect(); return; } } catch( final Exception err ) { this.disconnect(); return; } boolean updateGrid = false; final IAECluster cluster = this.target.getCluster(); if( cluster == null ) { this.updateTiles( c, world, min, max ); updateGrid = true; } else { c = cluster; } c.updateStatus( updateGrid ); return; } } } catch( final Throwable err ) { AELog.debug( err ); } this.disconnect(); } private boolean isValidTileAt( final World w, final int x, final int y, final int z ) { return this.isValidTile( w.getTileEntity( new BlockPos( x, y, z ) ) ); } /** * verify if the structure is the correct dimensions, or size * * @param min min world coord * @param max max world coord * * @return true if structure has correct dimensions or size */ public abstract boolean checkMultiblockScale( WorldCoord min, WorldCoord max ); private boolean verifyUnownedRegion( final World w, final WorldCoord min, final WorldCoord max ) { for( final AEPartLocation side : AEPartLocation.SIDE_LOCATIONS ) { if( this.verifyUnownedRegionInner( w, min.x, min.y, min.z, max.x, max.y, max.z, side ) ) { return false; } } return true; } /** * construct the correct cluster, usually very simple. * * @param w world * @param min min world coord * @param max max world coord * * @return created cluster */ public abstract IAECluster createCluster( World w, WorldCoord min, WorldCoord max ); public abstract boolean verifyInternalStructure( World worldObj, WorldCoord min, WorldCoord max ); /** * disassembles the multi-block. */ public abstract void disconnect(); /** * configure the multi-block tiles, most of the important stuff is in here. * * @param c updated cluster * @param w in world * @param min min world coord * @param max max world coord */ public abstract void updateTiles( IAECluster c, World w, WorldCoord min, WorldCoord max ); /** * check if the tile entities are correct for the structure. * * @param te to be checked tile entity * * @return true if tile entity is valid for structure */ public abstract boolean isValidTile( TileEntity te ); private boolean verifyUnownedRegionInner( final World w, int minX, int minY, int minZ, int maxX, int maxY, int maxZ, final AEPartLocation side ) { switch( side ) { case WEST: minX -= 1; maxX = minX; break; case EAST: maxX += 1; minX = maxX; break; case DOWN: minY -= 1; maxY = minY; break; case NORTH: maxZ += 1; minZ = maxZ; break; case SOUTH: minZ -= 1; maxZ = minZ; break; case UP: maxY += 1; minY = maxY; break; case INTERNAL: return false; } for( int x = minX; x <= maxX; x++ ) { for( int y = minY; y <= maxY; y++ ) { for( int z = minZ; z <= maxZ; z++ ) { final TileEntity te = w.getTileEntity( new BlockPos( x, y, z ) ); if( this.isValidTile( te ) ) { return true; } } } } return false; } }