Skip to content
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

Allow setting if the critical hit should disable sweep attack in CriticalHitEvent, adding SweepAttackEvent #1496

Merged
merged 10 commits into from
Sep 24, 2024
15 changes: 11 additions & 4 deletions patches/net/minecraft/world/entity/player/Player.java.patch
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,12 @@
if (p_36347_.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE)
&& p_36347_ instanceof Projectile projectile
&& projectile.deflect(ProjectileDeflection.AIM_DEFLECT, this, this, true)) {
@@ -1170,8 +_,12 @@
@@ -1170,18 +_,26 @@
&& !this.isPassenger()
&& p_36347_ instanceof LivingEntity
&& !this.isSprinting();
+ // Neo: Fire the critical hit event and override the critical hit status and damage multiplier based on the event.
+ // The boolean local above (flag2) is the vanilla critical hit result.
+ // The boolean local above (flag1) is the vanilla critical hit result.
+ var critEvent = net.neoforged.neoforge.common.CommonHooks.fireCriticalHit(this, p_36347_, flag1, flag1 ? 1.5F : 1.0F);
+ flag1 = critEvent.isCriticalHit();
if (flag1) {
Expand All @@ -268,9 +268,16 @@
}

float f3 = f + f1;
@@ -1179,9 +_,7 @@
boolean flag2 = false;
double d0 = (double)(this.walkDist - this.walkDistO);
if (flag4 && !flag1 && !flag && this.onGround() && d0 < (double)this.getSpeed()) {
- if (flag4 && !flag1 && !flag && this.onGround() && d0 < (double)this.getSpeed()) {
+ boolean allowSweepPreconditions = flag4 && !flag && this.onGround() && d0 < (double)this.getSpeed();
+ // Neo: the boolean local above (allowSweepPreconditions) is the vanilla sweep attack condition, excluding the condition of not doing critical hit
+ // Fire the sweep attack event based on current information.
+ // The sweep attack event default result will be allowSweep && !critEvent.disableSweep()
+ // The event cannot bypass item ability check
lcy0x1 marked this conversation as resolved.
Show resolved Hide resolved
+ var sweepEvent = net.neoforged.neoforge.common.CommonHooks.fireSweepAttack(this, p_36347_, allowSweepPreconditions, critEvent.disableSweep());
+ if (sweepEvent.allowSweep()) {
ItemStack itemstack1 = this.getItemInHand(InteractionHand.MAIN_HAND);
- if (itemstack1.getItem() instanceof SwordItem) {
- flag2 = true;
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/net/neoforged/neoforge/common/CommonHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
import net.neoforged.neoforge.event.entity.player.PlayerEnchantItemEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
import net.neoforged.neoforge.event.entity.player.SweepAttackEvent;
import net.neoforged.neoforge.event.level.BlockDropsEvent;
import net.neoforged.neoforge.event.level.BlockEvent;
import net.neoforged.neoforge.event.level.NoteBlockEvent;
Expand Down Expand Up @@ -923,6 +924,18 @@ public static CriticalHitEvent fireCriticalHit(Player player, Entity target, boo
return NeoForge.EVENT_BUS.post(new CriticalHitEvent(player, target, damageModifier, vanillaCritical));
}

/**
* Fires the {@link SweepAttackEvent} and returns the resulting event.
*
* @param player The attacking player
* @param target The attack target
* @param allowSweepPreconditions If the attack would have been a sweep attack by vanilla's rules in {@link Player#attack(Entity)}, other than the condition of not critical hit.
* @param disabledByCrit If the vanilla sweep attack would have been disabled by critical hit
*/
public static SweepAttackEvent fireSweepAttack(Player player, Entity target, boolean allowSweepPreconditions, boolean disabledByCrit) {
return NeoForge.EVENT_BUS.post(new SweepAttackEvent(player, target, allowSweepPreconditions, disabledByCrit));
}

/**
* Hook to fire {@link ItemAttributeModifierEvent}. Modders should use {@link ItemStack#forEachModifier(EquipmentSlot, BiConsumer)} instead.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class CriticalHitEvent extends PlayerEvent {

private float dmgMultiplier;
private boolean isCriticalHit;
private boolean disableSweep;

/**
* Fire via {@link CommonHooks#fireCriticalHit(Player, Entity, boolean, float)}
Expand All @@ -30,7 +31,7 @@ public CriticalHitEvent(Player player, Entity target, float dmgMultiplier, boole
super(player);
this.target = target;
this.dmgMultiplier = this.vanillaDmgMultiplier = dmgMultiplier;
this.isCriticalHit = this.isVanillaCritical = isCriticalHit;
this.disableSweep = this.isCriticalHit = this.isVanillaCritical = isCriticalHit;
}

/**
Expand All @@ -44,8 +45,6 @@ public Entity getTarget() {
* The damage multiplier is applied to the base attack's damage if the attack {@linkplain #isCriticalHit() critically hits}.
* <p>
* A damage multiplier of 1.0 will not change the damage, a value of 1.5 will increase the damage by 50%, and so on.
*
* @param modifier The new damage modifier.
*/
public float getDamageMultiplier() {
return this.dmgMultiplier;
Expand All @@ -55,8 +54,8 @@ public float getDamageMultiplier() {
* Sets the damage multiplier for the critical hit. Not used if {@link #isCriticalHit()} is false.
* <p>
* Changing the damage modifier to zero does not guarantee that the attack does zero damage.
*
* @param modifier The new damage modifier. Must not be negative.
*
* @param dmgMultiplier The new damage modifier. Must not be negative.
* @see #getDamageMultiplier()
*/
public void setDamageMultiplier(float dmgMultiplier) {
Expand All @@ -74,19 +73,36 @@ public boolean isCriticalHit() {
}

/**
* Changes the critical hit state.
*
* Changes the critical hit state. If set critical hit to true, disables sweep attack
lcy0x1 marked this conversation as resolved.
Show resolved Hide resolved
*
* @param isCriticalHit true if the attack should critically hit
*/
public void setCriticalHit(boolean isCriticalHit) {
this.isCriticalHit = isCriticalHit;
if (isCriticalHit) {
this.disableSweep = true;
}
}

/**
* Changes the attack to critical hit without disabling sweep
*/
public void setCriticalHitRetainSweep() {
this.isCriticalHit = true;
}

/**
* Set if this attack should disable sweep attack
*/
public void setDisableSweep(boolean disableSweep) {
this.disableSweep = disableSweep;
}

/**
* Gets the original damage multiplier set by vanilla.
* <p>
* If the event {@link #isVanillaCritical()}, the damage multiplier will be 1.5, otherwise it will be 1.0
*
*
* @see #getDamageMultiplier()
*/
public float getVanillaMultiplier() {
Expand All @@ -99,4 +115,12 @@ public float getVanillaMultiplier() {
public boolean isVanillaCritical() {
return this.isVanillaCritical;
}

/**
* @return true if the attack would disable sweep attack.
* Note that this is only part of the sweep attack conditions.
*/
public boolean disableSweep() {
return disableSweep;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) NeoForged and contributors
* SPDX-License-Identifier: LGPL-2.1-only
*/

package net.neoforged.neoforge.event.entity.player;

import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;

public class SweepAttackEvent extends PlayerEvent {
private final Entity target;
private final boolean vanillaAllowSweepPreconditions, disabledByCrit;

private boolean allowSweep;

public SweepAttackEvent(Player player, Entity target, boolean vanillaAllowSweepPreconditions, boolean disabledByCrit) {
super(player);
this.target = target;
this.vanillaAllowSweepPreconditions = vanillaAllowSweepPreconditions;
this.disabledByCrit = disabledByCrit;
this.allowSweep = vanillaAllowSweepPreconditions && !disabledByCrit;
}

/**
* @return Attack target
*/
public Entity getTarget() {
return target;
}

/**
* @return true if the attack would have been a sweep attack by vanilla's rules in {@link Player#attack(Entity)}, other than the condition of not critical hit.
*/
public boolean vanillaAllowSweepPreconditions() {
return vanillaAllowSweepPreconditions;
}

/**
* @return true if the sweep attack would be disabled by critical hit
*/
public boolean sweepDisabledByCrit() {
return disabledByCrit;
}

/**
* @return true if the attack would have been a sweep attack by vanilla's rules in {@link Player#attack(Entity)}.
*/
public boolean vanillaAllowSweep() {
return vanillaAllowSweepPreconditions && !disabledByCrit;
}

/**
* @return true if the sweep attack would happen
*/
public boolean allowSweep() {
return allowSweep;
}

/**
* @param sweep Whether to enable sweep attack for this attack
*/
public void setAllowSweep(boolean sweep) {
allowSweep = sweep;
}
}
Loading