/** Copyright (c) 2011-2014, SpaceToad and the BuildCraft Team http://www.mod-buildcraft.com
*
* The BuildCraft API is distributed under the terms of the MIT License. Please check the contents of the license, which
* should be located as "LICENSE.API" in the BuildCraft source code distribution. */
package buildcraft.api.blueprints;
import java.util.*;
import com.google.gson.GsonBuilder;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumFacing.Axis;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.BlockFluidBase;
import buildcraft.api.core.BCLog;
public class SchematicBlock extends SchematicBlockBase {
public IBlockState state = null;
public BuildingPermission defaultPermission = BuildingPermission.ALL;
/** This field contains requirements for a given block when stored in the blueprint. Modders can either rely on this
* list or compute their own int Schematic. */
public ItemStack[] storedRequirements = new ItemStack[0];
private boolean doNotUse = false;
@Override
public void getRequirementsForPlacement(IBuilderContext context, List<ItemStack> requirements) {
if (state != null) {
if (storedRequirements.length != 0) {
Collections.addAll(requirements, storedRequirements);
} else {
requirements.add(getItemStack(state));
}
}
}
@Override
public boolean isAlreadyBuilt(IBuilderContext context, BlockPos pos) {
IBlockState placed = context.world().getBlockState(pos);
if (state == placed) return true;
if (state.getBlock() != placed.getBlock()) return false;
// This fixes bugs with blocks like stairs that return extra properties that were not visible from the meta.
if (state.getBlock().getMetaFromState(state) == placed.getBlock().getMetaFromState(placed)) return true;
return false;
}
@Override
public void placeInWorld(IBuilderContext context, BlockPos pos, List<ItemStack> stacks) {
super.placeInWorld(context, pos, stacks);
this.setBlockInWorld(context, pos);
}
@Override
public void storeRequirements(IBuilderContext context, BlockPos pos) {
super.storeRequirements(context, pos);
if (state != null) {
List<ItemStack> req = state.getBlock().getDrops(context.world(), pos, state, 0);
if (req != null) {
storedRequirements = new ItemStack[req.size()];
req.toArray(storedRequirements);
}
}
}
@Override
public void writeSchematicToNBT(NBTTagCompound nbt, MappingRegistry registry) {
super.writeSchematicToNBT(nbt, registry);
writeBlockToNBT(nbt, registry);
writeRequirementsToNBT(nbt, registry);
}
@Override
public void readSchematicFromNBT(NBTTagCompound nbt, MappingRegistry registry) {
super.readSchematicFromNBT(nbt, registry);
readBlockFromNBT(nbt, registry);
if (!doNotUse()) {
readRequirementsFromNBT(nbt, registry);
}
}
/** Get a list of relative block coordinates which have to be built before this block can be placed. */
public Set<BlockPos> getPrerequisiteBlocks(IBuilderContext context) {
Set<BlockPos> indexes = new HashSet<BlockPos>();
if (state.getBlock() instanceof BlockFalling) {
indexes.add(new BlockPos(0, -1, 0));
}
return indexes;
}
@Override
public BuildingStage getBuildStage() {
if (state.getBlock() instanceof BlockFluidBase || state.getBlock() instanceof BlockLiquid) {
return BuildingStage.EXPANDING;
} else {
return BuildingStage.STANDALONE;
}
}
@Override
public BuildingPermission getBuildingPermission() {
return defaultPermission;
}
// Utility functions
protected void setBlockInWorld(IBuilderContext context, BlockPos pos) {
context.world().setBlockState(pos, state, 3);
}
@Override
public boolean doNotUse() {
return doNotUse;
}
protected void readBlockFromNBT(NBTTagCompound nbt, MappingRegistry registry) {
try {
Block block = registry.getBlockForId(nbt.getInteger("blockId"));
state = block.getStateFromMeta(nbt.getInteger("blockMeta"));
} catch (MappingNotFoundException e) {
BCLog.logger.info(e);
doNotUse = true;
}
}
protected void readRequirementsFromNBT(NBTTagCompound nbt, MappingRegistry registry) {
if (nbt.hasKey("rq")) {
NBTTagList rq = nbt.getTagList("rq", Constants.NBT.TAG_COMPOUND);
ArrayList<ItemStack> rqs = new ArrayList<ItemStack>();
for (int i = 0; i < rq.tagCount(); ++i) {
try {
NBTTagCompound sub = rq.getCompoundTagAt(i);
registry.stackToWorld(sub);
rqs.add(ItemStack.loadItemStackFromNBT(sub));
} catch (MappingNotFoundException e) {
defaultPermission = BuildingPermission.CREATIVE_ONLY;
} catch (Throwable t) {
t.printStackTrace();
defaultPermission = BuildingPermission.CREATIVE_ONLY;
}
}
storedRequirements = rqs.toArray(new ItemStack[rqs.size()]);
} else {
storedRequirements = new ItemStack[0];
}
}
protected void writeBlockToNBT(NBTTagCompound nbt, MappingRegistry registry) {
nbt.setInteger("blockId", registry.getIdForBlock(state.getBlock()));
nbt.setInteger("blockMeta", state.getBlock().getMetaFromState(state));
}
protected void writeRequirementsToNBT(NBTTagCompound nbt, MappingRegistry registry) {
if (storedRequirements.length > 0) {
NBTTagList rq = new NBTTagList();
for (ItemStack stack : storedRequirements) {
if (stack == null || stack.getItem() == null) throw new IllegalStateException("Found a null requirement! " + getClass());
NBTTagCompound sub = new NBTTagCompound();
stack.writeToNBT(sub);
rq.appendTag(sub);
}
nbt.setTag("rq", rq);
}
}
protected ItemStack getItemStack(IBlockState state, int quantity) {
return new ItemStack(state.getBlock(), quantity, state.getBlock().damageDropped(state));
}
protected ItemStack getItemStack(IBlockState state) {
return getItemStack(state, 1);
}
// Pretty much all blocks (that rotate) rotate this way now
@Override
public void rotateLeft(IBuilderContext context) {
IProperty<EnumFacing> facingProp = getFacingProp();
if (facingProp != null) {
EnumFacing face = state.getValue(facingProp);
if (face.getAxis() == Axis.Y) return;
state = state.withProperty(facingProp, face.rotateY());
}
}
protected IProperty<EnumFacing> getFacingProp() {
Collection<IProperty> props = state.getPropertyNames();
for (IProperty prop : props) {
if ("facing".equals(prop.getName()) && state.getValue(prop) instanceof EnumFacing) {
return prop;
}
}
return null;
}
}