Jump to content

[Solved] [1.10.2] Making sword deal extra damage to certain mobs


IceMetalPunk

Recommended Posts

I'm making a custom sword which is supposed to deal extra damage to Nether mobs (which I've defined as "any mobs immune to fire except shulkers and the Ender Dragon", since that seems to cover all of them exactly, for now). At first I was going to deal with it via event hooks, but then I realized I can just override the ItemSword#hitEntity method and deal the extra damage there.

 

Or so I thought. During testing, if I set the extra damage to something insane like 10000, it works perfectly and one-hit kills Nether mobs. But when I lower the extra damage to be the strength of the full sword damage, the entities aren't taking the proper amount of damage.

 

Here's the code I'm using:

 

package com.IceMetalPunk.amethystic.AmethysticItems;

import com.IceMetalPunk.amethystic.Amethystic;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.boss.EntityDragon;
import net.minecraft.entity.monster.EntityShulker;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemSword;
import net.minecraft.util.DamageSource;

public class ItemAmethystSword extends ItemSword {

public final float realAttackDamage;

protected ItemAmethystSword() {
	super(Amethystic.AMETHYST_MATERIAL);
	this.realAttackDamage = 3.0f + Amethystic.AMETHYST_MATERIAL.getDamageVsEntity();
	this.setUnlocalizedName("amethyst_sword").setRegistryName(Amethystic.MODID, "amethyst_sword");
	this.setCreativeTab(Amethystic.AMETHYSTIC_TAB);
}

// Make it deal more damage to Withers and Nether mobs
@Override
public boolean hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase attacker) {
	super.hitEntity(stack, target, attacker);
	if (target.isImmuneToFire() && !(target instanceof EntityShulker) && !(target instanceof EntityDragon)) {
		System.out.println(this.realAttackDamage);
		if (attacker instanceof EntityPlayer) {
			target.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) attacker), 1.0f + this.realAttackDamage);
		}
		else {
			target.attackEntityFrom(DamageSource.causeMobDamage(attacker), 1.0f + this.realAttackDamage);
		}
	}
	return true;
}

}

 

The numbers I'm using come from the fact that a sword's base attackDamage is 3 plus the material's damage (but since attackDamage is a private member, I'm creating my own here). And then that gets added via attribute modifiers to the player's own 1 damage from punching whenever they equip the sword.

 

The sword does 7 damage (same as diamond), but when I hit a Nether mob, it does less damage somehow. For example, using /entitydata for inspection, one hit dropped an unarmored zombie pigman from 20 health to 13.114-and-change health, less than 7 damage.

 

What am I missing here? This is supposed to be simple xD

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

The code you provided only attacks the enemy with the real attack damage + 1 (for both).

Well, yes. The ItemSword#hitEntity base code doesn't actually deal any damage; in fact, all it does is take item durability in a single line and then return xD I figured since the actual damage is coming from the attribute modifiers of the sword and being applied elsewhere internally, if I just use attackEntityFrom() in the method, it'll stack on top of the usual damage, hence it should be a net total of 2*damage.

 

I tested that by setting the damage amounts to 0 in both calls, and it worked fine, hitting the mobs for normal diamond sword amounts...

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

The sword does 7 damage (same as diamond), but when I hit a Nether mob, it does less damage somehow. For example, using /entitydata for inspection, one hit dropped an unarmored zombie pigman from 20 health to 13.114-and-change health, less than 7 damage.

 

What am I missing here? This is supposed to be simple xD

 

Pigmen have natural armor. Magma cubes, slimes, shulkers, zombies, and The Wither are other mobs that also have natural armor.

 

Item#hitEntity()

is called after the damage from items is done, so your implementation will do more damage than you expect. A better method to override would be

ItemSword#getDamageVsEntity()

.

Link to comment
Share on other sites

The sword does 7 damage (same as diamond), but when I hit a Nether mob, it does less damage somehow. For example, using /entitydata for inspection, one hit dropped an unarmored zombie pigman from 20 health to 13.114-and-change health, less than 7 damage.

 

What am I missing here? This is supposed to be simple xD

 

Pigmen have natural armor. Magma cubes, slimes, shulkers, zombies, and The Wither are other mobs that also have natural armor.

 

