Java tutorial
/** Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team http://www.mod-buildcraft.com * <p/> * BuildCraft is distributed under the terms of the Minecraft Mod Public License 1.0, or MMPL. Please check the contents * of the license located in http://www.mod-buildcraft.com/MMPL-1.0.txt */ package buildcraft.transport; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang3.builder.HashCodeBuilder; import net.minecraft.block.Block; import net.minecraft.block.BlockQuartz; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.util.Constants; import net.minecraftforge.fluids.IFluidBlock; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.registry.GameRegistry; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import buildcraft.BuildCraftTransport; import buildcraft.api.core.BCLog; import buildcraft.api.core.JavaTools; import buildcraft.api.facades.FacadeType; import buildcraft.api.facades.IFacadeItem; import buildcraft.api.recipes.BuildcraftRecipeRegistry; import buildcraft.api.transport.IPipe; import buildcraft.api.transport.PipeWire; import buildcraft.api.transport.pluggable.IPipePluggableItem; import buildcraft.api.transport.pluggable.PipePluggable; import buildcraft.core.BCCreativeTab; import buildcraft.core.lib.items.ItemBuildCraft; import buildcraft.core.lib.utils.Utils; import buildcraft.core.lib.world.FakeBlockAccessSingleBlock; import buildcraft.core.proxy.CoreProxy; import buildcraft.lib.misc.LocaleUtil; public class ItemFacade extends ItemBuildCraft implements IFacadeItem, IPipePluggableItem { public static class FacadeState { public final IBlockState state; public final boolean transparent; public final boolean hollow; public final PipeWire wire; public FacadeState(IBlockState state, PipeWire wire) { this.state = state; this.wire = wire; this.transparent = false; this.hollow = false; } public FacadeState(IBlockState state, PipeWire wire, boolean hollow) { this.state = state; this.wire = wire; this.transparent = false; this.hollow = hollow; } public FacadeState(NBTTagCompound nbt) { String key = nbt.getString("block"); Block block = (Block) Block.REGISTRY.getObject(new ResourceLocation(key)); if (block == null) throw new NullPointerException("Could not load a block from the key \"" + key + "\""); int metadata = nbt.getByte("metadata"); state = block.getStateFromMeta(metadata); this.wire = nbt.hasKey("wire") ? PipeWire.fromOrdinal(nbt.getByte("wire")) : null; this.transparent = nbt.hasKey("transparent") && nbt.getBoolean("transparent"); this.hollow = nbt.hasKey("hollow") && nbt.getBoolean("hollow"); } private FacadeState(PipeWire wire) { state = Blocks.BEDROCK.getDefaultState(); this.wire = wire; this.transparent = true; this.hollow = false; } public static FacadeState create(IBlockState state) { return create(state, null); } public static FacadeState create(IBlockState state, PipeWire wire) { return new FacadeState(state, wire); } public static FacadeState createTransparent(PipeWire wire) { return new FacadeState(wire); } public void writeToNBT(NBTTagCompound nbt) { if (state != null) { nbt.setString("block", Utils.getNameForBlock(state.getBlock())); nbt.setByte("metadata", (byte) state.getBlock().getMetaFromState(state)); } if (wire != null) { nbt.setByte("wire", (byte) wire.ordinal()); } nbt.setBoolean("transparent", transparent); nbt.setBoolean("hollow", hollow); } public static NBTTagList writeArray(FacadeState[] states) { if (states == null) { return null; } NBTTagList list = new NBTTagList(); for (FacadeState state : states) { NBTTagCompound stateNBT = new NBTTagCompound(); state.writeToNBT(stateNBT); list.appendTag(stateNBT); } return list; } public static FacadeState[] readArray(NBTTagList list) { if (list == null) { return new FacadeState[0]; } final int length = list.tagCount(); FacadeState[] states = new FacadeState[length]; for (int i = 0; i < length; i++) { states[i] = new FacadeState(list.getCompoundTagAt(i)); } return states; } @Override public int hashCode() { return new HashCodeBuilder().append(hollow).append(transparent).append(state).append(wire).build(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; FacadeState other = (FacadeState) obj; if (hollow != other.hollow) return false; if (state == null) { if (other.state != null) return false; } else if (!state.equals(other.state)) return false; if (transparent != other.transparent) return false; if (wire != other.wire) return false; return true; } } public static final ArrayList<ItemStack> allStacks = new ArrayList<>(); private static final HashSet<IBlockState> blacklistedFacades = new HashSet<>(); private static final HashSet<IBlockState> whitelistedFacades = new HashSet<>(); private static final Block NULL_BLOCK = null; private static final ItemStack NO_MATCH = new ItemStack(NULL_BLOCK, 0, 0); private static final Block[] PREVIEW_FACADES = new Block[] { Blocks.planks, Blocks.stonebrick, Blocks.glass }; private static ArrayList<ItemStack> previewStacks; public ItemFacade() { super(BuildCraftTransport.showAllFacadesCreative ? BCCreativeTab.get("facades") : BCCreativeTab.get("main")); setHasSubtypes(true); setMaxDamage(0); } @Override public String getItemStackDisplayName(ItemStack itemstack) { switch (getFacadeType(itemstack)) { case Basic: FacadeState[] states = getFacadeStates(itemstack); String displayName = states.length > 0 ? getFacadeStateDisplayName(states[0]) : "CORRUPT"; return super.getItemStackDisplayName(itemstack) + ": " + displayName; case Phased: return LocaleUtil.localize("item.FacadePhased.name"); default: return ""; } } public static boolean isTransparentFacade(IBlockState state) { Block block = state.getBlock(); return !block.isVisuallyOpaque() && !block.isOpaqueCube(); } @Override public String getUnlocalizedName(ItemStack itemstack) { return "item.Facade"; } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean debug) { for (FacadeState state : getFacadeStates(stack)) { if (state != null && !state.transparent && state.state != null && Item.getItemFromBlock(state.state.getBlock()) != null) { Item.getItemFromBlock(state.state.getBlock()).addInformation(new ItemStack(state.state.getBlock(), 1, state.state.getBlock().getMetaFromState(state.state)), player, list, debug); } } if (getFacadeType(stack) == FacadeType.Phased) { String stateString = LocaleUtil.localize("item.FacadePhased.state"); FacadeState defaultState = null; for (FacadeState state : getFacadeStates(stack)) { if (state.wire == null) { defaultState = state; continue; } list.add(String.format(stateString, state.wire.getColor(), getFacadeStateDisplayName(state))); } if (defaultState != null) { list.add(1, String.format(LocaleUtil.localize("item.FacadePhased.state_default"), getFacadeStateDisplayName(defaultState))); } } } public static String getFacadeStateDisplayName(FacadeState state) { if (state.state == null) { return LocaleUtil.localize("item.FacadePhased.state_transparent"); } // if (state.state.getBlock().getRenderType() == 31) { // TODO: Find out what render type is 31... and what this now means // meta &= 0x3; // } else if (state.block.getRenderType() == 39 && meta > 2) { // meta = 2; // } String s = CoreProxy.proxy.getItemDisplayName( new ItemStack(state.state.getBlock(), 1, state.state.getBlock().getMetaFromState(state.state))); if (state.hollow) { s += " (" + LocaleUtil.localize("item.Facade.state_hollow") + ")"; } return s; } public static List<IBlockState> getAllFacades() { List<IBlockState> stacks = new ArrayList<>(); for (Block b : Block.REGISTRY) { for (int i = 0; i < 16; i++) { try { IBlockState state = b.getStateFromMeta(i); if (isValidFacade(state)) { stacks.add(state); } } catch (Exception e) { } } } return stacks; } public static boolean isValidFacade(IBlockState state) { if (blacklistedFacades.contains(state)) { return false; } if (whitelistedFacades.contains(state)) { return true; } Block block = state.getBlock(); if (block instanceof IFluidBlock || block.hasTileEntity(state)) { return false; } block.setBlockBoundsBasedOnState(new FakeBlockAccessSingleBlock(state), BlockPos.ORIGIN); if (block.getBlockBoundsMinX() != 0.0D || block.getBlockBoundsMinY() != 0.0D || block.getBlockBoundsMinZ() != 0.0D) { return false; } if (block.getBlockBoundsMaxX() != 1.0D || block.getBlockBoundsMaxY() != 1.0D || block.getBlockBoundsMaxZ() != 1.0D) { return false; } return true; } private static void generateFacadeStacks() { HashSet<IBlockState> states = new HashSet<>(); for (Block b : Block.REGISTRY) { for (int i = 0; i < 16; i++) { try { Item item = Item.getItemFromBlock(b); if (item != null) { IBlockState state = b.getStateFromMeta(i); if (!states.contains(state) && isValidFacade(state)) { states.add(state); allStacks.add(BuildCraftTransport.facadeItem.getFacadeForBlock(state)); } } } catch (Exception e) { } } } if (BuildCraftTransport.showAllFacadesCreative) { previewStacks = allStacks; } else { previewStacks = new ArrayList<>(); List<ItemStack> hollowFacades = new ArrayList<>(); for (Block b : PREVIEW_FACADES) { if (isValidFacade(b.getDefaultState()) && !blacklistedFacades.contains(b.getDefaultState())) { ItemStack facade = BuildCraftTransport.facadeItem.getFacadeForBlock(b.getDefaultState()); previewStacks.add(facade); FacadeState state = getFacadeStates(facade)[0]; hollowFacades.add(getFacade(new FacadeState(state.state, state.wire, true))); } } previewStacks.addAll(hollowFacades); } } @SuppressWarnings({ "unchecked", "rawtypes" }) @Override @SideOnly(Side.CLIENT) public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List itemList) { itemList.addAll(previewStacks); } public void initialize() { for (String s : BuildCraftTransport.facadeBlacklist) { // TODO: Add state support? blacklistFacade(Block.getBlockFromName(s)); } } public static FacadeState[] getFacadeStates(ItemStack stack) { if (!stack.hasTagCompound()) return new FacadeState[0]; NBTTagCompound nbt = stack.getTagCompound(); nbt = migrate(stack, nbt); if (!nbt.hasKey("states")) return new FacadeState[0]; return FacadeState.readArray(nbt.getTagList("states", Constants.NBT.TAG_COMPOUND)); } private static NBTTagCompound migrate(ItemStack stack, NBTTagCompound nbt) { Block block = null, blockAlt = null; int metadata = 0, metadataAlt; PipeWire wire = null; if (nbt.hasKey("id")) block = Block.REGISTRY.getObjectById(nbt.getInteger("id")); else if (nbt.hasKey("name")) block = Block.REGISTRY.getObject(new ResourceLocation(nbt.getString("name"))); if (nbt.hasKey("name_alt")) blockAlt = Block.REGISTRY.getObject(new ResourceLocation(nbt.getString("name_alt"))); if (nbt.hasKey("meta")) metadata = nbt.getInteger("meta"); if (nbt.hasKey("meta_alt")) metadataAlt = nbt.getInteger("meta_alt"); else metadataAlt = stack.getItemDamage() & 0x0000F; if (nbt.hasKey("wire")) wire = PipeWire.fromOrdinal(nbt.getInteger("wire")); if (block != null) { FacadeState[] states; FacadeState mainState = FacadeState.create(block.getStateFromMeta(metadata)); if (blockAlt != null && wire != null) { FacadeState altState = FacadeState.create(blockAlt.getStateFromMeta(metadataAlt), wire); states = new FacadeState[] { mainState, altState }; } else { states = new FacadeState[] { mainState }; } NBTTagCompound newNbt = getFacade(states).getTagCompound(); stack.setTagCompound(newNbt); return newNbt; } return nbt; } @Override public IBlockState[] getBlockStatesForFacade(ItemStack stack) { FacadeState[] states = getFacadeStates(stack); IBlockState[] blocks = new IBlockState[states.length]; for (int i = 0; i < states.length; i++) { blocks[i] = states[i].state; } return blocks; } // GETTERS FOR FACADE DATA @Override public FacadeType getFacadeType(ItemStack stack) { if (!stack.hasTagCompound()) { return FacadeType.Basic; } NBTTagCompound nbt = stack.getTagCompound(); if (!nbt.hasKey("type")) { return FacadeType.Basic; } return FacadeType.fromOrdinal(nbt.getInteger("type")); } @Override public boolean doesSneakBypassUse(World world, BlockPos pos, EntityPlayer player) { // Simply send shift click to the pipe / mod block. return true; } public void initializeRecipes() { generateFacadeStacks(); Set<IBlockState> states = new HashSet<>(); for (Block b : Block.REGISTRY) { for (int i = 0; i < 16; i++) { try { IBlockState state = b.getStateFromMeta(i); if (!states.contains(state) && isValidFacade(state)) { states.add(state); ItemStack itemStack = new ItemStack(state.getBlock(), 1, state.getBlock().damageDropped(state)); ItemStack facade = getFacadeForBlock(state); ItemStack facade6 = facade.copy(); facade6.stackSize = 6; FacadeState fstate = getFacadeStates(facade6)[0]; ItemStack facadeHollow = getFacade(new FacadeState(fstate.state, fstate.wire, true)); ItemStack facade6Hollow = facadeHollow.copy(); facade6Hollow.stackSize = 6; if (!Loader.isModLoaded("BuildCraft|Silicon") || BuildCraftTransport.facadeForceNonLaserRecipe) { GameRegistry.addShapedRecipe(facade6, "t ", "ts", "t ", 't', itemStack, 's', BuildCraftTransport.pipeStructureCobblestone); GameRegistry.addShapedRecipe(facade6Hollow, "t ", " s", "t ", 't', itemStack, 's', BuildCraftTransport.pipeStructureCobblestone); } else { // TODO: Make the Assembly Table variant a dynamic recipe handler to save RAM String recipeId = "buildcraft:facade{" + Utils.getNameForBlock(state.getBlock()) + "#" + itemStack.getItemDamage() + "}"; BuildcraftRecipeRegistry.assemblyTable.addRecipe(recipeId, 8000, facade6, new ItemStack(BuildCraftTransport.pipeStructureCobblestone, 3), itemStack); BuildcraftRecipeRegistry.assemblyTable.addRecipe(recipeId + ":hollow", 8000, facade6Hollow, new ItemStack(BuildCraftTransport.pipeStructureCobblestone, 3), itemStack); BuildcraftRecipeRegistry.assemblyTable.addRecipe(recipeId + ":toHollow", 160, facadeHollow, facade); BuildcraftRecipeRegistry.assemblyTable.addRecipe(recipeId + ":fromHollow", 160, facade, facadeHollow); } } } catch (Exception e) { } } } } public static void whitelistFacade(IBlockState state) { whitelistedFacades.add(state); } public static void whitelistFacade(Block block) { if (block != null) { for (IBlockState state : block.getBlockState().getValidStates()) { whitelistFacade(state); } } } public static void blacklistFacade(IBlockState state) { blacklistedFacades.add(state); } public static void blacklistFacade(Block block) { if (block != null) { for (IBlockState state : block.getBlockState().getValidStates()) { blacklistFacade(state); } } } public class FacadeRecipe implements IRecipe { @Override public boolean matches(InventoryCrafting inventorycrafting, World world) { Object[] facade = getFacadeBlockFromCraftingGrid(inventorycrafting); return facade != null && facade[0] != null && ((IBlockState[]) facade[0]).length == 1; } @Override public ItemStack getCraftingResult(InventoryCrafting inventorycrafting) { Object[] facade = getFacadeBlockFromCraftingGrid(inventorycrafting); if (facade == null || ((IBlockState[]) facade[0]).length != 1) return null; IBlockState block = ((IBlockState[]) facade[0])[0]; ItemStack originalFacade = (ItemStack) facade[1]; if (block == null) return null; return getNextFacadeItemStack(block, originalFacade); } private Object[] getFacadeBlockFromCraftingGrid(InventoryCrafting inventorycrafting) { ItemStack slotmatch = null; int countOfItems = 0; for (int i = 0; i < inventorycrafting.getSizeInventory(); i++) { ItemStack slot = inventorycrafting.getStackInSlot(i); if (slot != null && slot.getItem() == ItemFacade.this && slotmatch == null) { slotmatch = slot; countOfItems++; } else if (slot != null) slotmatch = NO_MATCH; if (countOfItems > 1) return null; } if (slotmatch != null && slotmatch != NO_MATCH) return new Object[] { getBlockStatesForFacade(slotmatch), slotmatch }; return null; } private ItemStack getNextFacadeItemStack(IBlockState state, ItemStack originalFacade) { // TODO: Add an API for me! IBlockState newState = state; if (newState.getPropertyNames().contains(BlockQuartz.VARIANT)) { BlockQuartz.EnumType type = newState.getValue(BlockQuartz.VARIANT); if ("lines".equals(type.toString())) { newState = newState.withProperty(BlockQuartz.VARIANT, BlockQuartz.EnumType.byMetadata(((type.getMetadata() - 1) % 3) + 2)); } } else { for (net.minecraft.block.properties.IProperty<?> prop : state.getProperties().keySet()) { if (prop.getName().equals("axis")) { newState = newState.cycleProperty(prop); } } } return getFacadeForBlock(newState); } @Override public int getRecipeSize() { return 1; } @Override public ItemStack getRecipeOutput() { return null; } @Override public ItemStack[] getRemainingItems(InventoryCrafting inv) { ItemStack[] itemStack = new ItemStack[inv.getSizeInventory()]; for (int i = 0; i < itemStack.length; ++i) { ItemStack itemstack = inv.getStackInSlot(i); itemStack[i] = ForgeHooks.getContainerItem(itemstack); } return itemStack; } } @Override public ItemStack getFacadeForBlock(IBlockState state) { return getFacade(FacadeState.create(state)); } public static ItemStack getAdvancedFacade(PipeWire wire, IBlockState state, IBlockState stateAlt) { return getFacade(FacadeState.create(state), FacadeState.create(stateAlt, wire)); } public static ItemStack getFacade(FacadeState... states) { if (states == null || states.length == 0) return null; final boolean basic = states.length == 1 && states[0].wire == null; ItemStack stack = new ItemStack(BuildCraftTransport.facadeItem, 1, 0); NBTTagCompound nbt = new NBTTagCompound(); nbt.setByte("type", (byte) (basic ? FacadeType.Basic : FacadeType.Phased).ordinal()); nbt.setTag("states", FacadeState.writeArray(states)); stack.setTagCompound(nbt); return stack; } @Override public PipePluggable createPipePluggable(IPipe pipe, EnumFacing side, ItemStack stack) { return new FacadePluggable(getFacadeStates(stack)); } }