New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented LivingKnockBackEvent event and hook #4503
Conversation
Added LivingKnockBackEvent event, added onLivingKnockBack method to ForgeHooks, added onLivingKnockBack check into EntityLivingBase knockBack method. Added KnockBackHookTest test mod.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hook looks ok, but there are a few style points.
Make sure to use spaces for indentation for consistency with the rest of the codebase.
Also try to keep changes in patches strictly to what you need to implement your hook: don't touch imports and only commit the patch files you actually worked on.
import net.minecraftforge.fml.relauncher.Side; | ||
import net.minecraftforge.fml.relauncher.SideOnly; | ||
-import org.apache.logging.log4j.LogManager; | ||
-import org.apache.logging.log4j.Logger; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't change imports in patches.
|
||
public void func_70653_a(Entity p_70653_1_, float p_70653_2_, double p_70653_3_, double p_70653_5_) | ||
{ | ||
+ if (!net.minecraftforge.common.ForgeHooks.onLivingKnockBack(this, p_70653_1_, p_70653_2_, p_70653_3_, p_70653_5_)) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The formatting here doesn't match, check spaces are being used.
@@ -68,7 +68,7 @@ | |||
CreativeTabs creativetabs = this.func_77640_w(); | |||
return creativetabs != null && (p_194125_1_ == CreativeTabs.field_78027_g || p_194125_1_ == creativetabs); | |||
} | |||
@@ -435,11 +445,704 @@ | |||
@@ -435,11 +441,704 @@ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You aren't really changing the contents of this file, so leave it out of the PR.
@@ -559,6 +560,11 @@ public static boolean onLivingAttack(EntityLivingBase entity, DamageSource src, | |||
return !MinecraftForge.EVENT_BUS.post(new LivingAttackEvent(entity, src, amount)); | |||
} | |||
|
|||
public static boolean onLivingKnockBack(EntityLivingBase target, Entity attacker, float strength, double ratioX, double ratioZ) | |||
{ | |||
return !MinecraftForge.EVENT_BUS.post(new LivingKnockBackEvent(target, attacker, strength, ratioX, ratioZ)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you are negating the result when using this function, it'd be better to avoid the double-negation by just returning the result here directly.
import net.minecraftforge.fml.common.eventhandler.Cancelable; | ||
|
||
/** | ||
* LivingAttackEvent is fired when a living entity is about to be knocked back. <br> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be LivingKnockBackEvent
?
{ | ||
private final Entity attacker; | ||
private float strength; | ||
private double ratioX, ratioZ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These values can be final
as well.
import net.minecraftforge.fml.common.Mod; | ||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; | ||
|
||
@Mod(modid = "kbhtest", name = "Knock Back Hook Test") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a version = "1.0"
element here, to prevent a warning being logged.
@SubscribeEvent | ||
public static void onKnockBack(LivingKnockBackEvent event) | ||
{ | ||
if(event.getEntityLiving() instanceof EntitySheep) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make this mod be disabled by default?
@@ -0,0 +1,57 @@ | |||
package net.minecraftforge.event.entity.living; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file needs a license header.
LivingKnockBackEvent supports changing the values.
Generated patches.
Replaced tabs with spaces, restored unused imports, removed Item.java.patch from the PR, added a license header to and fixed LivingKnockBackEvent's description, removed unnecessary negation for the event post, fixed test mod parameters, disabled test mod by default.
I think a good way to handle allowing changes to the values is to patch in a block of code like this at the start of the net.minecraftforge.event.entity.living.LivingKnockBackEvent event
= net.minecraftforge.common.ForgeHooks.onLivingKnockBack(this, entityIn, strength, xRatio, zRatio);
if (event.isCanceled()) return;
strength = event.getStrength(); xRatio = event.getRatioX(); zRatio = event.getRatioZ(); Have the hook method construct and post the event as before, but then return the event itself, rather than a boolean. Then you can overwrite the passed in parameters with the new values from the event. The reason I'd suggest doing it this way is to keep all the code changes in one block, and to avoid needing to touch the vanilla logic. |
Event hook now initializes, posts and returns the event. knockBack method changed accordingly.
@bs2609 I fixed all the issues you pointed out. Will you approve now? When will these additions be merged with forge? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more cleanup required before it'll be approved. Lex is very strict about the standards: the smaller a patch file is, the better.
import javax.annotation.Nullable; | ||
+ | ||
+import org.apache.logging.log4j.LogManager; | ||
+import org.apache.logging.log4j.Logger; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have unused imports
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a patch, no touchy imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So do I have to remove the unused imports or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Minecraft vanilla files do not ever touch imports, ever ever ever. You have added several, REMOVE THEM.
|
||
public void func_70653_a(Entity p_70653_1_, float p_70653_2_, double p_70653_3_, double p_70653_5_) | ||
{ | ||
+ LivingKnockBackEvent event = net.minecraftforge.common.ForgeHooks.onLivingKnockBack(this, p_70653_1_, p_70653_2_, p_70653_3_, p_70653_5_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use a fully qualified name, rather than an import here; net.minecraftforge.event.entity.living.LivingKnockBackEvent event = ...
import javax.annotation.Nullable; | ||
|
||
import org.apache.commons.io.FilenameUtils; | ||
import org.apache.commons.io.IOUtils; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've reorganized the imports here, these lines have shifted place. Don't do this, it makes the patch files larger for no reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a forge class. Imports should be added but not organized, its entirely up to the users IDE as to how they are ordered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I don't have to organize them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, don't organize them. (And you're right @covers1624 it's a Forge class, not a patch, I missed that, but it still needs to be fixed).
{ | ||
this.field_70181_x /= 2.0D; | ||
- this.field_70181_x += (double)p_70653_2_; | ||
+ this.field_70181_x += (double) p_70653_2_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You have added a space here (double) p_70653_2_
which causes additional lines in the patch file that do precisely nothing.
Removed unused imports (again because I though they weren't mine), used full paths instead of imports in vanilla code, removed unnecessary spaces, restored imports to previous order.
@Draco18s I fixed everything, please approve. The question still stands: when will the additions be merged and released? |
You need to wait for mezz to review the PR. If they think it's ok, they'll assign it to Lex for final approval. |
Looks much better now. Inclusion is primarily up to folks like Lex and mezz, who will review it at some point. Getting PRs added can be a lengthy process. |
Well thanks to everyone for the input. Here's hoping it will get added soon, I really need this for my mod. |
This is a useful event. It is a shame that more information about the context of why the knockback is occurring cannot be passed in. I understand that it is cleanest to hook into the knockback() method so you only have the parameters available that that method gets (plus the target entity in which the method is being called). It would be a lot cooler though if the DamageSource could be passed in as well, and also if you could determine if the knockback was due to blocking with shield. In other words, instead of firing the event inside the knockback() method it would be much more useful if it was fired outside the method and a bit more information passed along. But it is still pretty cool as is, and could always be extended in an unbreaking way later. |
@Mod.EventBusSubscriber | ||
public class KnockBackHookTest | ||
{ | ||
private static final boolean ENABLED = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you put 4 spaces for tabs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As liach says, please use spaces for indentation.
{ | ||
protected Entity attacker; | ||
protected float strength; | ||
protected double ratioX, ratioZ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
protected final Entity attacker;
protected float strength;
protected double ratioX, ratioZ;
protected final float originalStrength;
protected final double originalRatioX, originalRatioZ;
public LivingKnockBackEvent(EntityLivingBase target, Entity attacker, float strength, double ratioX, double ratioZ)
{
super(target);
this.attacker = attacker;
this.originalStrength = strength;
this.originalRatioX = ratioX;
this.originalRatioZ = ratioZ;
this.strength = strength;
this.ratioX = ratioX;
this.ratioZ = ratioZ;
}
In case of multiple mods modifying the same event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good suggestion from liach, please add the "original" values as final values, so mods using the events can have more information about modifications to the values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good. Please address the remaining comments and then I will test this out.
Consider jabelar's comment as well, and see if you can fire this in a location that gives it access to the damage source and if there is a shield. That will make the event useful in more situations.
@Mod.EventBusSubscriber | ||
public class KnockBackHookTest | ||
{ | ||
private static final boolean ENABLED = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As liach says, please use spaces for indentation.
{ | ||
protected Entity attacker; | ||
protected float strength; | ||
protected double ratioX, ratioZ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good suggestion from liach, please add the "original" values as final values, so mods using the events can have more information about modifications to the values.
@mezz @jabelar I'll get around to fixing the issues. However, I'm not sure how to go about passing more information to the event. I could add the event to every knockBack() method call, but that would require modifying at least 4 different classes and wouldn't work if other modders called the method. I could add more params to the knockBack() method, but I'm not sure that's a good idea for compatibility or similar issues. |
I guess for now just keep it simple, the way it is. |
Added original fields and getters for the event's params, fixed indentation in the test mod.
@mezz Alright, I've added everything you pointed out. Will this be added to the api now? Also, why do none of the other events with changeable params have original fields? |
{ | ||
protected Entity attacker; | ||
protected float strength; | ||
protected double ratioX, ratioZ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed now.
Tested and works as expected. |
Changes
Added LivingKnockBackEvent event, added onLivingKnockBack method to ForgeHooks, added onLivingKnockBack check and values into EntityLivingBase knockBack method. Added KnockBackHookTest test mod.
Why?
This event fixes the problems with hard-coded vanilla knock back. Modders can now cancel, change or add their own knock back to entities with quite a few parameters at their disposal. I've seen a few threads asking for this type of event before.
This addition is absolutely necessary to me as currently I'm creating a mod that adds a few new attributes for items including a knock back attribute. Using events like LivingAttackEvent to cancel knock back is very inefficient, sometimes inconsistent and potentially unstable.
How does it work?
It's as simple as any other event in forge. The LivingKnockBackEvent contains a few handy parameters like the attacker, strength and ratios which can be changed resulting in a highly flexible event.
I added a test mod KnockBackHookTest for anyone doubting the hook's functionality.