Item#hitEntity()

is called after the damage from items is done, so your implementation will do more damage than you expect. A better method to override would be

ItemSword#getDamageVsEntity()

.

 

O_o How did I never know these guys had some natural armor? *Sigh* Okay, then...that makes sense now.

 

The getDamageVsEntity method doesn't have any parameters, so how would I determine which mob is being hit in the override of that?

 

(I'm getting the feeling I'll end up *needing* to handle this in an event handler, though that seems less efficient since it would fire for every attack rather than just attacks with this particular sword...)

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

A better method to override would be ItemSword#getDamageVsEntity().

I'm unsure about that. getDamageVsEntity() seems to be called only when a mob is deciding whether or not to pick up a fallen item (and wants to compare it to what it already has). Does it also figure into the player's attack calculation? One could try setting a break point to see if it is called during combat.

 

I actually like using the hitEntity method to deal the extra damage. One thing to look out for though: You might then be bypassing the weapon cool-down, re-enabling the hit-spamming that was nerfed by Minecraft's combat upgrade. Decide if you need/want to mimic the partial damage of quick hits.

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Link to comment
Share on other sites

A better method to override would be ItemSword#getDamageVsEntity().

I'm unsure about that. getDamageVsEntity() seems to be called only when a mob is deciding whether or not to pick up a fallen item (and wants to compare it to what it already has). Does it also figure into the player's attack calculation? One could try setting a break point to see if it is called during combat.

 

I actually like using the hitEntity method to deal the extra damage. One thing to look out for though: You might then be bypassing the weapon cool-down, re-enabling the hit-spamming that was nerfed by Minecraft's combat upgrade. Decide if you need/want to mimic the partial damage of quick hits.

Yeah, I don't see it being used anywhere else, either.

 

I'm not sure how it would be bypassing the cooldown; you can't trigger the extra damage unless you hit with the sword anyway. As far as I can see, the cooldown is only reset when calling PlayerControllerMP#attackEntity or EntityPlayer#attackTargetEntityWithCurrentItem, but not with attackEntityFrom. Am I missing something?

 

*EDIT* Okay, so some more testing shows that the armor points aren't the problem here, nor am I dealing more damage than expected. In fact, the sword is dealing exactly the same amount of damage as a normal diamond sword. As I said, if I set the extra damage to something crazy like 10000, it works, but with it set to the same strength as normal, it doesn't seem to do any extra damage. I'm confused...

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

I think the point is that

hitEntity

is called even while the cooldown is active.  So you get full bonus damage even if the sword itself is dealing 0.1 damage.

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

I think the point is that

hitEntity

is called even while the cooldown is active.  So you get full bonus damage even if the sword itself is dealing 0.1 damage.

 

Ah, yes, that makes sense. Well, the actual amount of bonus damage still needs calibration, so I may end up recalculating based on the cooldown anyway. But first I need to figure out why it doesn't seem to be doing any bonus damage unless the amount is turned way, way up...

 

*EDIT* Okay, odd...I threw in some debugging console logging, and it seems like target.attackEntityFrom() is returning false. Unfortunately, there are many reasons that would happen, so I guess it's time for me to step through and find out what's going on...

 

*EDIT 2* Well...the importance of breakpoints, everyone. So it turns out the problem here is in hit-based resistance times. After getting hit, there's a small amount of time where an entity will only take damage if the attack is stronger than the previous attack. Since this attack is equivalent, and applied immediately after the first attack, it was being ignored by the resistance time. When I was testing with very high values, those were more than the "previous attack" strength, so it let them through.

 

Okay, then. Now I have a place to start with fixing this. Time to see if I can actually reset the resistance timer in order to apply the second damage...

 

*EDIT 3* If anyone's still reading this... So it turns out the resistance timer is a public member, so that was easy enough. However, in order to take cooldown into consideration, it introduces another problem: the bonus damage is triggering when the cooldown has just been reset from the normal attack, meaning it actually does no damage if cooldown is considered, and this code will only see a value of 0 for the cooldown no matter what.

 

So is there a way to get the "previous cooldown", as it were? Or should I just be ignoring cooldown and having full bonus damage? (I thought about just dealing the equivalent of target.lastDamage, but that's also protected...I hope I won't have to hack my way through this via reflection...)

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

