Jump to content

[1.7.2][UNSOLVED] - Making vanilla tools incapable of breaking custom block


Father Of Time

Recommended Posts

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.

Link to comment
Share on other sites

public float getPlayerRelativeBlockHardness(EntityPlayer par1EntityPlayer, World par2World, int par3, int par4, int par5){ }

 

?

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.

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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)

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.

Link to comment
Share on other sites

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:

Link to comment
Share on other sites

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);

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!

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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…

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.

Link to comment
Share on other sites

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.  ;D

 

So in short, thank you for your help with this issue, as well as for the inspiration to grasp at a shinier brass ring.  ;)

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.