Jump to content

[1.7.10] Breaking a block without hitting it with a tool


Syndaryl

Recommended Posts

Every "Make a new tool" tutorial I can find is about making an existing tool template out of a new material. Fie on that I say, why try something simple when I can try something I can't find any information about!

 

I'm making a new tool type, a jackhammer or sledgehammer (haven't decided, currently calling it a sledgehammer), that works like an enhanced pick. When you break a block with it, it (ideally) breaks each block around that block that is of the same type.

So if you break a stone, it only breaks adjacent stone blocks, not cobblestone or sandstone or ore or dirt or sand or whatever. It takes damage for each block broken - if only one, then x1, if 6, then x6, etc. The breakage is not a chain reaction - it doesn't explode an entire ore seam or mountain at once, just a maximum of a 3x3 cube (how you'd attack the centre block while having each block around it populated I don't know.

 

I have most of the behaviour I'm looking for but I can't figure out how to break the adjacent blocks. I've been transforming them to air for testing purposes, but that's not really helpful - the blocks don't drop whatever if I do that.

 

I want to trigger regular block breakage without firing off the onBlockDestroyed() event on my tool again (because I don't want the chain reaction, eep). What method(s) am I looking for, and where are they hiding?

Link to comment
Share on other sites

Every "Make a new tool" tutorial I can find is about making an existing tool template out of a new material. Fie on that I say, why try something simple when I can try something I can't find any information about!

 

I'm making a new tool type, a jackhammer or sledgehammer (haven't decided, currently calling it a sledgehammer), that works like an enhanced pick. When you break a block with it, it (ideally) breaks each block around that block that is of the same type.

So if you break a stone, it only breaks adjacent stone blocks, not cobblestone or sandstone or ore or dirt or sand or whatever. It takes damage for each block broken - if only one, then x1, if 6, then x6, etc. The breakage is not a chain reaction - it doesn't explode an entire ore seam or mountain at once, just a maximum of a 3x3 cube (how you'd attack the centre block while having each block around it populated I don't know.

 

I have most of the behaviour I'm looking for but I can't figure out how to break the adjacent blocks. I've been transforming them to air for testing purposes, but that's not really helpful - the blocks don't drop whatever if I do that.

 