I think the point is that

hitEntity

is called even while the cooldown is active.  So you get full bonus damage even if the sword itself is dealing 0.1 damage.

 

Ah, yes, that makes sense. Well, the actual amount of bonus damage still needs calibration, so I may end up recalculating based on the cooldown anyway. But first I need to figure out why it doesn't seem to be doing any bonus damage unless the amount is turned way, way up...

 

*EDIT* Okay, odd...I threw in some debugging console logging, and it seems like target.attackEntityFrom() is returning false. Unfortunately, there are many reasons that would happen, so I guess it's time for me to step through and find out what's going on...

 

*EDIT 2* Well...the importance of breakpoints, everyone. So it turns out the problem here is in hit-based resistance times. After getting hit, there's a small amount of time where an entity will only take damage if the attack is stronger than the previous attack. Since this attack is equivalent, and applied immediately after the first attack, it was being ignored by the resistance time. When I was testing with very high values, those were more than the "previous attack" strength, so it let them through.

 

Okay, then. Now I have a place to start with fixing this. Time to see if I can actually reset the resistance timer in order to apply the second damage...

 

*EDIT 3* If anyone's still reading this... So it turns out the resistance timer is a public member, so that was easy enough. However, in order to take cooldown into consideration, it introduces another problem: the bonus damage is triggering when the cooldown has just been reset from the normal attack, meaning it actually does no damage if cooldown is considered, and this code will only see a value of 0 for the cooldown no matter what.

 

So is there a way to get the "previous cooldown", as it were? Or should I just be ignoring cooldown and having full bonus damage? (I thought about just dealing the equivalent of target.lastDamage, but that's also protected...I hope I won't have to hack my way through this via reflection...)

I am currently wondering where entities are actually damage by the player now... the best way to figure this out would probably be to see where getDamageVsEntity() is called.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

It's got nothing to do with ItemSword#getDamageVsEntity(). Entities are damaged by the player via a call to PlayerControllerMP#attackEntity, which is called in Minecraft#clickMouse. It just uses the player's strength modifier, which is updated whenever you change your equipped item. (In other words, the sword doesn't deal any damage, it just "makes you hit stronger" by an amount equal to the sword's attack strength when it's equipped; that strength is calculated in the item's constructor based on its material's attack damage.)

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

It's got nothing to do with ItemSword#getDamageVsEntity().

If this isnt called when an entity is attacked by an item from the player there would be no point in the methods existence. PlayerControllerMp#attackEntity calls other methods figure out which one happens before resistance times are sent that are in the items class that give you the target then deal the damage there (hopefully without recursion).

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

As previously mentioned, ItemSword#getDamageVsEntity is only called in one place: when a mob that can pick up loot decides whether to pick up the item or not. It's how the mobs decide which swords are better and which should be dropped, since the ItemSword#attackDamage member is private and so couldn't be accessed from inside the mob class.

 

As for cooldown times... there are literally only two lines of code between when the game gets the normal attack strength based on the current cooldown and when it resets that cooldown. And those two lines are just straight arithmetic. There's nowhere to hook into between them...which is extremely unfortunate...

 

However, just before that calculation is made, Forge does fire an onPlayerAttackTarget event...so even though I was trying to avoid doing this with events due to its niche situations, I might have to. And the player class does have a special CooldownTracker that's public, so if I hook into it there, I should have access to the full cooldown information. Maybe; it seems quite decoupled from the ticksSinceLastSwing that all the damage calculations use, so I'll have to see what I can finagle out of it.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

You've reached the conclusion that I saw yesterday. Since you seem to want to preserve the weapon recharge rule, but still use hitEntity, I suggest this:

 

Write a simple event handler that detects your sword, peeks at the cooldown percentage, and then stores it somewhere to use a moment later in your implementation of hitEntity. Because the code-path between storage and use is so short (within one method), you might even be safe using a public field inside class ItemAmethystSword. If you nest your event handler class inside your sword class, then the field might not even need to be public.

 

Then rewrite hitEntity to implement the partial damage and also compensate for or bypass the mob's temporary immunity.

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Link to comment
Share on other sites

If I'm going to end up using event handlers anyway (which I think I'm just going to have to live with), then there's a more elegant solution: there's the PlayerEvent.AttackEntityEvent, which fires in the same method as damage calculations, but shortly before the damage calculations, i.e. when the cooldown is exactly the value needed to calculate cooldown-adjusted damage. So I can hook into that, check if the item in the player's main hand is the custom sword, and if so, cancel the default event and recalculate the damage and deal it myself (essentially copy-pasting the default code as much as possible, but with a different damage value).

 

