package mcjty.rftools.blocks.spaceprojector;
import cpw.mods.fml.common.Optional;
import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral;
import li.cil.oc.api.machine.Arguments;
import li.cil.oc.api.machine.Callback;
import li.cil.oc.api.machine.Context;
import li.cil.oc.api.network.SimpleComponent;
import mcjty.lib.container.InventoryHelper;
import mcjty.lib.entity.GenericEnergyReceiverTileEntity;
import mcjty.lib.network.Argument;
import mcjty.lib.network.PacketRequestIntegerFromServer;
import mcjty.lib.varia.BlockMeta;
import mcjty.lib.varia.BlockTools;
import mcjty.lib.varia.Coordinate;
import mcjty.rftools.RFTools;
import mcjty.rftools.blocks.RFToolsTools;
import mcjty.rftools.blocks.teleporter.TeleportationTools;
import mcjty.rftools.items.ModItems;
import mcjty.rftools.items.shapecard.ShapeCardItem;
import mcjty.rftools.network.RFToolsMessages;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDynamicLiquid;
import net.minecraft.block.BlockStaticLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.FakePlayerFactory;
import net.minecraftforge.common.util.ForgeDirection;
import java.util.*;
@Optional.InterfaceList({
@Optional.Interface(iface = "li.cil.oc.api.network.SimpleComponent", modid = "OpenComputers"),
@Optional.Interface(iface = "dan200.computercraft.api.peripheral.IPeripheral", modid = "ComputerCraft")})
public class BuilderTileEntity extends GenericEnergyReceiverTileEntity implements ISidedInventory, SimpleComponent, IPeripheral {
public static final String COMPONENT_NAME = "builder";
public static final String CMD_SETMODE = "setMode";
public static final String CMD_SETANCHOR = "setAnchor";
public static final String CMD_SETROTATE = "setRotate";
public static final String CMD_SETSILENT = "setSilent";
public static final String CMD_SETSUPPORT = "setSupport";
public static final String CMD_SETENTITIES = "setEntities";
public static final String CMD_SETLOOP = "setLoop";
public static final String CMD_GETLEVEL = "getLevel";
public static final String CLIENTCMD_GETLEVEL = "getLevel";
private InventoryHelper inventoryHelper = new InventoryHelper(this, BuilderContainer.factory, 1);
public static final int MODE_COPY = 0;
public static final int MODE_MOVE = 1;
public static final int MODE_SWAP = 2;
public static final int MODE_BACK = 3;
public static final String[] MODES = new String[] { "Copy", "Move", "Swap", "Back" };
public static final String ROTATE_0 = "0";
public static final String ROTATE_90 = "90";
public static final String ROTATE_180 = "180";
public static final String ROTATE_270 = "270";
public static final int ANCHOR_SW = 0;
public static final int ANCHOR_SE = 1;
public static final int ANCHOR_NW = 2;
public static final int ANCHOR_NE = 3;
private int mode = MODE_COPY;
private int rotate = 0;
private int anchor = ANCHOR_SW;
private boolean silent = false;
private boolean supportMode = false;
private boolean entityMode = false;
private boolean loopMode = false;
// For usage in the gui
private static int currentLevel = 0;
private int powered = 0;
private boolean boxValid = false;
private Coordinate minBox = null;
private Coordinate maxBox = null;
private Coordinate scan = null;
private int projDx;
private int projDy;
private int projDz;
private int cardType = ShapeCardItem.CARD_UNKNOWN; // One of the card types out of ShapeCardItem.CARD_...
// For chunkloading with the quarry.
private ForgeChunkManager.Ticket ticket = null;
// The currently forced chunk.
private ChunkCoordIntPair forcedChunk = null;
// Cached set of blocks that we need to build in shaped mode
private Set<Coordinate> cachedBlocks = null;
private ChunkCoordIntPair cachedChunk = null; // For which chunk are the cachedBlocks valid
// Cached set of blocks that we want to void with the quarry.
private Set<Block> cachedVoidableBlocks = null;
public BuilderTileEntity() {
super(SpaceProjectorConfiguration.BUILDER_MAXENERGY, SpaceProjectorConfiguration.BUILDER_RECEIVEPERTICK);
}
@Override
@Optional.Method(modid = "ComputerCraft")
public String getType() {
return COMPONENT_NAME;
}
@Override
@Optional.Method(modid = "ComputerCraft")
public String[] getMethodNames() {
return new String[] { "hasCard", "getMode", "setMode", "getRotate", "setRotate", "getAnchor", "setAnchor", "getSupportMode", "setSupportMode", "getEntityMode", "setEntityMode",
"getLoopMode", "setLoopMode", "getScan" };
}
@Override
@Optional.Method(modid = "ComputerCraft")
public Object[] callMethod(IComputerAccess computer, ILuaContext context, int method, Object[] arguments) throws LuaException, InterruptedException {
switch (method) {
case 0: return new Object[] { hasCard() != null };
case 1: return new Object[] { getMode() };
case 2: setMode(((Double) arguments[0]).intValue()); return null;
case 3: return new Object[] { getRotate() };
case 4: setRotate(((Double) arguments[0]).intValue()); return null;
case 5: return new Object[] { getAnchor() };
case 6: setAnchor(((Double) arguments[0]).intValue()); return null;
case 7: return new Object[] { hasSupportMode() };
case 8: setSupportMode(((Double) arguments[0]).intValue() > 0); return null;
case 9: return new Object[] { hasEntityMode() };
case 10: setEntityMode(((Double) arguments[0]).intValue() > 0); return null;
case 11: return new Object[] { hasLoopMode() };
case 12: setLoopMode(((Double) arguments[0]).intValue() > 0); return null;
case 13: return scan == null ? null : new Object[] { scan.getX(), scan.getY(), scan.getZ() };
}
return new Object[0];
}
@Override
@Optional.Method(modid = "ComputerCraft")
public void attach(IComputerAccess computer) {
}
@Override
@Optional.Method(modid = "ComputerCraft")
public void detach(IComputerAccess computer) {
}
@Override
@Optional.Method(modid = "ComputerCraft")
public boolean equals(IPeripheral other) {
return false;
}
@Override
@Optional.Method(modid = "OpenComputers")
public String getComponentName() {
return COMPONENT_NAME;
}
@Callback(doc = "Return true if the builder has a shape or space card in it", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] hasCard(Context context, Arguments args) throws Exception {
return new Object[] { hasCard() != null };
}
@Callback(doc = "Get the current building mode (only useful in combination with a space card). Values are 0 (copy), 1 (move), 2 (swap), 3 (back)", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getMode(Context context, Arguments args) throws Exception {
return new Object[] { getMode() };
}
@Callback(doc = "Set the current building mode (only useful in combination with a space card). Values are 0 (copy), 1 (move), 2 (swap), 3 (back)", setter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] setMode(Context context, Arguments args) throws Exception {
int mode = args.checkInteger(0);
setMode(mode);
return null;
}
@Callback(doc = "Get the current rotation mode (only useful in combination with a space card). Values are 0 to 3 (increments of 90 degrees)", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getRotate(Context context, Arguments args) throws Exception {
return new Object[] { getRotate()};
}
@Callback(doc = "Set the current rotation mode (only useful in combination with a space card). Values are 0 to 3 (increments of 90 degrees)", setter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] setRotate(Context context, Arguments args) throws Exception {
Integer angle = args.checkInteger(0);
setRotate(angle);
return null;
}
@Callback(doc = "Get the current anchor mode (only useful in combination with a space card). Values are 0 (SW), 1 (SE), 2 (NW), 3 (NE)", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getAnchor(Context context, Arguments args) throws Exception {
return new Object[] { getAnchor()};
}
@Callback(doc = "Set the current anchor mode. In contrast with getAnchor() this also works with a shape card and it will reposition the shape before the builder. Values are 0 (SW), 1 (SE), 2 (NW), 3 (NE)", setter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] setAnchor(Context context, Arguments args) throws Exception {
Integer angle = args.checkInteger(0);
setAnchor(angle);
return null;
}
@Callback(doc = "Return true if support/preview mode is enabled", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getSupportMode(Context context, Arguments args) throws Exception {
return new Object[] { hasSupportMode()};
}
@Callback(doc = "Enable/disable support/preview mode", setter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] setSupportMode(Context context, Arguments args) throws Exception {
boolean support = args.checkBoolean(0);
setSupportMode(support);
return null;
}
@Callback(doc = "Return true if entity mode is enabled (entities are also moved). This is only useful in combination with a space card", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getEntityMode(Context context, Arguments args) throws Exception {
return new Object[] { hasEntityMode()};
}
@Callback(doc = "Enable/disable entity mode (entities are also moved). This is only useful in combination with a space card", setter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] setEntityMode(Context context, Arguments args) throws Exception {
boolean ent = args.checkBoolean(0);
setEntityMode(ent);
return null;
}
@Callback(doc = "Return true if loop mode is enabled. In this mode the builder will keep on working as long as it has a redstone signal", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getLoopMode(Context context, Arguments args) throws Exception {
return new Object[] { hasLoopMode()};
}
@Callback(doc = "Enable/disable loop mode. In this mode the builder will keep on working as long as it has a redstone signal", setter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] setLoopMode(Context context, Arguments args) throws Exception {
boolean ent = args.checkBoolean(0);
setLoopMode(ent);
return null;
}
@Callback(doc = "Return the current location where the builder is working", getter = true)
@Optional.Method(modid = "OpenComputers")
public Object[] getScan(Context context, Arguments args) throws Exception {
if (scan == null) {
return null;
}
Map<String,Integer> coordinate = new HashMap<String, Integer>();
coordinate.put("x", scan.getX());
coordinate.put("y", scan.getY());
coordinate.put("z", scan.getZ());
return new Object[] { coordinate };
}
private boolean isShapeCard() {
ItemStack itemStack = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
if (itemStack == null || itemStack.stackSize == 0) {
return false;
}
return itemStack.getItem() == ModItems.shapeCardItem;
}
private NBTTagCompound hasCard() {
ItemStack itemStack = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
if (itemStack == null || itemStack.stackSize == 0) {
return null;
}
NBTTagCompound tagCompound = itemStack.getTagCompound();
return tagCompound;
}
private void makeSupportBlocksShaped() {
ItemStack shapeCard = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
Coordinate dimension = ShapeCardItem.getClampedDimension(shapeCard, SpaceProjectorConfiguration.maxBuilderDimension);
Coordinate offset = ShapeCardItem.getClampedOffset(shapeCard, SpaceProjectorConfiguration.maxBuilderOffset);
ShapeCardItem.Shape shape = ShapeCardItem.getShape(shapeCard);
List<Coordinate> blocks = new ArrayList<Coordinate>();
ShapeCardItem.composeShape(shape.makeHollow(), worldObj, getCoordinate(), dimension, offset, blocks,
SpaceProjectorConfiguration.maxBuilderDimension*256*SpaceProjectorConfiguration.maxBuilderDimension, false, null);
for (Coordinate block : blocks) {
if (worldObj.isAirBlock(block.getX(), block.getY(), block.getZ())) {
int error = SupportBlock.STATUS_OK;
worldObj.setBlock(block.getX(), block.getY(), block.getZ(), SpaceProjectorSetup.supportBlock, error, 3);
worldObj.setBlockMetadataWithNotify(block.getX(), block.getY(), block.getZ(), error, 3);
}
}
}
private void makeSupportBlocks() {
if (isShapeCard()) {
makeSupportBlocksShaped();
return;
}
SpaceChamberRepository.SpaceChamberChannel chamberChannel = calculateBox();
if (chamberChannel != null) {
int dimension = chamberChannel.getDimension();
World world = DimensionManager.getWorld(dimension);
if (world == null) {
return;
}
for (int x = minBox.getX() ; x <= maxBox.getX() ; x++) {
for (int y = minBox.getY() ; y <= maxBox.getY() ; y++) {
for (int z = minBox.getZ() ; z <= maxBox.getZ() ; z++) {
Coordinate src = new Coordinate(x, y, z);
Coordinate dest = sourceToDest(src);
Block srcBlock = world.getBlock(src.getX(), src.getY(), src.getZ());
Block dstBlock = worldObj.getBlock(dest.getX(), dest.getY(), dest.getZ());
int error = SupportBlock.STATUS_OK;
if (mode != MODE_COPY) {
TileEntity srcTileEntity = world.getTileEntity(src.getX(), src.getY(), src.getZ());
TileEntity dstTileEntity = worldObj.getTileEntity(dest.getX(), dest.getY(), dest.getZ());
int error1 = isMovable(world, src.getX(), src.getY(), src.getZ(), srcBlock, srcTileEntity);
int error2 = isMovable(worldObj, dest.getX(), dest.getY(), dest.getZ(), dstBlock, dstTileEntity);
error = Math.max(error1, error2);
}
if (isEmpty(srcBlock) && !isEmpty(dstBlock)) {
world.setBlock(src.getX(), src.getY(), src.getZ(), SpaceProjectorSetup.supportBlock, error, 3);
world.setBlockMetadataWithNotify(src.getX(), src.getY(), src.getZ(), error, 3);
}
if (isEmpty(dstBlock) && !isEmpty(srcBlock)) {
worldObj.setBlock(dest.getX(), dest.getY(), dest.getZ(), SpaceProjectorSetup.supportBlock, error, 3);
worldObj.setBlockMetadataWithNotify(dest.getX(), dest.getY(), dest.getZ(), error, 3);
}
}
}
}
}
}
private void clearSupportBlocksShaped() {
ItemStack shapeCard = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
Coordinate dimension = ShapeCardItem.getClampedDimension(shapeCard, SpaceProjectorConfiguration.maxBuilderDimension);
Coordinate offset = ShapeCardItem.getClampedOffset(shapeCard, SpaceProjectorConfiguration.maxBuilderOffset);
ShapeCardItem.Shape shape = ShapeCardItem.getShape(shapeCard);
List<Coordinate> blocks = new ArrayList<Coordinate>();
ShapeCardItem.composeShape(shape.makeHollow(), worldObj, getCoordinate(), dimension, offset, blocks, SpaceProjectorConfiguration.maxSpaceChamberDimension*SpaceProjectorConfiguration.maxSpaceChamberDimension*SpaceProjectorConfiguration.maxSpaceChamberDimension, false, null);
for (Coordinate block : blocks) {
if (worldObj.getBlock(block.getX(), block.getY(), block.getZ()) == SpaceProjectorSetup.supportBlock) {
worldObj.setBlockToAir(block.getX(), block.getY(), block.getZ());
}
}
}
public void clearSupportBlocks() {
if (worldObj.isRemote) {
// Don't do anything on the client.
return;
}
if (isShapeCard()) {
clearSupportBlocksShaped();
return;
}
SpaceChamberRepository.SpaceChamberChannel chamberChannel = calculateBox();
if (chamberChannel != null) {
int dimension = chamberChannel.getDimension();
World world = DimensionManager.getWorld(dimension);
for (int x = minBox.getX() ; x <= maxBox.getX() ; x++) {
for (int y = minBox.getY() ; y <= maxBox.getY() ; y++) {
for (int z = minBox.getZ() ; z <= maxBox.getZ() ; z++) {
Coordinate src = new Coordinate(x, y, z);
if (world != null) {
Block srcBlock = world.getBlock(src.getX(), src.getY(), src.getZ());
if (srcBlock == SpaceProjectorSetup.supportBlock) {
world.setBlockToAir(src.getX(), src.getY(), src.getZ());
}
}
Coordinate dest = sourceToDest(src);
Block dstBlock = worldObj.getBlock(dest.getX(), dest.getY(), dest.getZ());
if (dstBlock == SpaceProjectorSetup.supportBlock) {
worldObj.setBlockToAir(dest.getX(), dest.getY(), dest.getZ());
}
}
}
}
}
}
public boolean hasLoopMode() {
return loopMode;
}
public void setLoopMode(boolean loopMode) {
this.loopMode = loopMode;
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public boolean hasEntityMode() {
return entityMode;
}
public void setEntityMode(boolean entityMode) {
this.entityMode = entityMode;
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public boolean hasSupportMode() {
return supportMode;
}
public void setSupportMode(boolean supportMode) {
this.supportMode = supportMode;
if (supportMode) {
makeSupportBlocks();
} else {
clearSupportBlocks();
}
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public boolean isSilent() {
return silent;
}
public void setSilent(boolean silent) {
this.silent = silent;
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public int getMode() {
return mode;
}
public void setMode(int mode) {
if (mode != this.mode) {
this.mode = mode;
restartScan();
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}
public void resetBox() {
boxValid = false;
}
public int getAnchor() {
return anchor;
}
public void setAnchor(int anchor) {
if (supportMode) {
clearSupportBlocks();
}
boxValid = false;
this.anchor = anchor;
if (isShapeCard()) {
// If there is a shape card we modify it for the new settings.
ItemStack shapeCard = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
Coordinate dimension = ShapeCardItem.getDimension(shapeCard);
Coordinate minBox = positionBox(dimension);
int dx = dimension.getX();
int dy = dimension.getY();
int dz = dimension.getZ();
Coordinate offset = new Coordinate(minBox.getX() + (int)Math.ceil(dx / 2), minBox.getY() + (int)Math.ceil(dy / 2), minBox.getZ() + (int)Math.ceil(dz / 2));
NBTTagCompound tagCompound = shapeCard.getTagCompound();
if (tagCompound == null) {
tagCompound = new NBTTagCompound();
shapeCard.setTagCompound(tagCompound);
}
tagCompound.setInteger("offsetX", offset.getX());
tagCompound.setInteger("offsetY", offset.getY());
tagCompound.setInteger("offsetZ", offset.getZ());
}
if (supportMode) {
makeSupportBlocks();
}
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
// Give a dimension, return a min coordinate of the box right in front of the builder
private Coordinate positionBox(Coordinate dimension) {
int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord);
ForgeDirection direction = BlockTools.getOrientationHoriz(meta);
int spanX = dimension.getX();
int spanY = dimension.getY();
int spanZ = dimension.getZ();
int x = 0;
int y;
int z = 0;
y = - ((anchor == ANCHOR_NE || anchor == ANCHOR_NW) ? spanY - 1 : 0);
switch (direction) {
case SOUTH:
x = - ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanX - 1 : 0);
z = - spanZ;
break;
case NORTH:
x = 1 - spanX + ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanX - 1 : 0);
z = 1;
break;
case WEST:
x = 1;
z = - ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanZ - 1 : 0);
break;
case EAST:
x = - spanX;
z = - ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? 0 : spanZ - 1);
break;
case DOWN:
case UP:
case UNKNOWN:
break;
}
return new Coordinate(x, y, z);
}
public int getRotate() {
return rotate;
}
public void setRotate(int rotate) {
if (supportMode) {
clearSupportBlocks();
}
boxValid = false;
this.rotate = rotate;
if (supportMode) {
makeSupportBlocks();
}
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@Override
public void setPowered(int powered) {
if (this.powered != powered) {
this.powered = powered;
if (loopMode || (powered > 0 && scan == null)) {
restartScan();
}
markDirty();
}
}
private Coordinate rotate(Coordinate c) {
switch (rotate) {
case 0: return c;
case 1: return new Coordinate(-c.getZ(), c.getY(), c.getX());
case 2: return new Coordinate(-c.getX(), c.getY(), -c.getZ());
case 3: return new Coordinate(c.getZ(), c.getY(), -c.getX());
}
return c;
}
private void createProjection(SpaceChamberRepository.SpaceChamberChannel chamberChannel) {
Coordinate minC = rotate(chamberChannel.getMinCorner());
Coordinate maxC = rotate(chamberChannel.getMaxCorner());
Coordinate minCorner = new Coordinate(Math.min(minC.getX(), maxC.getX()), Math.min(minC.getY(), maxC.getY()), Math.min(minC.getZ(), maxC.getZ()));
Coordinate maxCorner = new Coordinate(Math.max(minC.getX(), maxC.getX()), Math.max(minC.getY(), maxC.getY()), Math.max(minC.getZ(), maxC.getZ()));
int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord);
ForgeDirection direction = BlockTools.getOrientationHoriz(meta);
int spanX = maxCorner.getX() - minCorner.getX();
int spanY = maxCorner.getY() - minCorner.getY();
int spanZ = maxCorner.getZ() - minCorner.getZ();
switch (direction) {
case SOUTH:
projDx = xCoord + ForgeDirection.NORTH.offsetX - minCorner.getX() - ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanX : 0);
projDz = zCoord + ForgeDirection.NORTH.offsetZ - minCorner.getZ() - spanZ;
break;
case NORTH:
projDx = xCoord + ForgeDirection.SOUTH.offsetX - minCorner.getX() - spanX + ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanX : 0);
projDz = zCoord + ForgeDirection.SOUTH.offsetZ - minCorner.getZ();
break;
case WEST:
projDx = xCoord + ForgeDirection.EAST.offsetX - minCorner.getX();
projDz = zCoord + ForgeDirection.EAST.offsetZ - minCorner.getZ() - ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanZ : 0);
break;
case EAST:
projDx = xCoord + ForgeDirection.WEST.offsetX - minCorner.getX() - spanX;
projDz = zCoord + ForgeDirection.WEST.offsetZ - minCorner.getZ() - spanZ + ((anchor == ANCHOR_NE || anchor == ANCHOR_SE) ? spanZ : 0);
break;
case DOWN:
case UP:
case UNKNOWN:
break;
}
projDy = yCoord - minCorner.getY() - ((anchor == ANCHOR_NE || anchor == ANCHOR_NW) ? spanY : 0);
}
private void calculateBox(NBTTagCompound cardCompound) {
int channel = cardCompound.getInteger("channel");
SpaceChamberRepository repository = SpaceChamberRepository.getChannels(worldObj);
SpaceChamberRepository.SpaceChamberChannel chamberChannel = repository.getChannel(channel);
Coordinate minCorner = chamberChannel.getMinCorner();
Coordinate maxCorner = chamberChannel.getMaxCorner();
if (minCorner == null || maxCorner == null) {
return;
}
if (boxValid) {
// Double check if the box is indeed still valid.
if (minCorner.equals(minBox) && maxCorner.equals(maxBox)) {
return;
}
}
boxValid = true;
cardType = ShapeCardItem.CARD_SPACE;
createProjection(chamberChannel);
minBox = minCorner;
maxBox = maxCorner;
restartScan();
}
private void checkStateServerShaped() {
float factor = getInfusedFactor();
for (int i = 0 ; i < SpaceProjectorConfiguration.quarryBaseSpeed + (factor * SpaceProjectorConfiguration.quarryInfusionSpeedFactor) ; i++) {
if (scan != null) {
handleBlockShaped();
}
}
}
@Override
protected void checkStateServer() {
if (powered == 0 && loopMode) {
return;
}
if (scan == null) {
return;
}
if (isShapeCard()) {
if (powered == 0) {
chunkUnload();
return;
}
checkStateServerShaped();
return;
}
SpaceChamberRepository.SpaceChamberChannel chamberChannel = calculateBox();
if (chamberChannel == null) {
scan = null;
markDirty();
return;
}
int dimension = chamberChannel.getDimension();
World world = DimensionManager.getWorld(dimension);
if (world == null) {
// The other location must be loaded.
return;
}
float factor = getInfusedFactor();
for (int i = 0 ; i < 2 + (factor * 40) ; i++) {
if (scan != null) {
handleBlock(world);
}
}
}
private void calculateBoxShaped() {
ItemStack shapeCard = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
if (shapeCard == null) {
return;
}
Coordinate dimension = ShapeCardItem.getClampedDimension(shapeCard, SpaceProjectorConfiguration.maxBuilderDimension);
Coordinate offset = ShapeCardItem.getClampedOffset(shapeCard, SpaceProjectorConfiguration.maxBuilderOffset);
Coordinate minCorner = ShapeCardItem.getMinCorner(getCoordinate(), dimension, offset);
Coordinate maxCorner = ShapeCardItem.getMaxCorner(getCoordinate(), dimension, offset);
if (minCorner.getY() < 0) {
minCorner = new Coordinate(minCorner.getX(), 0, minCorner.getZ());
} else if (minCorner.getY() > 255) {
minCorner = new Coordinate(minCorner.getX(), 255, minCorner.getZ());
}
if (maxCorner.getY() < 0) {
maxCorner = new Coordinate(maxCorner.getX(), 0, maxCorner.getZ());
} else if (maxCorner.getY() > 255) {
maxCorner = new Coordinate(maxCorner.getX(), 255, maxCorner.getZ());
}
if (boxValid) {
// Double check if the box is indeed still valid.
if (minCorner.equals(minBox) && maxCorner.equals(maxBox)) {
return;
}
}
boxValid = true;
cardType = shapeCard.getItemDamage();
cachedBlocks = null;
cachedChunk = null;
cachedVoidableBlocks = null;
minBox = minCorner;
maxBox = maxCorner;
restartScan();
}
private SpaceChamberRepository.SpaceChamberChannel calculateBox() {
NBTTagCompound tc = hasCard();
if (tc == null) {
return null;
}
int channel = tc.getInteger("channel");
if (channel == -1) {
return null;
}
SpaceChamberRepository repository = SpaceChamberRepository.getChannels(worldObj);
SpaceChamberRepository.SpaceChamberChannel chamberChannel = repository.getChannel(channel);
if (chamberChannel == null) {
return null;
}
calculateBox(tc);
if (!boxValid) {
return null;
}
return chamberChannel;
}
private Set<Coordinate> getCachedBlocks(ChunkCoordIntPair chunk) {
if ((chunk != null && !chunk.equals(cachedChunk)) || (chunk == null && cachedChunk != null)) {
cachedBlocks = null;
}
if (cachedBlocks == null) {
cachedBlocks = new HashSet<Coordinate>();
ItemStack shapeCard = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
ShapeCardItem.Shape shape = ShapeCardItem.getShape(shapeCard);
Coordinate dimension = ShapeCardItem.getClampedDimension(shapeCard, SpaceProjectorConfiguration.maxBuilderDimension);
Coordinate offset = ShapeCardItem.getClampedOffset(shapeCard, SpaceProjectorConfiguration.maxBuilderOffset);
ShapeCardItem.composeShape(shape, worldObj, getCoordinate(), dimension, offset, cachedBlocks,
SpaceProjectorConfiguration.maxSpaceChamberDimension * SpaceProjectorConfiguration.maxSpaceChamberDimension * SpaceProjectorConfiguration.maxSpaceChamberDimension,
!ShapeCardItem.isNormalShapeCard(shapeCard), chunk);
cachedChunk = chunk;
}
return cachedBlocks;
}
private void handleBlockShaped() {
for (int i = 0 ; i < 100 ; i++) {
if (scan == null) {
return;
}
if (getCachedBlocks(new ChunkCoordIntPair(scan.getX() >> 4, scan.getZ() >> 4)).contains(scan)) {
if (!handleSingleBlock()) {
nextLocation();
}
return;
} else {
nextLocation();
}
}
}
private int getCardType() {
if (cardType == ShapeCardItem.CARD_UNKNOWN) {
ItemStack card = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
if (card != null) {
cardType = card.getItemDamage();
}
}
return cardType;
}
// Return true if we have to wait at this spot.
private boolean handleSingleBlock() {
int sx = scan.getX();
int sy = scan.getY();
int sz = scan.getZ();
if (!chunkLoad(sx, sz)) {
// The chunk is not available and we could not chunkload it. We have to wait.
return true;
}
int rfNeeded;
switch (getCardType()) {
case ShapeCardItem.CARD_VOID:
rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.voidShapeCardFactor);
break;
case ShapeCardItem.CARD_QUARRY_FORTUNE:
case ShapeCardItem.CARD_QUARRY_CLEAR_FORTUNE:
rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.fortunequarryShapeCardFactor);
break;
case ShapeCardItem.CARD_QUARRY_SILK:
case ShapeCardItem.CARD_QUARRY_CLEAR_SILK:
rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.silkquarryShapeCardFactor);
break;
case ShapeCardItem.CARD_QUARRY:
case ShapeCardItem.CARD_QUARRY_CLEAR:
rfNeeded = SpaceProjectorConfiguration.builderRfPerQuarry;
break;
case ShapeCardItem.CARD_SHAPE:
rfNeeded = SpaceProjectorConfiguration.builderRfPerOperation;
break;
default:
rfNeeded = 0;
break;
}
Block block = null;
if (getCardType() != ShapeCardItem.CARD_SHAPE) {
block = worldObj.getBlock(sx, sy, sz);
if (!isEmpty(block)) {
float hardness;
if (block instanceof BlockDynamicLiquid || block instanceof BlockStaticLiquid) {
hardness = 1.0f;
} else {
if (getCachedVoidableBlocks().contains(block)) {
rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerQuarry * SpaceProjectorConfiguration.voidShapeCardFactor);
}
hardness = block.getBlockHardness(worldObj, sx, sy, sz);
}
rfNeeded *= (int) ((hardness + 1) * 2);
}
}
rfNeeded = (int) (rfNeeded * (3.0f - getInfusedFactor()) / 3.0f);
if (rfNeeded > getEnergyStored(ForgeDirection.DOWN)) {
// Not enough energy.
return true;
}
switch (getCardType()) {
case ShapeCardItem.CARD_VOID:
return voidBlock(rfNeeded, sx, sy, sz, block);
case ShapeCardItem.CARD_QUARRY:
case ShapeCardItem.CARD_QUARRY_CLEAR:
return quarryBlock(rfNeeded, sx, sy, sz, block);
case ShapeCardItem.CARD_QUARRY_FORTUNE:
case ShapeCardItem.CARD_QUARRY_CLEAR_FORTUNE:
return quarryBlock(rfNeeded, sx, sy, sz, block);
case ShapeCardItem.CARD_QUARRY_SILK:
case ShapeCardItem.CARD_QUARRY_CLEAR_SILK:
return silkQuarryBlock(rfNeeded, sx, sy, sz, block);
case ShapeCardItem.CARD_SHAPE:
return buildBlock(rfNeeded, sx, sy, sz);
}
return true;
}
private boolean buildBlock(int rfNeeded, int sx, int sy, int sz) {
if (isEmptyOrReplacable(worldObj, sx, sy, sz)) {
BlockMeta block = consumeBlock(null, 0);
if (block == null) {
return true; // We could not find a block. Wait
}
worldObj.setBlock(sx, sy, sz, block.getBlock(), block.getMeta(), 3);
worldObj.setBlockMetadataWithNotify(sx, sy, sz, block.getMeta(), 3);
if (!silent) {
RFToolsTools.playSound(worldObj, block.getBlock().stepSound.getBreakSound(), sx, sy, sz, 1.0f, 1.0f);
}
consumeEnergy(rfNeeded);
}
return false;
}
private Set<Block> getCachedVoidableBlocks() {
if (cachedVoidableBlocks == null) {
ItemStack card = inventoryHelper.getStackInSlot(BuilderContainer.SLOT_TAB);
if (card != null && card.getItem() == ModItems.shapeCardItem) {
cachedVoidableBlocks = ShapeCardItem.getVoidedBlocks(card);
} else {
cachedVoidableBlocks = Collections.emptySet();
}
}
return cachedVoidableBlocks;
}
private void clearOrDirtBlock(int rfNeeded, int sx, int sy, int sz, Block block, boolean clear) {
if (clear) {
worldObj.setBlockToAir(sx, sy, sz);
} else {
worldObj.setBlock(sx, sy, sz, Blocks.dirt, 0, 2); // No block update!
}
consumeEnergy(rfNeeded);
if (!silent) {
RFToolsTools.playSound(worldObj, block.stepSound.getBreakSound(), sx, sy, sz, 1.0f, 1.0f);
}
}
private boolean silkQuarryBlock(int rfNeeded, int sx, int sy, int sz, Block block) {
if (sx >= xCoord-1 && sx <= xCoord+1 && sy >= yCoord-1 && sy <= yCoord+1 && sz >= zCoord-1 && sz <= zCoord+1) {
// Skip a 3x3x3 block around the builder.
return false;
}
if (isEmpty(block)) {
return false;
}
if (block.getBlockHardness(worldObj, sx, sy, sz) >= 0) {
boolean clear = ShapeCardItem.isClearingQuarry(getCardType());
if ((!clear) && block == Blocks.dirt) {
// We can skip dirt if we are not clearing.
return false;
}
if (SpaceProjectorConfiguration.quarrySkipTileEntities && worldObj.getTileEntity(sx, sy, sz) != null) {
// Skip tile entities
return false;
}
FakePlayer fakePlayer = FakePlayerFactory.getMinecraft(DimensionManager.getWorld(0));
if (block.canEntityDestroy(worldObj, sx, sy, sz, fakePlayer)) {
if (getCachedVoidableBlocks().contains(block)) {
clearOrDirtBlock(rfNeeded, sx, sy, sz, block, clear);
} else {
int meta = worldObj.getBlockMetadata(sx, sy, sz);
List<ItemStack> drops;
if (block.canSilkHarvest(worldObj, fakePlayer, sx, sy, sz, meta)) {
Item item = Item.getItemFromBlock(block);
if (item != null) {
int m = 0;
if (item.getHasSubtypes()) {
m = meta;
}
drops = Collections.singletonList(new ItemStack(item, 1, m));
} else {
drops = Collections.emptyList();
}
} else {
drops = block.getDrops(worldObj, sx, sy, sz, meta, 0);
}
if (checkAndInsertItems(drops)) {
clearOrDirtBlock(rfNeeded, sx, sy, sz, block, clear);
} else {
return true; // Not enough room. Wait
}
}
}
}
return false;
}
private boolean quarryBlock(int rfNeeded, int sx, int sy, int sz, Block block) {
if (sx >= xCoord-1 && sx <= xCoord+1 && sy >= yCoord-1 && sy <= yCoord+1 && sz >= zCoord-1 && sz <= zCoord+1) {
// Skip a 3x3x3 block around the builder.
return false;
}
if (isEmpty(block)) {
return false;
}
if (block.getBlockHardness(worldObj, sx, sy, sz) >= 0) {
boolean clear = ShapeCardItem.isClearingQuarry(getCardType());
if ((!clear) && block == Blocks.dirt) {
// We can skip dirt if we are not clearing.
return false;
}
if (SpaceProjectorConfiguration.quarrySkipTileEntities && worldObj.getTileEntity(sx, sy, sz) != null) {
// Skip tile entities
return false;
}
FakePlayer fakePlayer = FakePlayerFactory.getMinecraft(DimensionManager.getWorld(0));
if (block.canEntityDestroy(worldObj, sx, sy, sz, fakePlayer)) {
if (getCachedVoidableBlocks().contains(block)) {
clearOrDirtBlock(rfNeeded, sx, sy, sz, block, clear);
} else {
int meta = worldObj.getBlockMetadata(sx, sy, sz);
List<ItemStack> drops = block.getDrops(worldObj, sx, sy, sz, meta, (getCardType() == ShapeCardItem.CARD_QUARRY_FORTUNE || getCardType() == ShapeCardItem.CARD_QUARRY_CLEAR_FORTUNE) ? 3 : 0);
if (checkAndInsertItems(drops)) {
clearOrDirtBlock(rfNeeded, sx, sy, sz, block, clear);
} else {
return true; // Not enough room. Wait
}
}
}
}
return false;
}
private boolean voidBlock(int rfNeeded, int sx, int sy, int sz, Block block) {
if (sx >= xCoord-1 && sx <= xCoord+1 && sy >= yCoord-1 && sy <= yCoord+1 && sz >= zCoord-1 && sz <= zCoord+1) {
// Skip a 3x3x3 block around the builder.
return false;
}
if (block.getBlockHardness(worldObj, sx, sy, sz) >= 0) {
if (!silent) {
RFToolsTools.playSound(worldObj, block.stepSound.getBreakSound(), sx, sy, sz, 1.0f, 1.0f);
}
worldObj.setBlockToAir(sx, sy, sz);
consumeEnergy(rfNeeded);
}
return false;
}
private void handleBlock(World world) {
Coordinate dest = sourceToDest(scan);
int x = scan.getX();
int y = scan.getY();
int z = scan.getZ();
int destX = dest.getX();
int destY = dest.getY();
int destZ = dest.getZ();
switch (mode) {
case MODE_COPY:
copyBlock(world, x, y, z, worldObj, destX, destY, destZ);
break;
case MODE_MOVE:
if (entityMode) {
moveEntities(world, x, y, z, worldObj, destX, destY, destZ);
}
moveBlock(world, x, y, z, worldObj, destX, destY, destZ, rotate);
break;
case MODE_BACK:
if (entityMode) {
moveEntities(worldObj, destX, destY, destZ, world, x, y, z);
}
moveBlock(worldObj, destX, destY, destZ, world, x, y, z, oppositeRotate());
break;
case MODE_SWAP:
if (entityMode) {
swapEntities(world, x, y, z, worldObj, destX, destY, destZ);
}
swapBlock(world, x, y, z, worldObj, destX, destY, destZ);
break;
}
nextLocation();
}
private static Random random = new Random();
// Also works if block is null and just picks the first available block.
private BlockMeta findAndConsumeBlock(IInventory inventory, Block block, int meta) {
if (block == null) {
// We are not looking for a specific block. Pick a random one out of the chest.
List<Integer> slots = new ArrayList<Integer>();
for (int i = 0; i < inventory.getSizeInventory(); i++) {
ItemStack stack = inventory.getStackInSlot(i);
if (stack != null && stack.stackSize > 0 && stack.getItem() instanceof ItemBlock) {
slots.add(i);
}
}
if (slots.size() == 0) {
return null;
}
int randomSlot = slots.get(random.nextInt(slots.size()));
ItemStack stack = inventory.getStackInSlot(randomSlot);
ItemBlock itemBlock = (ItemBlock) stack.getItem();
inventory.decrStackSize(randomSlot, 1);
return new BlockMeta(itemBlock.field_150939_a, stack.getItemDamage());
} else {
for (int i = 0; i < inventory.getSizeInventory(); i++) {
ItemStack stack = inventory.getStackInSlot(i);
if (stack != null && stack.stackSize > 0 && stack.getItem() instanceof ItemBlock) {
ItemBlock itemBlock = (ItemBlock) stack.getItem();
if (itemBlock.field_150939_a == block && (meta == -1 || stack.getItemDamage() == meta)) {
inventory.decrStackSize(i, 1);
return new BlockMeta(itemBlock.field_150939_a, stack.getItemDamage());
}
}
}
}
return null;
}
private boolean checkAndInsertItems(List<ItemStack> items) {
TileEntity teAbove = worldObj.getTileEntity(xCoord, yCoord+1, zCoord);
boolean ok = false;
if (teAbove instanceof IInventory) {
ok = checkAndInsertItems(items, (IInventory) teAbove);
}
if (ok) {
return true;
}
TileEntity teDown = worldObj.getTileEntity(xCoord, yCoord-1, zCoord);
if (teDown instanceof IInventory) {
ok = checkAndInsertItems(items, (IInventory) teDown);
}
return ok;
}
private boolean checkAndInsertItems(List<ItemStack> items, IInventory inventory) {
Map<Integer, ItemStack> undo = new HashMap<Integer, ItemStack>();
for (ItemStack item : items) {
int remaining = InventoryHelper.mergeItemStackSafe(inventory, false, ForgeDirection.DOWN.ordinal(), item, 0, inventory.getSizeInventory(), undo);
if (remaining > 0) {
undo(undo, inventory);
return false;
}
}
return true;
}
private void undo(Map<Integer,ItemStack> undo, IInventory inventory) {
for (Map.Entry<Integer, ItemStack> entry : undo.entrySet()) {
inventory.setInventorySlotContents(entry.getKey(), entry.getValue());
}
}
private BlockMeta consumeBlock(Block block, int meta) {
TileEntity te = worldObj.getTileEntity(xCoord, yCoord+1, zCoord);
if (te instanceof IInventory) {
BlockMeta b = findAndConsumeBlock((IInventory) te, block, meta);
if (b != null) {
return b;
}
}
te = worldObj.getTileEntity(xCoord, yCoord-1, zCoord);
if (te instanceof IInventory) {
BlockMeta b = findAndConsumeBlock((IInventory) te, block, meta);
if (b != null) {
return b;
}
}
// if (meta != -1) {
// Try a second time with meta equal to -1 (which means to ignore meta).
// return consumeBlock(block, -1);
// }
return null;
}
public static SpaceProjectorSetup.BlockInformation getBlockInformation(World world, int x, int y, int z, Block block, TileEntity tileEntity) {
if (isEmpty(block)) {
return SpaceProjectorSetup.BlockInformation.FREE;
}
FakePlayer fakePlayer = FakePlayerFactory.getMinecraft(DimensionManager.getWorld(0));
if (!block.canEntityDestroy(world, x, y, z, fakePlayer)) {
return SpaceProjectorSetup.BlockInformation.INVALID;
}
SpaceProjectorSetup.BlockInformation blockInformation = SpaceProjectorSetup.getBlockInformation(block);
if (tileEntity != null) {
switch (SpaceProjectorConfiguration.teMode) {
case MOVE_FORBIDDEN:
return SpaceProjectorSetup.BlockInformation.INVALID;
case MOVE_WHITELIST:
if (blockInformation == null || blockInformation.getBlockLevel() == SupportBlock.STATUS_ERROR) {
return SpaceProjectorSetup.BlockInformation.INVALID;
}
break;
case MOVE_BLACKLIST:
if (blockInformation != null && blockInformation.getBlockLevel() == SupportBlock.STATUS_ERROR) {
return SpaceProjectorSetup.BlockInformation.INVALID;
}
break;
case MOVE_ALLOWED:
break;
}
}
if (blockInformation != null) {
return blockInformation;
}
return SpaceProjectorSetup.BlockInformation.OK;
}
private int isMovable(World world, int x, int y, int z, Block block, TileEntity tileEntity) {
return getBlockInformation(world, x, y, z, block, tileEntity).getBlockLevel();
}
public static boolean isEmptyOrReplacable(World world, int x, int y, int z) {
Block block = world.getBlock(x, y, z);
if (block.isReplaceable(world, x, y, z)) {
return true;
}
return isEmpty(block);
}
// True if this block can just be overwritten (i.e. are or support block)
public static boolean isEmpty(Block block) {
if (block == null) {
return true;
}
if (block.getMaterial() == Material.air) {
return true;
}
if (block == SpaceProjectorSetup.supportBlock) {
return true;
}
return false;
}
private void clearBlock(World world, int x, int y, int z) {
if (supportMode) {
world.setBlock(x, y, z, SpaceProjectorSetup.supportBlock, 0, 3);
} else {
world.setBlockToAir(x, y, z);
}
}
private int oppositeRotate() {
switch (rotate) {
case 1:
return 3;
case 3:
return 1;
}
return rotate;
}
private int rotateMeta(Block block, int meta, SpaceProjectorSetup.BlockInformation information, int rotMode) {
Item item = Item.getItemFromBlock(block);
if (item != null && item.getHasSubtypes()) {
// If the item has subtypes we cannot rotate it.
return meta;
}
switch (information.getRotateInfo()) {
case SpaceProjectorSetup.BlockInformation.ROTATE_mfff:
switch (rotMode) {
case 0: return meta;
case 1: {
ForgeDirection dir = ForgeDirection.values()[meta & 7];
return (meta & 8) | dir.getRotation(ForgeDirection.UP).ordinal();
}
case 2: {
ForgeDirection dir = ForgeDirection.values()[meta & 7];
return (meta & 8) | dir.getOpposite().ordinal();
}
case 3: {
ForgeDirection dir = ForgeDirection.values()[meta & 7];
return (meta & 8) | dir.getOpposite().getRotation(ForgeDirection.UP).ordinal();
}
}
break;
case SpaceProjectorSetup.BlockInformation.ROTATE_mmmm:
return meta;
}
return meta;
}
private void copyBlock(World world, int x, int y, int z, World destWorld, int destX, int destY, int destZ) {
int rf = getEnergyStored(ForgeDirection.DOWN);
int rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerOperation * getDimensionCostFactor(world, destWorld) * (4.0f - getInfusedFactor()) / 4.0f);
if (rfNeeded > rf) {
// Not enough energy.
return;
}
if (isEmptyOrReplacable(destWorld, destX, destY, destZ)) {
Block origBlock = world.getBlock(x, y, z);
int origMeta = world.getBlockMetadata(x, y, z);
if (origBlock == null || origBlock.getMaterial() == Material.air) {
return;
}
if (consumeBlock(origBlock, origMeta) == null) {
return;
}
SpaceProjectorSetup.BlockInformation information = getBlockInformation(world, x, y, z, origBlock, null);
origMeta = rotateMeta(origBlock, origMeta, information, rotate);
destWorld.setBlock(destX, destY, destZ, origBlock, origMeta, 3);
destWorld.setBlockMetadataWithNotify(destX, destY, destZ, origMeta, 3);
if (!silent) {
RFToolsTools.playSound(destWorld, origBlock.stepSound.getBreakSound(), destX, destY, destZ, 1.0f, 1.0f);
}
consumeEnergy(rfNeeded);
}
}
private double getDimensionCostFactor(World world, World destWorld) {
return destWorld.provider.dimensionId == world.provider.dimensionId ? 1.0 : SpaceProjectorConfiguration.dimensionCostFactor;
}
private boolean consumeEntityEnergy(int rfNeeded, int rfNeededPlayer, Entity entity) {
int rf = getEnergyStored(ForgeDirection.DOWN);
int rfn;
if (entity instanceof EntityPlayer) {
rfn = rfNeededPlayer;
} else {
rfn = rfNeeded;
}
if (rfn > rf) {
// Not enough energy.
return true;
} else {
consumeEnergy(rfn);
}
return false;
}
private void moveEntities(World world, int x, int y, int z, World destWorld, int destX, int destY, int destZ) {
int rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerEntity * getDimensionCostFactor(world, destWorld) * (4.0f - getInfusedFactor()) / 4.0f);
int rfNeededPlayer = (int) (SpaceProjectorConfiguration.builderRfPerPlayer * getDimensionCostFactor(world, destWorld) * (4.0f - getInfusedFactor()) / 4.0f);
// Check for entities.
List entities = world.getEntitiesWithinAABBExcludingEntity(null, AxisAlignedBB.getBoundingBox(x-.1, y-.1, z-.1, x + 1.1, y + 1.1, z + 1.1));
for (Object o : entities) {
Entity entity = (Entity) o;
if (consumeEntityEnergy(rfNeeded, rfNeededPlayer, entity)) return;
double newX = destX + (entity.posX - x);
double newY = destY + (entity.posY - y);
double newZ = destZ + (entity.posZ - z);
teleportEntity(world, destWorld, entity, newX, newY, newZ);
}
}
private void swapEntities(World world, int x, int y, int z, World destWorld, int destX, int destY, int destZ) {
int rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerEntity * getDimensionCostFactor(world, destWorld) * (4.0f - getInfusedFactor()) / 4.0f);
int rfNeededPlayer = (int) (SpaceProjectorConfiguration.builderRfPerPlayer * getDimensionCostFactor(world, destWorld) * (4.0f - getInfusedFactor()) / 4.0f);
// Check for entities.
List entitiesSrc = world.getEntitiesWithinAABBExcludingEntity(null, AxisAlignedBB.getBoundingBox(x, y, z, x + 1, y + 1, z + 1));
List entitiesDst = destWorld.getEntitiesWithinAABBExcludingEntity(null, AxisAlignedBB.getBoundingBox(destX, destY, destZ, destX + 1, destY + 1, destZ + 1));
for (Object o : entitiesSrc) {
Entity entity = (Entity) o;
if (isEntityInBlock(x, y, z, entity)) {
if (consumeEntityEnergy(rfNeeded, rfNeededPlayer, entity)) return;
double newX = destX + (entity.posX - x);
double newY = destY + (entity.posY - y);
double newZ = destZ + (entity.posZ - z);
teleportEntity(world, destWorld, entity, newX, newY, newZ);
}
}
for (Object o : entitiesDst) {
Entity entity = (Entity) o;
if (isEntityInBlock(destX, destY, destZ, entity)) {
if (consumeEntityEnergy(rfNeeded, rfNeededPlayer, entity)) return;
double newX = x + (entity.posX - destX);
double newY = y + (entity.posY - destY);
double newZ = z + (entity.posZ - destZ);
teleportEntity(destWorld, world, entity, newX, newY, newZ);
}
}
}
private void teleportEntity(World world, World destWorld, Entity entity, double newX, double newY, double newZ) {
if (entity instanceof EntityPlayer) {
if (world.provider.dimensionId != destWorld.provider.dimensionId) {
TeleportationTools.teleportToDimension((EntityPlayer) entity, destWorld.provider.dimensionId, newX, newY, newZ);
}
((EntityPlayer) entity).setPositionAndUpdate(newX, newY, newZ);
} else {
if (world.provider.dimensionId != destWorld.provider.dimensionId) {
NBTTagCompound tagCompound = new NBTTagCompound();
float rotationYaw = entity.rotationYaw;
float rotationPitch = entity.rotationPitch;
entity.writeToNBT(tagCompound);
Class<? extends Entity> entityClass = entity.getClass();
world.removeEntity(entity);
try {
Entity newEntity = entityClass.getConstructor(World.class).newInstance(destWorld);
newEntity.readFromNBT(tagCompound);
newEntity.setLocationAndAngles(newX, newY, newZ, rotationYaw, rotationPitch);
destWorld.spawnEntityInWorld(newEntity);
} catch (Exception e) {
}
} else {
entity.setLocationAndAngles(newX, newY, newZ, entity.rotationYaw, entity.rotationPitch);
destWorld.updateEntityWithOptionalForce(entity, false);
}
}
}
private boolean isEntityInBlock(int x, int y, int z, Entity entity) {
if (entity.posX >= x && entity.posX < x+1 && entity.posY >= y && entity.posY < y+1 && entity.posZ >= z && entity.posZ < z+1) {
return true;
}
return false;
}
private void moveBlock(World world, int x, int y, int z, World destWorld, int destX, int destY, int destZ, int rotMode) {
Block destBlock = destWorld.getBlock(destX, destY, destZ);
if (isEmpty(destBlock)) {
Block origBlock = world.getBlock(x, y, z);
if (isEmpty(origBlock)) {
return;
}
TileEntity origTileEntity = world.getTileEntity(x, y, z);
SpaceProjectorSetup.BlockInformation information = getBlockInformation(world, x, y, z, origBlock, origTileEntity);
if (information.getBlockLevel() == SupportBlock.STATUS_ERROR) {
return;
}
int rf = getEnergyStored(ForgeDirection.DOWN);
int rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerOperation * getDimensionCostFactor(world, destWorld) * information.getCostFactor() * (4.0f - getInfusedFactor()) / 4.0f);
if (rfNeeded > rf) {
// Not enough energy.
return;
} else {
consumeEnergy(rfNeeded);
}
int origMeta = world.getBlockMetadata(x, y, z);
origMeta = rotateMeta(origBlock, origMeta, information, rotMode);
world.removeTileEntity(x, y, z);
clearBlock(world, x, y, z);
destWorld.setBlock(destX, destY, destZ, origBlock, origMeta, 3);
destWorld.setBlockMetadataWithNotify(destX, destY, destZ, origMeta, 3);
if (origTileEntity != null) {
origTileEntity.validate();
destWorld.setTileEntity(destX, destY, destZ, origTileEntity);
origTileEntity.markDirty();
destWorld.markBlockForUpdate(destX, destY, destZ);
}
if (!silent) {
RFToolsTools.playSound(world, origBlock.stepSound.getBreakSound(), x, y, z, 1.0f, 1.0f);
RFToolsTools.playSound(destWorld, origBlock.stepSound.getBreakSound(), destX, destY, destZ, 1.0f, 1.0f);
}
}
}
private void swapBlock(World world, int x, int y, int z, World destWorld, int destX, int destY, int destZ) {
Block srcBlock = world.getBlock(x, y, z);
TileEntity srcTileEntity = world.getTileEntity(x, y, z);
Block dstBlock = destWorld.getBlock(destX, destY, destZ);
TileEntity dstTileEntity = destWorld.getTileEntity(destX, destY, destZ);
if (isEmpty(srcBlock) && isEmpty(dstBlock)) {
return;
}
SpaceProjectorSetup.BlockInformation srcInformation = getBlockInformation(world, x, y, z, srcBlock, srcTileEntity);
if (srcInformation.getBlockLevel() == SupportBlock.STATUS_ERROR) {
return;
}
SpaceProjectorSetup.BlockInformation dstInformation = getBlockInformation(destWorld, destX, destY, destZ, dstBlock, dstTileEntity);
if (dstInformation.getBlockLevel() == SupportBlock.STATUS_ERROR) {
return;
}
int rf = getEnergyStored(ForgeDirection.DOWN);
int rfNeeded = (int) (SpaceProjectorConfiguration.builderRfPerOperation * getDimensionCostFactor(world, destWorld) * srcInformation.getCostFactor() * (4.0f - getInfusedFactor()) / 4.0f);
rfNeeded += (int) (SpaceProjectorConfiguration.builderRfPerOperation * getDimensionCostFactor(world, destWorld) * dstInformation.getCostFactor() * (4.0f - getInfusedFactor()) / 4.0f);
if (rfNeeded > rf) {
// Not enough energy.
return;
} else {
consumeEnergy(rfNeeded);
}
int srcMeta = world.getBlockMetadata(x, y, z);
srcMeta = rotateMeta(srcBlock, srcMeta, srcInformation, oppositeRotate());
int dstMeta = destWorld.getBlockMetadata(destX, destY, destZ);
dstMeta = rotateMeta(dstBlock, dstMeta, dstInformation, rotate);
world.removeTileEntity(x, y, z);
world.setBlockToAir(x, y, z);
destWorld.removeTileEntity(destX, destY, destZ);
destWorld.setBlockToAir(destX, destY, destZ);
destWorld.setBlock(destX, destY, destZ, srcBlock, srcMeta, 3);
destWorld.setBlockMetadataWithNotify(destX, destY, destZ, srcMeta, 3);
if (srcTileEntity != null) {
srcTileEntity.validate();
destWorld.setTileEntity(destX, destY, destZ, srcTileEntity);
srcTileEntity.markDirty();
destWorld.markBlockForUpdate(destX, destY, destZ);
}
world.setBlock(x, y, z, dstBlock, dstMeta, 3);
world.setBlockMetadataWithNotify(x, y, z, dstMeta, 3);
if (dstTileEntity != null) {
dstTileEntity.validate();
world.setTileEntity(x, y, z, dstTileEntity);
dstTileEntity.markDirty();
world.markBlockForUpdate(x, y, z);
}
if (!silent) {
if (!isEmpty(srcBlock)) {
RFToolsTools.playSound(world, srcBlock.stepSound.getBreakSound(), x, y, z, 1.0f, 1.0f);
}
if (!isEmpty(dstBlock)) {
RFToolsTools.playSound(destWorld, dstBlock.stepSound.getBreakSound(), destX, destY, destZ, 1.0f, 1.0f);
}
}
}
private Coordinate sourceToDest(Coordinate source) {
Coordinate c = rotate(source);
return new Coordinate(c.getX() + projDx, c.getY() + projDy, c.getZ() + projDz);
}
private void restartScan() {
chunkUnload();
if (loopMode || (powered > 0 && scan == null)) {
if (getCardType() == ShapeCardItem.CARD_SPACE) {
calculateBox();
scan = minBox;
} else if (getCardType() != ShapeCardItem.CARD_UNKNOWN) {
calculateBoxShaped();
// We start at the top for a quarry or shape building
scan = new Coordinate(minBox.getX(), maxBox.getY(), minBox.getZ());
}
cachedBlocks = null;
cachedChunk = null;
cachedVoidableBlocks = null;
} else {
scan = null;
}
}
@Override
public void invalidate() {
super.invalidate();
chunkUnload();
}
private void chunkUnload() {
if (forcedChunk != null && ticket != null) {
ForgeChunkManager.unforceChunk(ticket, forcedChunk);
forcedChunk = null;
}
}
private boolean chunkLoad(int x, int z) {
int cx = x >> 4;
int cz = z >> 4;
if (worldObj.getChunkProvider().chunkExists(cx, cz)) {
return true;
}
if (SpaceProjectorConfiguration.quarryChunkloads) {
if (ticket == null) {
ForgeChunkManager.setForcedChunkLoadingCallback(RFTools.instance, new ForgeChunkManager.LoadingCallback() {
@Override
public void ticketsLoaded(List<ForgeChunkManager.Ticket> tickets, World world) {
}
});
ticket = ForgeChunkManager.requestTicket(RFTools.instance, worldObj, ForgeChunkManager.Type.NORMAL);
if (ticket == null) {
// Chunk is not loaded and we can't get a ticket.
return false;
}
}
ChunkCoordIntPair pair = new ChunkCoordIntPair(cx, cz);
if (pair.equals(forcedChunk)) {
return true;
}
if (forcedChunk != null) {
ForgeChunkManager.unforceChunk(ticket, forcedChunk);
}
forcedChunk = pair;
ForgeChunkManager.forceChunk(ticket, forcedChunk);
return true;
}
// Chunk is not loaded and we don't do chunk loading so we cannot proceed.
return false;
}
private void nextLocation() {
if (scan != null) {
int x = scan.getX();
int y = scan.getY();
int z = scan.getZ();
if (getCardType() == ShapeCardItem.CARD_SPACE) {
nextLocationNormal(x, y, z);
} else {
nextLocationQuarry(x, y, z);
}
}
}
private void nextLocationQuarry(int x, int y, int z) {
if (x >= maxBox.getX() || ((x+1) % 16 == 0)) {
if (z >= maxBox.getZ() || ((z+1) % 16 == 0)) {
if (y <= minBox.getY()) {
if (x < maxBox.getX()) {
x++;
z = (z >> 4) << 4;
y = maxBox.getY();
scan = new Coordinate(x, y, z);
} else if (z < maxBox.getZ()) {
x = minBox.getX();
z++;
y = maxBox.getY();
scan = new Coordinate(x, y, z);
} else {
restartScan();
}
} else {
scan = new Coordinate((x >> 4) << 4, y - 1, (z >> 4) << 4);
}
} else {
scan = new Coordinate((x >> 4) << 4, y, z + 1);
}
} else {
scan = new Coordinate(x + 1, y, z);
}
}
private void nextLocationNormal(int x, int y, int z) {
if (x >= maxBox.getX()) {
if (z >= maxBox.getZ()) {
if (y >= maxBox.getY()) {
if (mode != MODE_SWAP || isShapeCard()) {
restartScan();
} else {
// We don't restart in swap mode.
scan = null;
}
} else {
scan = new Coordinate(minBox.getX(), y + 1, minBox.getZ());
}
} else {
scan = new Coordinate(minBox.getX(), y, z + 1);
}
} else {
scan = new Coordinate(x + 1, y, z);
}
}
@Override
public int[] getAccessibleSlotsFromSide(int side) {
return BuilderContainer.factory.getAccessibleSlots();
}
@Override
public boolean canInsertItem(int index, ItemStack item, int side) {
return BuilderContainer.factory.isInputSlot(index);
}
@Override
public boolean canExtractItem(int index, ItemStack item, int side) {
return BuilderContainer.factory.isOutputSlot(index);
}
@Override
public int getSizeInventory() {
return inventoryHelper.getCount();
}
@Override
public ItemStack getStackInSlot(int index) {
return inventoryHelper.getStackInSlot(index);
}
@Override
public ItemStack decrStackSize(int index, int amount) {
if (index == BuilderContainer.SLOT_TAB && inventoryHelper.getStackInSlot(index) != null && amount > 0) {
// Restart if we go from having a stack to not having stack or the other way around.
refreshSettings();
}
return inventoryHelper.decrStackSize(index, amount);
}
@Override
public ItemStack getStackInSlotOnClosing(int index) {
return null;
}
@Override
public void setInventorySlotContents(int index, ItemStack stack) {
if (index == BuilderContainer.SLOT_TAB && ((stack == null && inventoryHelper.getStackInSlot(index) != null) || (stack != null && inventoryHelper.getStackInSlot(index) == null))) {
// Restart if we go from having a stack to not having stack or the other way around.
refreshSettings();
}
inventoryHelper.setInventorySlotContents(getInventoryStackLimit(), index, stack);
}
private void refreshSettings() {
clearSupportBlocks();
cachedBlocks = null;
cachedChunk = null;
cachedVoidableBlocks = null;
boxValid = false;
scan = null;
cardType = ShapeCardItem.CARD_UNKNOWN;
}
@Override
public String getInventoryName() {
return "Builder";
}
@Override
public boolean hasCustomInventoryName() {
return false;
}
@Override
public int getInventoryStackLimit() {
return 1;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player) {
return canPlayerAccess(player);
}
@Override
public void openInventory() {
}
@Override
public void closeInventory() {
}
@Override
public boolean isItemValidForSlot(int index, ItemStack stack) {
return true;
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
powered = tagCompound.getByte("powered");
}
@Override
public void readRestorableFromNBT(NBTTagCompound tagCompound) {
super.readRestorableFromNBT(tagCompound);
readBufferFromNBT(tagCompound);
mode = tagCompound.getInteger("mode");
anchor = tagCompound.getInteger("anchor");
rotate = tagCompound.getInteger("rotate");
silent = tagCompound.getBoolean("silent");
supportMode = tagCompound.getBoolean("support");
entityMode = tagCompound.getBoolean("entityMode");
loopMode = tagCompound.getBoolean("loopMode");
scan = Coordinate.readFromNBT(tagCompound, "scan");
minBox = Coordinate.readFromNBT(tagCompound, "minBox");
maxBox = Coordinate.readFromNBT(tagCompound, "maxBox");
}
private void readBufferFromNBT(NBTTagCompound tagCompound) {
NBTTagList bufferTagList = tagCompound.getTagList("Items", Constants.NBT.TAG_COMPOUND);
for (int i = 0 ; i < bufferTagList.tagCount() ; i++) {
NBTTagCompound nbtTagCompound = bufferTagList.getCompoundTagAt(i);
inventoryHelper.setStackInSlot(i, ItemStack.loadItemStackFromNBT(nbtTagCompound));
}
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
tagCompound.setByte("powered", (byte) powered);
}
@Override
public void writeRestorableToNBT(NBTTagCompound tagCompound) {
super.writeRestorableToNBT(tagCompound);
writeBufferToNBT(tagCompound);
tagCompound.setInteger("mode", mode);
tagCompound.setInteger("anchor", anchor);
tagCompound.setInteger("rotate", rotate);
tagCompound.setBoolean("silent", silent);
tagCompound.setBoolean("support", supportMode);
tagCompound.setBoolean("entityMode", entityMode);
tagCompound.setBoolean("loopMode", loopMode);
Coordinate.writeToNBT(tagCompound, "scan", scan);
Coordinate.writeToNBT(tagCompound, "minBox", minBox);
Coordinate.writeToNBT(tagCompound, "maxBox", maxBox);
}
private void writeBufferToNBT(NBTTagCompound tagCompound) {
NBTTagList bufferTagList = new NBTTagList();
for (int i = 0 ; i < inventoryHelper.getCount() ; i++) {
ItemStack stack = inventoryHelper.getStackInSlot(i);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
if (stack != null) {
stack.writeToNBT(nbtTagCompound);
}
bufferTagList.appendTag(nbtTagCompound);
}
tagCompound.setTag("Items", bufferTagList);
}
// Request the current scan level.
public void requestCurrentLevel() {
RFToolsMessages.INSTANCE.sendToServer(new PacketRequestIntegerFromServer(xCoord, yCoord, zCoord,
CMD_GETLEVEL,
CLIENTCMD_GETLEVEL));
}
public static int getCurrentLevel() {
return currentLevel;
}
@Override
public boolean execute(EntityPlayerMP playerMP, String command, Map<String, Argument> args) {
boolean rc = super.execute(playerMP, command, args);
if (rc) {
return true;
}
if (CMD_SETMODE.equals(command)) {
setMode(args.get("mode").getInteger());
return true;
} else if (CMD_SETANCHOR.equals(command)) {
setAnchor(args.get("anchor").getInteger());
return true;
} else if (CMD_SETROTATE.equals(command)) {
setRotate(args.get("rotate").getInteger());
return true;
} else if (CMD_SETSILENT.equals(command)) {
setSilent(args.get("silent").getBoolean());
return true;
} else if (CMD_SETSUPPORT.equals(command)) {
setSupportMode(args.get("support").getBoolean());
return true;
} else if (CMD_SETENTITIES.equals(command)) {
setEntityMode(args.get("entities").getBoolean());
return true;
} else if (CMD_SETLOOP.equals(command)) {
setLoopMode(args.get("loop").getBoolean());
return true;
}
return false;
}
@Override
public Integer executeWithResultInteger(String command, Map<String, Argument> args) {
Integer rc = super.executeWithResultInteger(command, args);
if (rc != null) {
return rc;
}
if (CMD_GETLEVEL.equals(command)) {
return scan == null ? -1 : scan.getY();
}
return null;
}
@Override
public boolean execute(String command, Integer result) {
boolean rc = super.execute(command, result);
if (rc) {
return true;
}
if (CLIENTCMD_GETLEVEL.equals(command)) {
currentLevel = result;
return true;
}
return false;
}
}