Ground pound now prevents fall damage. Fixes #351

This commit is contained in:
Sollace 2024-05-17 18:23:38 +01:00
parent fffbee84e3
commit 6a8c0d82ee
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
5 changed files with 52 additions and 47 deletions

View file

@ -20,6 +20,7 @@ import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.VecHelper;
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
@ -106,7 +107,8 @@ public class EarthPonyStompAbility implements Ability<Hit> {
public boolean apply(Pony iplayer, Hit data) {
PlayerEntity player = iplayer.asEntity();
Runnable r = () -> {
Float2FloatFunction r = fallDistance -> {
player.fallDistance = 0;
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum());
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
@ -163,13 +165,14 @@ public class EarthPonyStompAbility implements Ability<Hit> {
iplayer.subtractEnergyCost(rad);
iplayer.asEntity().addExhaustion(3);
return 0F;
};
if (iplayer.asEntity().isOnGround()) {
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
iplayer.asEntity().jump();
iplayer.updateVelocity();
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.run(), 5);
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.get(0F), 5);
} else {
thrustDownwards(iplayer);
iplayer.waitForFall(r);

View file

@ -1,6 +1,7 @@
package com.minelittlepony.unicopia.entity;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@ -38,6 +39,7 @@ import com.minelittlepony.unicopia.projectile.ProjectileImpactListener;
import com.minelittlepony.unicopia.server.world.DragonBreathStore;
import com.minelittlepony.unicopia.util.*;
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
import it.unimi.dsi.fastutil.floats.Float2ObjectFunction;
import net.fabricmc.fabric.api.util.TriState;
import net.minecraft.block.BlockState;
@ -83,7 +85,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
private final Interactable jumpingHeuristic;
@Nullable
private Runnable landEvent;
private final AtomicReference<Float2FloatFunction> landEvent = new AtomicReference<>();
private float prevFallDistance;
private boolean invisible = false;
@ -131,11 +134,11 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
this.invisible = invisible;
}
public void waitForFall(Runnable action) {
public void waitForFall(Float2FloatFunction action) {
if (entity.isOnGround()) {
action.run();
action.get(0F);
} else {
landEvent = action;
landEvent.set(action);
}
}
@ -206,6 +209,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
@Override
public boolean beforeUpdate() {
prevFallDistance = entity.fallDistance;
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
updateVelocity();
@ -236,9 +240,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
invinsibilityTicks--;
}
if (landEvent != null && entity.isOnGround() && landedChanged()) {
landEvent.run();
landEvent = null;
if (entity.isOnGround() && landedChanged()) {
onLanded(prevFallDistance);
}
if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) {
@ -261,6 +264,11 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
transportation.tick();
}
private float onLanded(float fallDistance) {
var event = landEvent.getAndSet(null);
return event == null ? fallDistance : event.get(fallDistance);
}
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {
@Nullable
EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute);
@ -465,10 +473,17 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
.isPresent();
}
protected void handleFall(float distance, float damageMultiplier, DamageSource cause) {
public float onImpact(float distance, float damageMultiplier, DamageSource cause) {
float fallDistance = onLanded(getEffectiveFallDistance(distance));
getSpellSlot().get(SpellPredicate.IS_DISGUISE, false).ifPresent(spell -> {
spell.getDisguise().onImpact(this, distance, damageMultiplier, cause);
spell.getDisguise().onImpact(this, fallDistance, damageMultiplier, cause);
});
return fallDistance;
}
protected float getEffectiveFallDistance(float distance) {
return distance;
}
@Override

View file

@ -723,9 +723,22 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
});
}
public Optional<Float> onImpact(float distance, float damageMultiplier, DamageSource cause) {
float originalDistance = distance;
@Override
public float onImpact(float distance, float damageMultiplier, DamageSource cause) {
distance = super.onImpact(distance, damageMultiplier, cause);
if (getCompositeRace().canUseEarth() && entity.isSneaking()) {
double radius = distance / 10;
if (radius > 0) {
EarthPonyStompAbility.spawnEffectAround(entity, entity.getSteppingPos(), radius, radius);
}
}
return distance;
}
@Override
protected float getEffectiveFallDistance(float distance) {
boolean extraProtection = getSpellSlot().get(SpellType.SHIELD, false).isPresent();
if (!entity.isCreative() && !entity.isSpectator()) {
@ -740,14 +753,9 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
if (getCompositeRace().canFly() || (getCompositeRace().canUseEarth() && entity.isSneaking())) {
distance -= 5;
}
distance = Math.max(0, distance);
}
handleFall(distance, damageMultiplier, cause);
if (distance != originalDistance) {
return Optional.of(distance);
}
return Optional.empty();
return Math.max(0, distance);
}
public void onEat(ItemStack stack) {
@ -762,19 +770,6 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
}
@SuppressWarnings("deprecation")
@Override
protected void handleFall(float distance, float damageMultiplier, DamageSource cause) {
super.handleFall(distance, damageMultiplier, cause);
if (getCompositeRace().canUseEarth() && entity.isSneaking()) {
double radius = distance / 10;
if (radius > 0) {
EarthPonyStompAbility.spawnEffectAround(entity, entity.getLandingPos(), radius, radius);
}
}
}
public void onKill(Entity killedEntity, DamageSource damage) {
if (killedEntity != null && killedEntity.getType() == EntityType.PHANTOM && getPhysics().isFlying()) {
UCriteria.KILL_PHANTOM_WHILE_FLYING.trigger(entity);

View file

@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.gen.Accessor;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@ -151,6 +152,11 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ
get().onDamage(source, amount).ifPresent(info::setReturnValue);
}
@ModifyVariable(method = "handleFallDamage(FFLnet/minecraft/entity/damage/DamageSource;)Z", at = @At("HEAD"), ordinal = 0, argsOnly = true)
private float onHandleFallDamage(float distance, float distanceAgain, float damageMultiplier, DamageSource cause) {
return get().onImpact(distance, damageMultiplier, cause);
}
@Inject(method = "hurtByWater()Z", at = @At("HEAD"), cancellable = true)
private void onCanBeHurtByWater(CallbackInfoReturnable<Boolean> info) {
TriState hurtByWater = get().canBeHurtByWater();

View file

@ -26,7 +26,6 @@ import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.stat.Stats;
import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@ -48,24 +47,11 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe
Pony.registerAttributes(info.getReturnValue());
}
@ModifyVariable(method = "applyDamage(Lnet/minecraft/entity/damage/DamageSource;F)V", at = @At("HEAD"), ordinal = 0)
@ModifyVariable(method = "applyDamage(Lnet/minecraft/entity/damage/DamageSource;F)V", at = @At("HEAD"), ordinal = 0, argsOnly = true)
protected float modifyDamageAmount(float amount, DamageSource source) {
return get().modifyDamage(source, amount).orElse(amount);
}
@Inject(method = "handleFallDamage(FFLnet/minecraft/entity/damage/DamageSource;)Z", at = @At("HEAD"), cancellable = true)
private void onHandleFallDamage(float distance, float damageMultiplier, DamageSource cause, CallbackInfoReturnable<Boolean> info) {
get().onImpact(fallDistance, damageMultiplier, cause).ifPresent(newDistance -> {
PlayerEntity self = (PlayerEntity)(Object)this;
if (distance >= 2) {
self.increaseStat(Stats.FALL_ONE_CM, Math.round(distance * 100));
}
info.setReturnValue(super.handleFallDamage(newDistance, damageMultiplier, cause));
});
}
@Inject(method = "eatFood(Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;", at = @At("HEAD"))
private void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> info) {
get().onEat(stack);