I was hoping to avoid event handlers since they fire more generically than I'm going to need, but I guess a little inefficiency will just have to exist in this.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

An "is this my sword?" check is super cheap.  Don't even worry about it.

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

An "is this my sword?" check is super cheap.  Don't even worry about it.

Fair enough. I have a habit of trying to over-optimize to the point of impracticality xD

 

But yeah, my idea with the AttackEntityEvent hook--and a big, copypasta method for recreating the attack plus a multiplier--worked perfectly! So I guess this thread can be considered solved now.

 

Thanks for everyone's help!

Whatever Minecraft needs, it is most likely not yet another tool tier.

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

    • Hi Everyone, I'm new to the sub but needed some help figuring out a lot of the server tick issues and errors I have been getting. I run a small 1-3 player 1.19.2 forge minecraft server with around 215 or so mods (mix of QoL, server sided, performance, and client/ui mods). I run a Ryzen 5600x, 48gb of ram, and an Asus tuf 1650s. Current jvm allocation is for 12gb (overkill I know, but thought it would require so for the amount of mods I have). Typically my server had ran <20ms avg. tick, but currently has been going up closer and closer to 50ms, with sky rockets to >100ms up to around even 700ms at times. I assume it has to do with an entity ticking loop or something of the sort butn my knowledge of servers ands mods is very inept. Here is my mod list: https://mclo.gs/Yh3uW9J Here is the link to my latest.log: https://mclo.gs/uXtekkO In addition here is my debug.log: https://mclo.gs/f4zMNQQ I see a lot of errors in both logs, but cannot figure out for the life of me what mod(s) are causing them. If there is anymore info that I can provide that can help me sort this out, I am more than willing to provide it. Just want my server to run nicely lol. edit: i know the current logs show missing content. those are mods that i have already deemed not needed/not working well/as intended so they have been removed. edit #2: i have already tried using spark profiler to find the mod that is using the most resources, but to no avail. here is the link to the latest profiler i ran: https://spark.lucko.me/dIAmpPkGdo Thank you in advance!
    • i recheck the kapenjoe tutorial from another stance and actually manage to make custom trades for the villagers and the trader    seems like the wanderer has 64 normal trades and 6 especial  ### addCustomWandererTrades( generic 64) ### addCustomWandererTrades( rare    6)   ################################################## the problem is that the 3 custome trades i add rarely gets loaded in the wanderer offered item list but are there  if i delete the list whit generic.clear() before adding mi things then only mi things get loaded an a ice cube i dont know where is coming              generic.add((trader, rand) -> new MerchantOffer(                 new ItemStack(Items.EMERALD, 6),                 new ItemStack(BlockInit.POTTED_BLUE_HERB.get().asItem(), 2),                 2, 10, 0.02F)         ); it dont seems to be a weight variable to increase the possibility of mi custom trades ######################### what i want is  to increase the chance of mi custome trades to be vissible  how can i do that....          
    • For Example, Simply swords is a mod that i think looks cool. I've noticed I can use it in a world but friends can't join. Error is "Registry remapping failed: null". Is there a way to fix this or is it not possible to use with friends?
    • You could try using spark (https://www.curseforge.com/minecraft/mc-mods/spark) to see if it gives you any other insight into what is making ticks take too long, perhaps it's a combination of mods. If it's simply the yuushya mod processing that is causing it to hang, the only solution would be removing that mod, or possibly updating/downgrading to a version that doesn't make ticks take too long.
    • Looking for help with reading this crashlog for my server. I can tell yuushya causes it. I want to try to figure out what else causes this crash. I need yuushya but any other mod could get deleted if needed. https://paste.ee/p/eUS38 is the crash log
  • Topics

×
×
  • Create New...

Important Information

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