Jump to content

[1.7.10] Change damage type of lightning for all entities?


Recommended Posts

Posted

I've implemented a custom damage type ("electricity") by simply creating a new public static DamageSource in my main mod class. It works fine with my custom electricity-damaging blocks, but I'd also like the direct damage from a lightning strike to be considered electricity damage. (This way, if the 5 instant damage from a bolt kills a player, it says they were electrocuted instead of burned.)

 

I don't have any experience with modifying base classes; how would I go about overriding the onStruckByLightning() method for the base entity class so that all entities that don't override it themselves will have this proper electricity behavior?

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

Posted

I'm pretty sure there's no lightningBolt damage source; it just uses the inFire damage source. But I've been looking into event listeners (I've never used them; I'm very new to modding), and I think that is the right way to go. I've found there's an EntityStruckByLightning event; I'm going to try and use that to make this work. The only thing I'm unsure about is mod compatibility; canceling getting struck by lightening could cause issues with other mods, I'd think. Hopefully, if I copy the usual code and just change the damage source, it won't be too much of a problem...

 

*EDIT* And already I've run into another problem. The default lightning-strike code increments the private member "fire". I don't have access to that variable inside the event listener, and there doesn't seem to be any method to get the current value of "fire", so it's not even possible to use setFire() to do the incrementation (even if I could, setFire() takes an int and multiplies it by 20, so I couldn't add 1 even then). How would I replicate the onStruckByLightning code in an event listener if I have this problem?

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

Posted

I'm pretty sure there's no lightningBolt damage source; it just uses the inFire damage source.

 

In 1.8 they added a lightingBolt damage source. So doing this mod would be much easier in 1.8 because as diesieben07 mentions then you could just handle the living hurt event and check for that damage source. I think in 1.7.10 you might get the most control by actually replacing the vanilla lightning bolt entity with your own, but that might require a lot of coding (or at least copying).

 

You're also right that it is bad that the fire field in Entity doesn't have a getter function (someone should submit a PR for this), while it does have a setter function. As diesieben07 mentions you should probably use reflection, but theoretically since there is a setter function you could create your own field to keep track of what it should be and call the setter function.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Sadly, the setFire() method doesn't work as you'd expect; it doesn't allow you to increase the value of the member, only decrease it. And in the case of lightning, the value needs to be increased, so I can't use the setter that comes with the Entity class.

 

I'm looking into reflection, but I'm not quite sure I understand how it works. Looking online at some examples, I tried this code to change the fire field from private to public, but I ended up getting a NoSuchField exception for "fire", even though Entity#fire is definitely a member:

 

    	/* Reflection to change private members to public for access */
    	try {
		// Get Entity#fire field and make it accessible
		Field fireField=Entity.class.getField("fire");
		fireField.setAccessible(true);

		// Make modifiers accessible
		Field modifiersField = Field.class.getDeclaredField("modifiers");
	    	modifiersField.setAccessible(true);

		// Change the modifiers on the fire field to make it public and not private.
	    try {
			modifiersField.setInt(fireField, (fireField.getModifiers() & ~Modifier.PRIVATE) | Modifier.PUBLIC);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	} catch (NoSuchFieldException e) {
		e.printStackTrace();
	} catch (SecurityException e) {
		e.printStackTrace();
	}

 

Am I not understanding something about how reflection works?

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

Posted

Oh boy if there wasn't enough help needed before, there will be soon

Field fireField=Entity.class.getField("fire");

Fire is a private field and therefore is only accessible with

Class.getDeclaredField(String)

Also note that when the code is recompiled it'll stop working since the field names are reverted to their obfuscated variants.

 

Secondly you need an object to grab local variables from. You need an entity and then you need to invoke the

set(Object targetInstance, Object newValue)

method with your now accessible field. And that's about it.

 

I'm not following why you need to change the burntime on entities struck by lightning though

I think its my java of the variables.

Posted

Oh boy if there wasn't enough help needed before, there will be soon

Field fireField=Entity.class.getField("fire");

Fire is a private field and therefore is only accessible with

Class.getDeclaredField(String)

Also note that when the code is recompiled it'll stop working since the field names are reverted to their obfuscated variants.

 

Secondly you need an object to grab local variables from. You need an entity and then you need to invoke the

set(Object targetInstance, Object newValue)

method with your now accessible field. And that's about it.

 

I'm not following why you need to change the burntime on entities struck by lightning though

 

Ah, sorry, as I said, I have absolutely zero experience with reflection in any language >_< I need to change the burntime because lightning does that already. I want everything to be exactly like the vanilla lightning, except with the DamageSource coming from my custom electricity type instead of fire damage. So I've had to cancel the entire event and replace it with my own, as there doesn't seem to be a way to simply change that source (if there is, please let me know; it'd be much easier).

 

So I've managed to make everything error-free, but I can't seem to test it to see if it works. I have this test code that should summon a lightning bolt at the player's position when a block is right-clicked:

 

	@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float px, float py, float pz) {
	world.addWeatherEffect(new EntityLightningBolt(world, px, py, pz));
	return true;
}

 

When I right-click it, I get the sky flashing and sound effects, but the lightning bolt itself doesn't appear.

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

Posted

So, I've tried many nuances of the above code, even trying to spawn lightning bolts in directly with World#spawnEntityInWorld, but nothing seems to work. I always get the proper flashing sky and sound effect, but the lightning bolt itself never appears at all. Is there something more I need to do besides just adding to the weather effects list in order to get lightning?

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

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.