Father Of Time Posted March 5, 2014 Posted March 5, 2014 Good afternoon to all, Although this is my first post on the Minecraft Forge Forums I have been working with Minecraft Forge for some time (around a year); however, it only recently that I’ve decided to request assistance from the community when facing an issue rather than relying on outdated tutorials and trial and error. So I suppose I should dive right in… I am currently experimenting with code in an attempt to make a single block unbreakable by any tool but the desired one (so for instance a block that can only be broken by a shovel; pickaxes, axes and hoes will have no effect). Now I have been digging through Item, tool, player, block and hook classes which all play a role in the determination of block hardness, harvest ability, and player related break speed (among other aspects of block breaking). However, this is where I am being slowed down… Almost everything I have found specifies that you set a tools harvest characteristics on a block by utilizing the following code: block.setHarvestLevel( "hoe", -1 ); The first argument is a toolClass string variable that specifies the tool you wish to set the harvest characteristics; if you look at the base block class at getHarvestLevel you can see that by setting the value to -1 you make the tool not capable of harvesting the block /** * Queries the harvest level of this item stack for the specifred tool class, * Returns -1 if this tool is not of the specified type * * @param stack This item stack instance * @return Harvest level, or -1 if not the specified tool type. */ public int getHarvestLevel(int metadata) { return harvestLevel[metadata]; } However, this is where my problem lies… Being incapable of harvesting a block is not the same as being incapable of breaking the block… If a block isn’t harvestable by a tool it still suffers block damage while being mined, the only difference is that when the block finally breaks it doesn’t drop it’s resource… So this is my end goal (simplified for the intention of understanding) 1) Add a custom block with custom material: package org.moltenenterprises.dystopia.experiment; import org.moltenenterprises.dystopia.BlockRegistry; import org.moltenenterprises.dystopia.DystopiaMod; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; public class BlockSteel extends Block { public BlockSteel(){ super( BlockRegistry.materialSteel ); this.setHardness( 10.0f ); this.setStepSound( Block.soundTypeMetal ); this.setBlockName( "SteelBlock" ); this.setBlockTextureName("DystopiaMod:block_steel"); } } package org.moltenenterprises.dystopia.experiment; import net.minecraft.block.material.MapColor; import net.minecraft.block.material.Material; public class MaterialSteel extends Material { public MaterialSteel() { super( MapColor.ironColor ); this.setNoPushMobility(); this.setRequiresTool(); } } 2) I want to add a custom tool class, blow torches (not one of the default tool types, pick, axe, shovel or hoe ). package org.moltenenterprises.dystopia.experiment; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import java.util.Set; import org.moltenenterprises.dystopia.DystopiaMod; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemAxe; import net.minecraft.item.ItemPickaxe; import net.minecraft.item.ItemSpade; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemTool; // blow torch notes: // half the damage of a pick, but sets the victim on fire when hit. public class BlowTorchItem extends ItemTool { private static final Set effectiveSet = Sets.newHashSet(new Block[]{ Blocks.iron_block, Blocks.iron_bars }); private static final Set igniteSet = Sets.newHashSet(new Block[]{ Blocks.planks, Blocks.log } ); // private String toolClass; public BlowTorchItem( Item.ToolMaterial toolMaterial ) { super(1.0F, toolMaterial, effectiveSet ); this.setUnlocalizedName( toolMaterial.toString() + "BlowTorchItem" ); this.setTextureName("dystopiamod:unmarked_rune_item"); // ("dystopiamod:" + toolMaterial.toString() + "_blow_torch_item" ); } // called by canHarvestBlock(Block par1Block, ItemStack itemStack) in Item.class public boolean func_150897_b(Block p_150897_1_) { System.out.println( "REACHED CANHARVESTBLOCK in BlockTorchToolItem.class" ); return p_150897_1_ == Blocks.obsidian ? this.toolMaterial.getHarvestLevel() == 3 : (p_150897_1_ != Blocks.diamond_block && p_150897_1_ != Blocks.diamond_ore ? (p_150897_1_ != Blocks.emerald_ore && p_150897_1_ != Blocks.emerald_block ? (p_150897_1_ != Blocks.gold_block && p_150897_1_ != Blocks.gold_ore ? (p_150897_1_ != Blocks.iron_block && p_150897_1_ != Blocks.iron_ore ? (p_150897_1_ != Blocks.lapis_block && p_150897_1_ != Blocks.lapis_ore ? (p_150897_1_ != Blocks.redstone_ore && p_150897_1_ != Blocks.lit_redstone_ore ? (p_150897_1_.getMaterial() == Material.rock ? true : (p_150897_1_.getMaterial() == Material.iron ? true : p_150897_1_.getMaterial() == Material.anvil)) : this.toolMaterial.getHarvestLevel() >= 2) : this.toolMaterial.getHarvestLevel() >= 1) : this.toolMaterial.getHarvestLevel() >= 1) : this.toolMaterial.getHarvestLevel() >= 2) : this.toolMaterial.getHarvestLevel() >= 2) : this.toolMaterial.getHarvestLevel() >= 2); } // I think this is the effective against list, make it affective against steel, but can dig any metal material. It will set any non metal material on fire. public float func_150893_a(ItemStack p_150893_1_, Block p_150893_2_) { return p_150893_2_.getMaterial() != Material.iron && p_150893_2_.getMaterial() != Material.anvil && p_150893_2_.getMaterial() != Material.rock ? super.func_150893_a(p_150893_1_, p_150893_2_) : this.efficiencyOnProperMaterial; } @Override public int getHarvestLevel(ItemStack stack, String toolClass) { return super.getHarvestLevel(stack, toolClass); } @Override public Set<String> getToolClasses(ItemStack stack ) { return super.getToolClasses(stack); } } 3) I want to make it so that the SteelBlock above can't be damaged by any tool (pick, shovel, hoe or axe) except the blow torch. So in closing, will this require for me to abandon the notion of utilizing existing tool architecture and to create my own item that mimics tool behavior because existing tools aren’t designed to be incapable of breaking blocks (no example exist except bedrock, which is hardcoded into Pickaxe.class) I want to thank everyone who is able and willing to assist with this issue in advance; I look forward to hearing what cleaver solutions people propose for this problem. Quote
Draco18s Posted March 5, 2014 Posted March 5, 2014 public float getPlayerRelativeBlockHardness(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5){ } ? Quote Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable. If you think this is the case, JUST REPORT ME. Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice. Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked. DO NOT PM ME WITH PROBLEMS. No help will be given.
Father Of Time Posted March 5, 2014 Author Posted March 5, 2014 Good afternoon once again, So I just wanted to append the information I've already posted. I decided to take another look into how Bedrock is protected from block destruction and realized that I had overlooked a method within Block.class: /** * Determines if this block is can be destroyed by the specified entities normal behavior. * * @param world The current world * @param x X Position * @param y Y Position * @param z Z position * @return True to allow the ender dragon to destroy this block */ public boolean canEntityDestroy(IBlockAccess world, int x, int y, int z, Entity entity) { if (entity instanceof EntityWither) { return this != Blocks.bedrock && this != Blocks.end_portal && this != Blocks.end_portal_frame && this != Blocks.command_block; } else if (entity instanceof EntityDragon) { return this != Blocks.obsidian && this != Blocks.end_stone && this != Blocks.bedrock; } return true; } This keeps creatures that are capable of breaking blocks from attempting to break bedrock. As I looked at this I realized that I could get the behavior I desire by ghetto rigging things a little: public boolean canEntityDestroy(IBlockAccess world, int x, int y, int z, Entity entity) { if( entity instanceof EntityPlayer ){ EntityPlayer player = (EntityPlayer)entity; Item heldItem = player.getHeldItem().getItem(); return ( heldItem != null && heldItem instanceof BlowTorchItem ); } return false; } This would make it so that a block will be unbreakable unless the entity breaking it is a player holding my custom tool, and if they are in fact holding the custom tool then it will utilize the vanilla tool mechanics (material buffs and things of that nature). Now I believe the above will give me the behavior I am looking for, but I am curious if anyone has any better solutions that actual utilize features of vanilla tools and not a "bypass" to the system. Again, thank you in advance to anyone who is able and willing to assist me with this matter; have a great day! Quote
Father Of Time Posted March 5, 2014 Author Posted March 5, 2014 public float getPlayerRelativeBlockHardness(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5){ } ? Firstly, thank you for taking the time to respond; however, although I believe the method you mentioned could accomplish the behavior I am looking for it's kind of a "work around" to the vanilla tool effectiveness system. I believe the above function is more intended to be used for player specific conditions (like if a player has a mining speed potion applied). Your suggestion follows the same logic that I was proposing in my previous post however, so I am beginning to think this may be the best solution (because no vanilla or forge solution exists). I will code everything in the above manner to see if it behaves as we assume, and if so I will report back; but if anyone knows of a better solution to making a block unbreakable by everything but one specific tool I would love to hear. Thank you once again for your time and attention to this matter! Quote
SanAndreaP Posted March 5, 2014 Posted March 5, 2014 public float getPlayerRelativeBlockHardness(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5){ } ? Firstly, thank you for taking the time to respond; however, although I believe the method you mentioned could accomplish the behavior I am looking for it's kind of a "work around" to the vanilla tool effectiveness system. I believe the above function is more intended to be used for player specific conditions (like if a player has a mining speed potion applied). Your suggestion follows the same logic that I was proposing in my previous post however, so I am beginning to think this may be the best solution (because no vanilla or forge solution exists). I will code everything in the above manner to see if it behaves as we assume, and if so I will report back; but if anyone knows of a better solution to making a block unbreakable by everything but one specific tool I would love to hear. Thank you once again for your time and attention to this matter! 1. canEntityDestroy is only called by those entities mentioned within that methods code, so not really useful 2. getPlayerRelativeBlockHardness should work just fine, since your goal actually is a player specific condition (either the player has a blowtorch or not) Quote Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! | mah twitter This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.
Father Of Time Posted March 5, 2014 Author Posted March 5, 2014 1. canEntityDestroy is only called by those entities mentioned within that methods code, so not really useful Hah, would you look at that... I didn't even notice that it was only called during an AI update in the wither and ender dragon; nice catch! (hard for me to notice those type of things while at work and workspaceless). 2. getPlayerRelativeBlockHardness should work just fine, since your goal actually is a player specific condition (either the player has a blowtorch or not) I'm positive it will work as I've utilized the above method to make a custom door that can only be broken/opened with a prison door key; however, I was just hoping that somewhere within the vanilla harvest aspects of tools that there would be something I could set/utilize that would make a tool incapible of damaging a block. I think at this point I have gathered enough information to do some testing when I get home from work, and once I have done that I will report back with any success/issues I may have. On an unrelated note, I'm impressed with the responsiveness of the Minecraft Forge forums; I have several other aspects of this mod that I would enjoy discussing with other individuals that are familiar with Forge, do you have any suggestions as to where I could find interested parties (such as an IRC). To give you an example of some of the concepts I'd like to discuss: Quote
Mecblader Posted March 5, 2014 Posted March 5, 2014 You may be able to do two things. One, you can make a block break listener, but might be a little long winded. Two, you can make the mining lvl required to mine the block a larger amount than the vanilla tools. Here is the code: MinecraftForge.setBlockHarvestLevel(Block, "tool", lvl); e.g. MinecraftForge.setBlockHarvestLevel(Mod.MySpecialBlock, "pickaxe", 1); Quote Don't be afraid to ask question when modding, there are no stupid question! Unless you don't know java then all your questions are stupid!
Bishamonten Posted March 6, 2014 Posted March 6, 2014 I'm not really that great when it comes to coding and what not. but in the: setBlockHarvestLevel(Block, "tool", lvl); I had a small light of inspiration. Would it be possible to in the "tool" couldn't you do like "myPickaxe". only problem is where you set up your tools, you have set your tool to be both "pickaxe" and "myPickaxe" (that way your tool will still function like the default tool.) There may be another way of going about what i'm talking about. But it just randomly occurred to me and i thought i'd throw that out there. But i think Mecblader has the two most likely solutions. The block break listener being the least likely approach as i believe that would be called every single time a block is broken anywhere. Again I'm just a novice. Quote
SanAndreaP Posted March 7, 2014 Posted March 7, 2014 setBlockHarvestLevel(Block, "tool", lvl); this only prevents the blocks from being harvested, thus not dropping items (like diamond ore only drops diamond with an iron pickaxe or better) As I've seen in the OP, he doesn't want this behavior: However, this is where my problem lies… Being incapable of harvesting a block is not the same as being incapable of breaking the block… If a block isn’t harvestable by a tool it still suffers block damage while being mined, the only difference is that when the block finally breaks it doesn’t drop it’s resource… Quote Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! | mah twitter This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.
Father Of Time Posted March 7, 2014 Author Posted March 7, 2014 Good afternoon to all, I wanted to take a moment to report back with the results of my code experimentations, as well as to reply to the people who were kind enough to assist me with my issue. After much digging through the vanilla base tool classes I've come to the conclusion that the method in which I wished to accomplish my goal does not exist; however, like you suggested ( and as past code supported ) the method suggested earlier in this thread was a good solution to the problem. I am the type who believes that a picture is worth a thousand words, so I through together this demonstration video and slap it on YouTube to give everyone a visual of what affects this code has: For those who are interested in the code that causes this behavior it's the following: @Override public float getPlayerRelativeBlockHardness(EntityPlayer entityPlayer, World world, int x, int y, int z ){ ItemStack heldStack = entityPlayer.getHeldItem(); if( heldStack != null && heldStack.getItem() instanceof BlowTorchItem && ((BlowTorchItem)heldStack.getItem()).getIsBurning() ){ return super.getPlayerRelativeBlockHardness( entityPlayer, world, x, y, z ); } return 0.0F; } Now obviously some of the above code is specific to my project, but basically what this code does is evaluates the item being held by the player breaking the block, and if the player is holding the desired tool it returns the super class relative block strength; this allows for the material damage modifiers of iron, gold, diamonds, etc. to function as normal. However, if the item in hand isn't the desired item then it returns 0.0 (which means no damage id dealt to the block). You may be able to do two things. One, you can make a block break listener, but might be a little long winded. Two, you can make the mining lvl required to mine the block a larger amount than the vanilla tools. Here is the code: MinecraftForge.setBlockHarvestLevel(Block, "tool", lvl); e.g. MinecraftForge.setBlockHarvestLevel(Mod.MySpecialBlock, "pickaxe", 1); Thank you for your contributions to this conversation. Regarding your first proposal of using events, although I do believe that I could achieve my desired behavior via this method I feel it's slightly unnecessary, the block class itself has plenty of overridable functions that are capable of achieving this behavior as well; my only goal was to identify if there was a specific way of getting my desired behavior (making vanilla tools incapable of breaking certain blocks) via the vanilla basetool classes, which appears to be no. In regards to your second proposal, as SanAndreasP was kind enough to point out, setBlockHarvestLevel(...) only has an impact on whether or not the blocks "drops" and generated; I demonstrated this concept at the end of the video I linked to above. I'm not really that great when it comes to coding and what not. but in the: setBlockHarvestLevel(Block, "tool", lvl); I had a small light of inspiration. Would it be possible to in the "tool" couldn't you do like "myPickaxe". only problem is where you set up your tools, you have set your tool to be both "pickaxe" and "myPickaxe" (that way your tool will still function like the default tool.) There may be another way of going about what i'm talking about. But it just randomly occurred to me and i thought i'd throw that out there. But i think Mecblader has the two most likely solutions. The block break listener being the least likely approach as i believe that would be called every single time a block is broken anywhere. Again I'm just a novice. You sure can register a custom tool type this way, although it took me a bit of digging to figure this out. If you look inside Block.class at setHarvestLevel(...) you will see it simply stores 16 strings in an array associated with 16 ints in a second array, this is done so that a tool type can assign a required harvest level per block metadata level (although why I don't know, I can't think of a tool that has different harvest effectiveness based on a blocks metadata): private String[] harvestTool = new String[16]; private int[] harvestLevel = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; /** * Sets or removes the tool and level required to harvest this block. * * @param toolClass Class * @param level Harvest level: * Wood: 0 * Stone: 1 * Iton: 2 * Diamond: 3 * Gold: 0 */ public void setHarvestLevel(String toolClass, int level) { for (int m = 0; m < 16; m++) { setHarvestLevel(toolClass, level, m); } } And it's this integer that a tools material type (wood = 0, stone = 1, etc...) is compared against to see if the tool being used can harvest the block. Once again though, as SanAndreasP was kind enough to point out this has no impact on whether the a tool can Break a block, but rather what resources it generated when harvested. If you look into it a blocks hardness controls how long it takes to break (or -1 to be unbreakable) and harvest ability has to do with the resources it drops, fortune enchantment, etc... I was trying to get a blocks hardness to be conditional based on the tool being used, but instead I simply made it condition on the item in the players hand while being harvested (nearly the same thing). Thank you to everyone who participated in this discussion, I believe I have all of the information I need related to this topic; however, I have enjoyed the responsiveness of this community so I am sure you will be seeing me again soon. Oh, and on a personal note… I only recently noticed that it was you SanAndreasP who was assisting me with my issue. I feel like I should point out that it was your mod that single handedly brought me to the Forge community. I have been a member of the Bukkit community for several years now and was growing tired of the limitation of server side only modifications. One day as this frustration was growing I accidentally stumbled across your mod when trying to find a solution for changing player name plate text color without client modifications (which at the time was impossible due to the color being hardcoded in the livingEntityRenderer). While researching why this wasn’t possible it lead me to a few post on the Minecraft Forge forums which quickly brought light to your mod, Clay soldiers… At the time your mod blew everything out of the water and warped peoples perspectives of what was possible with Minecraft modifications! It was that same inspiring awesomeness that lead me to begin playing around with the Forge API, and here we are today. So in short, thank you for your help with this issue, as well as for the inspiration to grasp at a shinier brass ring. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.