I want to trigger regular block breakage without firing off the onBlockDestroyed() event on my tool again (because I don't want the chain reaction, eep). What method(s) am I looking for, and where are they hiding?

 

i think i have seen something like world.breakBlock() or world.destroy() somewhere but i can't remember where.

I would use world.setBlock() to set air and then i would use e.g.: Blocks.stone.getDrops() to spawn the items manually. But thats mostlikely not the best way to do this.

Here could be your advertisement!

Link to comment
Share on other sites

i think i have seen something like world.breakBlock() or world.destroy() somewhere but i can't remember where.

I would use world.setBlock() to set air and then i would use e.g.: Blocks.stone.getDrops() to spawn the items manually. But thats mostlikely not the best way to do this.

 

I've found gameWorld_.destroyBlockInWorldPartially(actor.getEntityId(), x, y, z, damage) but I can't seem to figure out how much damage to apply to explode anything but the block hit. EDIT: Like, I tried getBlockHardness * 5000 and THAT didn't do it.

 

I'm having a poke at <block>.removedByPlayer() right now, but I can't get it to drop either, even when I set the last argument (canHarvest) to true;

Link to comment
Share on other sites

Welp. I'm baffled.

 

onBlockDestroyed() is called twice every time I break a block, for reasons not obvious to me, meaning my home-rolled "drop item and destroy block" method is being called twice.

 

Weirder still, for some reason the second set of objects dropped appear to be a bit derpy - I can see them, they react to having a block plonked down in their space, but I can't pick them up and they don't save with a server restart. I suppose it's good they're noninteractive since I'm not supposed to have 2x drops, but wut?

Link to comment
Share on other sites

"for reasons not obvious to me"

Break event is called twice because it's both client and server side method, so if you want to make some calculations you can always make it server side. (Every client has "client" and "server" which is virtually taking care of most things)

 

In the end client will always sync with server, unless you make some radical error.

 

EDIT: As to finding method, if you won't find it until i get back home, I will write how to make it.

 

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Aha! That makes sense, I really need to remember about the client/server side split, for when I see "it's being done twice !?!" again.

 

I haven't found the "proper" function so I wrote my own to serve until I get it. I can just sub in the real function call once I find it.

 

 

		private void breakBlock(World gameWorld_,
		BlockWithLocation blockXYZ) {
	// System.out.println(String.format("breakBlock() dropping at %d %d %d", blockXYZ.x, blockXYZ.y, blockXYZ.z));
        int fortune = 0; // figure out how to get my Fortune enchant level later
	ItemStack dropedItemStack = new ItemStack( blockXYZ.b.getItemDropped(0, new Random(), fortune));

	EntityItem drop = new EntityItem(gameWorld_, blockXYZ.x, blockXYZ.y, blockXYZ.z, dropedItemStack);
	gameWorld_.spawnEntityInWorld(drop);
	gameWorld_.setBlockToAir(blockXYZ.x, blockXYZ.y, blockXYZ.z);
}

 

BlockWithLocation is just a custom object that has 4 fields: a block, and an x, y, and z int.

Link to comment
Share on other sites

OK, that's weirder. If I make it server side only, it never gets called at all.

 

And if I make it client side only, it STILL gets called twice and produces the "junk" ghost blocks.

 

@SideOnly(Side.SERVER)
    public boolean onBlockDestroyed(ItemStack toolInstance, World gameWorld_, Block blockStruck, int worldX, int worldY, int worldZ, EntityLivingBase actor)
    {
	System.out.println(String.format("onBlockDestroyed() nuking block at %d %d %d", worldX, worldY, worldZ));
        Deque<BlockWithLocation> blockDeck = new LinkedList<BlockWithLocation>();
        getNeighboringBlocksToDeque(gameWorld_, blockStruck, worldX, worldY,
			worldZ, blockDeck);
	System.out.println(String.format("getNeighboringBlocksToDeque(): returned deck of %d", blockDeck.size()));
        hitManyBlocks(toolInstance, gameWorld_, worldX, worldY, worldZ,
			actor, blockDeck);

        
        return true;
    }

Link to comment
Share on other sites

I was simply explaining that it should be that way. There is a reason they are being called on both sides by vanilla and it should stay that way. Only real fact is that when you for e.g generate random it will be different on both sides - BUT the server side value will most likely take over - I was having fun with those some time ago and I simply said "nah, it works so better leave it".

 

And back to issue:

You want to have a tool that when it breaks block, the block broken will scan blocks around and if block == blockaround it will break too giving loot (without recurrency/chain reaction)?

 

If so - take a look at BlockEvent.class

You have two events you can use - both seem good for what you want to do.

 

How would i do it?

1. Subscribe to BreakEvent.

2. Read neat documentation with nice addnotation: Reference to the Player who broke the block.

3. If (equipeditem == sledgehammer) - BAM, launch "reaction"

4. Scan blocks around with simple +/- x/y/z scanner

5. If (blockaround == sameblock)

6. Wait... <miracles happening>

7. BOOOOOOOM!!! Stomp, crush, destroy, smash! Set(0) and drop!

8. Profit!

 

And yes... this is me in free time:

 

 

 

Hope it helped :)

 

P.S - you can probably do that all from tool side of code, but I am too lazy to look into that, unless you want me to.

Using event will cost you one "get" (itemequiped) and one "if" statement per block broken (the rest of actual code would be launched anyway), so I guess that's not worst way to do it, but there is better.

  • Like 1

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

How many times we have to say do NOT use @$ideOnly.

Its not what it looks like.

 

So I see! Unfortunately there's a lot of tutorials floating around still using it that claim to have been "updated" for 1.7 :(

 

Use if(!world.isRemote)!

 

That indeed did the trick. Thank you sir!

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



×
×
  • Create New...

Important Information

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