/** Copyright (c) 2011-2015, 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.List; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.BlockPos; import net.minecraft.util.Vec3; import buildcraft.api.core.IInvSlot; /** A schematic is a piece of a blueprint. It allows to stock blocks or entities to blueprints, and can have a state * that moves from a blueprint referential to a world referential. Although default schematic behavior will be OK for a * lot of objects, specific blocks and entities may be associated with a dedicated schematic class, which will be * instantiated automatically. * * Schematic perform "id translation" in case the block ids between a blueprint and the world installation are * different. Mapping is done through the builder context. * * Detailed documentation on the schematic behavior can be found on * http://www.mod-buildcraft.com/wiki/doku.php?id=builder_support * * Example of schematics for minecraft blocks are available in the package buildcraft.core.schematics. */ public abstract class Schematic { /** Blocks are build in various stages, in order to make sure that a block can indeed be placed, and that it's * unlikely to disturb other blocks. */ public enum BuildingStage { /** Standalone blocks do not change once placed. */ STANDALONE, /** Expanding blocks will grow and may disturb other block locations, like liquids. */ EXPANDING } /** This is called to verify whether the required item is equal to the supplied item. * * Primarily rely on this for checking metadata/NBT - the item ID itself might have been filtered out by previously * running code. */ public boolean isItemMatchingRequirement(ItemStack suppliedStack, ItemStack requiredStack) { return BuilderAPI.schematicHelper.isEqualItem(suppliedStack, requiredStack); } /** This is called each time an item matches a requirement. By default, it will increase damage of items that can be * damaged by the amount of the requirement, and remove the intended amount of items that can't be damaged. * * Client may override this behavior. Note that this subprogram may be called twice with the same parameters, once * with a copy of requirements and stack to check if the entire requirements can be fulfilled, and once with the * real inventory. Implementer is responsible for updating req (with the remaining requirements if any) and slot * (after usage). * * returns what was used (similar to req, but created from slot, so that any NBT based differences are drawn from * the correct source) */ public ItemStack useItem(IBuilderContext context, ItemStack req, IInvSlot slot) { ItemStack stack = slot.getStackInSlot(); ItemStack result = stack.copy(); if (stack.isItemStackDamageable()) { if (req.getItemDamage() + stack.getItemDamage() <= stack.getMaxDamage()) { stack.setItemDamage(req.getItemDamage() + stack.getItemDamage()); result.setItemDamage(req.getItemDamage()); req.stackSize = 0; } if (stack.getItemDamage() >= stack.getMaxDamage()) { slot.decreaseStackInSlot(1); } } else { if (stack.stackSize >= req.stackSize) { result.stackSize = req.stackSize; stack.stackSize -= req.stackSize; req.stackSize = 0; } else { req.stackSize -= stack.stackSize; stack.stackSize = 0; } } if (stack.stackSize == 0) { stack.stackSize = 1; if (stack.getItem().hasContainerItem(stack)) { ItemStack newStack = stack.getItem().getContainerItem(stack); slot.setStackInSlot(newStack); } else { slot.setStackInSlot(null); } } return result; } /** Perform a 90 degree rotation to the slot. */ public void rotateLeft(IBuilderContext context) { } /** Applies translations to all positions in the schematic to center in the blueprint referential */ public void translateToBlueprint(Vec3 transform) { } /** Apply translations to all positions in the schematic to center in the builder referential */ public void translateToWorld(Vec3 transform) {} /** Translates blocks and item ids to the blueprint referential */ public void idsToBlueprint(MappingRegistry registry) {} /** Translates blocks and item ids to the world referential */ public void idsToWorld(MappingRegistry registry) {} /** Initializes a schematic for blueprint according to an objet placed on {x, y, z} on the world. For blocks, block * and meta fields will be initialized automatically. */ public void initializeFromObjectAt(IBuilderContext context, BlockPos pos) {} /** Places the block in the world, at the location specified in the slot, using the stack in parameters */ public void placeInWorld(IBuilderContext context, BlockPos pos, List<ItemStack> stacks) {} /** Write specific requirements coming from the world to the blueprint. */ public void storeRequirements(IBuilderContext context, BlockPos pos) {} /** Returns the requirements needed to build this block. When the requirements are met, they will be removed all at * once from the builder, before calling writeToWorld. */ public void getRequirementsForPlacement(IBuilderContext context, List<ItemStack> requirements) {} /** Returns the amount of energy required to build this slot, depends on the stacks selected for the build. */ public int getEnergyRequirement(List<ItemStack> stacksUsed) { int result = 0; if (stacksUsed != null) { for (ItemStack s : stacksUsed) { result += s.stackSize * BuilderAPI.BUILD_ENERGY; } } return result; } /** Returns the flying stacks to display in the builder animation. */ public List<ItemStack> getStacksToDisplay(List<ItemStack> stackConsumed) { return stackConsumed; } /** Return the stage where this schematic has to be built. */ public BuildingStage getBuildStage() { return BuildingStage.STANDALONE; } /** Return true if the block on the world correspond to the block stored in the blueprint at the location given by * the slot. By default, this subprogram is permissive and doesn't take into account metadata. * * Post processing will be called on these blocks. */ public boolean isAlreadyBuilt(IBuilderContext context, BlockPos pos) { return true; } /** Return true if the block should not be placed to the world. Requirements will not be asked on such a block, and * building will not be called. * * Post processing will be called on these blocks. */ public boolean doNotBuild() { return false; } /** Return true if the schematic should not be used at all. This is computed straight after readFromNBT can be used * to deactivate schematics in which an inconsistency is detected. It will be considered as a block of air instead. * * Post processing will *not* be called on these blocks. */ public boolean doNotUse() { return false; } /** Return the maximium building permission for blueprint containing this schematic. */ public BuildingPermission getBuildingPermission() { return BuildingPermission.ALL; } /** Called on a block when the blueprint has finished to place all the blocks. This may be useful to adjust variable * depending on surrounding blocks that may not be there already at initial building. */ public void postProcessing(IBuilderContext context, BlockPos pos) {} /** Saves this schematic to the blueprint NBT. */ public void writeSchematicToNBT(NBTTagCompound nbt, MappingRegistry registry) {} /** Loads this schematic from the blueprint NBT. */ public void readSchematicFromNBT(NBTTagCompound nbt, MappingRegistry registry) {} /** Returns the number of cycles to wait after building this schematic. Tiles and entities typically require more * wait, around 5 cycles. */ public int buildTime() { return 1; } }