diff --git a/patchwork-events-entity/src/main/java/com/patchworkmc/impl/event/entity/EntityEvents.java b/patchwork-events-entity/src/main/java/com/patchworkmc/impl/event/entity/EntityEvents.java index 7848b8c4..cbcf225c 100644 --- a/patchwork-events-entity/src/main/java/com/patchworkmc/impl/event/entity/EntityEvents.java +++ b/patchwork-events-entity/src/main/java/com/patchworkmc/impl/event/entity/EntityEvents.java @@ -28,7 +28,9 @@ import net.minecraftforge.event.entity.living.LivingDamageEvent; import net.minecraftforge.event.entity.living.LivingSpawnEvent; import net.minecraftforge.event.entity.living.LivingEvent; +import net.minecraftforge.event.entity.living.LivingFallEvent; import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.eventbus.api.Event; import net.minecraftforge.eventbus.api.Event.Result; @@ -93,6 +95,15 @@ public static float onLivingHurt(LivingEntity entity, DamageSource src, float da return MinecraftForge.EVENT_BUS.post(event) ? 0 : event.getAmount(); } + public static float[] onLivingFall(LivingEntity entity, float distance, float damageMultiplier) { + LivingFallEvent event = new LivingFallEvent(entity, distance, damageMultiplier); + return MinecraftForge.EVENT_BUS.post(event) ? null : new float[]{ event.getDistance(), event.getDamageMultiplier() }; + } + + public static void onFlyablePlayerFall(PlayerEntity player, float distance, float damageMultiplier) { + MinecraftForge.EVENT_BUS.post(new PlayerFlyableFallEvent(player, distance, damageMultiplier)); + } + public static float onLivingDamage(LivingEntity entity, DamageSource src, float damage) { LivingDamageEvent event = new LivingDamageEvent(entity, src, damage); return MinecraftForge.EVENT_BUS.post(event) ? 0 : event.getAmount(); diff --git a/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinLivingEntity.java b/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinLivingEntity.java index 8d6bc228..cb8d0512 100644 --- a/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinLivingEntity.java +++ b/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinLivingEntity.java @@ -20,6 +20,7 @@ package com.patchworkmc.mixin.event.entity; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; @@ -33,6 +34,9 @@ @Mixin(LivingEntity.class) public class MixinLivingEntity { + @Unique + private float[] fallData; + // TODO: Forge bug: PlayerEntity calls its super, so this event gets fired twice on the client. @Inject(method = "onDeath", at = @At("HEAD"), cancellable = true) private void hookDeath(DamageSource source, CallbackInfo callback) { @@ -76,6 +80,27 @@ private void hookApplyDamageForHurtEventCancel(DamageSource source, float damage } } + @ModifyVariable(method = "handleFallDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/Entity.handleFallDamage(FF)V", shift = At.Shift.BEFORE), ordinal = 0) + private float hookHandleFallDamageDistance(float distance, float damageMultiplier) { + return fallData[0]; + } + + @ModifyVariable(method = "handleFallDamage", at = @At(value = "INVOKE", target = "net/minecraft/entity/Entity.handleFallDamage(FF)V", shift = At.Shift.AFTER), ordinal = 1) + private float hookHandleFallDamageMultiplier(float distance, float damageMultiplier) { + return fallData[1]; + } + + @Inject(method = "handleFallDamage", at = @At("HEAD"), cancellable = true) + private void hookHandleFallDamageCancel(float distance, float damageMultiplier, CallbackInfo info) { + LivingEntity entity = (LivingEntity) (Object) this; + + fallData = EntityEvents.onLivingFall(entity, distance, damageMultiplier); + + if (fallData == null) { + info.cancel(); + } + } + // No shift, because we are specifically not modifying the value for this function call. // TODO: Forge patches a bit later into the function here, being inconsistent with their patch for PlayerEntity. For the moment, I don't feel like finding an injection point for that, and this may be a Forge bug? @ModifyVariable(method = "applyDamage", argsOnly = true, at = @At(value = "INVOKE", target = "net/minecraft/entity/LivingEntity.setAbsorptionAmount (F)V", ordinal = 0)) diff --git a/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinPlayerEntity.java b/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinPlayerEntity.java index 824ab685..c1397dba 100644 --- a/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinPlayerEntity.java +++ b/patchwork-events-entity/src/main/java/com/patchworkmc/mixin/event/entity/MixinPlayerEntity.java @@ -20,6 +20,7 @@ package com.patchworkmc.mixin.event.entity; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.ModifyVariable; @@ -29,6 +30,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; @@ -37,6 +39,9 @@ @Mixin(PlayerEntity.class) public class MixinPlayerEntity { + @Shadow + public PlayerAbilities abilities; + @Inject(method = "interact", at = @At("HEAD"), cancellable = true) private void hookInteractEntity(Entity entity, Hand hand, CallbackInfoReturnable callback) { PlayerEntity player = (PlayerEntity) (Object) this; @@ -99,6 +104,14 @@ private void hookApplyDamageForHurtEventCancel(DamageSource source, float damage } } + @Inject(method = "handleFallDamage", at = @At("RETURN")) + private void hookHandleFallDamage(float distance, float damageMultiplier) { + if (abilities.allowFlying) { + PlayerEntity player = (PlayerEntity) (Object) this; + EntityEvents.onFlyablePlayerFall(player, distance, damageMultiplier); + } + } + // No shift, because we are specifically not modifying the value for this function call. @ModifyVariable(method = "applyDamage", argsOnly = true, at = @At(value = "INVOKE", target = "net/minecraft/entity/player/PlayerEntity.setAbsorptionAmount (F)V", ordinal = 0)) private float hookApplyDamageForDamageEvent(float damage, DamageSource source) { diff --git a/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/living/LivingFallEvent.java b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/living/LivingFallEvent.java new file mode 100644 index 00000000..a6b91e48 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/living/LivingFallEvent.java @@ -0,0 +1,77 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.entity.living; + +import net.minecraft.entity.LivingEntity; + +/** + * LivingFallEvent is fired when a {@link LivingEntity} is set to be falling. + * + *

This event is fired whenever a {@link LivingEntity} is set to fall in + * {@link LivingEntity#fall(float, float)}.

+ * + *

For players that are able to fly, {@link net.minecraftforge.event.entity.player.PlayerFlyableFallEvent} will be fired instead.

+ * + *

This event is fired via {@link com.patchworkmc.impl.event.entity.EntityEvents#onLivingFall(LivingEntity, float, float)}.

+ * + *

{@link #distance} contains the distance the {@link LivingEntity} is to fall. If this event is cancelled, this value is set to 0.0F.

+ * + *

This event is cancellable. + * If this event is cancelled, the {@link LivingEntity} does not take fall damage.

+ * + *

This event is fired on the {@link MinecraftForge#EVENT_BUS}.

+ */ +public class LivingFallEvent extends LivingEvent { + private float distance; + private float damageMultiplier; + + // For EventBus + public LivingFallEvent() { + this(null, 0, 0); + } + + public LivingFallEvent(LivingEntity entity, float distance, float damageMultiplier) { + super(entity); + + this.setDistance(distance); + this.setDamageMultiplier(damageMultiplier); + } + + public float getDistance() { + return distance; + } + + public void setDistance(float distance) { + this.distance = distance; + } + + public float getDamageMultiplier() { + return damageMultiplier; + } + + public void setDamageMultiplier(float damageMultiplier) { + this.damageMultiplier = damageMultiplier; + } + + @Override + public boolean isCancelable() { + return true; + } +} diff --git a/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerFlyableFallEvent.java b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerFlyableFallEvent.java new file mode 100644 index 00000000..13d994f5 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerFlyableFallEvent.java @@ -0,0 +1,59 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.entity.player; + +import net.minecraft.entity.player.PlayerEntity; + +/** + * Occurs when a player falls, but is able to fly. + * {@link net.minecraftforge.event.entity.living.LivingFallEvent} will be fired for players that are not able to fly. + */ +public class PlayerFlyableFallEvent extends PlayerEvent { + private float distance; + private float multiplier; + + // For EventBus + public PlayerFlyableFallEvent() { + this(null, 0, 0); + } + + public PlayerFlyableFallEvent(PlayerEntity player, float distance, float multiplier) { + super(player); + + this.distance = distance; + this.multiplier = multiplier; + } + + public float getDistance() { + return distance; + } + + public void setDistance(float distance) { + this.distance = distance; + } + + public float getMultiplier() { + return multiplier; + } + + public void setMultiplier(float multiplier) { + this.multiplier = multiplier; + } +}