mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-01 19:46:42 +01:00
Ground pound now prevents fall damage. Fixes #351
This commit is contained in:
parent
fffbee84e3
commit
6a8c0d82ee
5 changed files with 52 additions and 47 deletions
|
@ -20,6 +20,7 @@ import com.minelittlepony.unicopia.server.world.BlockDestructionManager;
|
||||||
import com.minelittlepony.unicopia.util.PosHelper;
|
import com.minelittlepony.unicopia.util.PosHelper;
|
||||||
import com.minelittlepony.unicopia.util.VecHelper;
|
import com.minelittlepony.unicopia.util.VecHelper;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.enchantment.EnchantmentHelper;
|
import net.minecraft.enchantment.EnchantmentHelper;
|
||||||
|
@ -106,7 +107,8 @@ public class EarthPonyStompAbility implements Ability<Hit> {
|
||||||
public boolean apply(Pony iplayer, Hit data) {
|
public boolean apply(Pony iplayer, Hit data) {
|
||||||
PlayerEntity player = iplayer.asEntity();
|
PlayerEntity player = iplayer.asEntity();
|
||||||
|
|
||||||
Runnable r = () -> {
|
Float2FloatFunction r = fallDistance -> {
|
||||||
|
player.fallDistance = 0;
|
||||||
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum());
|
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos(), iplayer.getPhysics().getGravitySignum());
|
||||||
|
|
||||||
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
|
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
|
||||||
|
@ -163,13 +165,14 @@ public class EarthPonyStompAbility implements Ability<Hit> {
|
||||||
|
|
||||||
iplayer.subtractEnergyCost(rad);
|
iplayer.subtractEnergyCost(rad);
|
||||||
iplayer.asEntity().addExhaustion(3);
|
iplayer.asEntity().addExhaustion(3);
|
||||||
|
return 0F;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (iplayer.asEntity().isOnGround()) {
|
if (iplayer.asEntity().isOnGround()) {
|
||||||
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
|
iplayer.setAnimation(Animation.STOMP, Animation.Recipient.ANYONE, 10);
|
||||||
iplayer.asEntity().jump();
|
iplayer.asEntity().jump();
|
||||||
iplayer.updateVelocity();
|
iplayer.updateVelocity();
|
||||||
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.run(), 5);
|
AwaitTickQueue.scheduleTask(iplayer.asWorld(), w -> r.get(0F), 5);
|
||||||
} else {
|
} else {
|
||||||
thrustDownwards(iplayer);
|
thrustDownwards(iplayer);
|
||||||
iplayer.waitForFall(r);
|
iplayer.waitForFall(r);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.minelittlepony.unicopia.entity;
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
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.server.world.DragonBreathStore;
|
||||||
import com.minelittlepony.unicopia.util.*;
|
import com.minelittlepony.unicopia.util.*;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
|
||||||
import it.unimi.dsi.fastutil.floats.Float2ObjectFunction;
|
import it.unimi.dsi.fastutil.floats.Float2ObjectFunction;
|
||||||
import net.fabricmc.fabric.api.util.TriState;
|
import net.fabricmc.fabric.api.util.TriState;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
@ -83,7 +85,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
private final Interactable jumpingHeuristic;
|
private final Interactable jumpingHeuristic;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Runnable landEvent;
|
private final AtomicReference<Float2FloatFunction> landEvent = new AtomicReference<>();
|
||||||
|
private float prevFallDistance;
|
||||||
|
|
||||||
private boolean invisible = false;
|
private boolean invisible = false;
|
||||||
|
|
||||||
|
@ -131,11 +134,11 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
this.invisible = invisible;
|
this.invisible = invisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForFall(Runnable action) {
|
public void waitForFall(Float2FloatFunction action) {
|
||||||
if (entity.isOnGround()) {
|
if (entity.isOnGround()) {
|
||||||
action.run();
|
action.get(0F);
|
||||||
} else {
|
} else {
|
||||||
landEvent = action;
|
landEvent.set(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +209,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean beforeUpdate() {
|
public boolean beforeUpdate() {
|
||||||
|
prevFallDistance = entity.fallDistance;
|
||||||
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
|
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
|
||||||
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
|
entity.setVelocity(entity.getVelocity().multiply(0, 1, 0));
|
||||||
updateVelocity();
|
updateVelocity();
|
||||||
|
@ -236,9 +240,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
invinsibilityTicks--;
|
invinsibilityTicks--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (landEvent != null && entity.isOnGround() && landedChanged()) {
|
if (entity.isOnGround() && landedChanged()) {
|
||||||
landEvent.run();
|
onLanded(prevFallDistance);
|
||||||
landEvent = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.hasStatusEffect(UEffects.PARALYSIS) && entity.getVelocity().horizontalLengthSquared() > 0) {
|
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();
|
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) {
|
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {
|
||||||
@Nullable
|
@Nullable
|
||||||
EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute);
|
EntityAttributeInstance instance = asEntity().getAttributeInstance(attribute);
|
||||||
|
@ -465,10 +473,17 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
.isPresent();
|
.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 -> {
|
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
|
@Override
|
||||||
|
|
|
@ -723,9 +723,22 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Float> onImpact(float distance, float damageMultiplier, DamageSource cause) {
|
@Override
|
||||||
float originalDistance = distance;
|
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();
|
boolean extraProtection = getSpellSlot().get(SpellType.SHIELD, false).isPresent();
|
||||||
|
|
||||||
if (!entity.isCreative() && !entity.isSpectator()) {
|
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())) {
|
if (getCompositeRace().canFly() || (getCompositeRace().canUseEarth() && entity.isSneaking())) {
|
||||||
distance -= 5;
|
distance -= 5;
|
||||||
}
|
}
|
||||||
distance = Math.max(0, distance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFall(distance, damageMultiplier, cause);
|
return Math.max(0, distance);
|
||||||
if (distance != originalDistance) {
|
|
||||||
return Optional.of(distance);
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEat(ItemStack stack) {
|
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) {
|
public void onKill(Entity killedEntity, DamageSource damage) {
|
||||||
if (killedEntity != null && killedEntity.getType() == EntityType.PHANTOM && getPhysics().isFlying()) {
|
if (killedEntity != null && killedEntity.getType() == EntityType.PHANTOM && getPhysics().isFlying()) {
|
||||||
UCriteria.KILL_PHANTOM_WHILE_FLYING.trigger(entity);
|
UCriteria.KILL_PHANTOM_WHILE_FLYING.trigger(entity);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.*;
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
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.CallbackInfo;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
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);
|
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)
|
@Inject(method = "hurtByWater()Z", at = @At("HEAD"), cancellable = true)
|
||||||
private void onCanBeHurtByWater(CallbackInfoReturnable<Boolean> info) {
|
private void onCanBeHurtByWater(CallbackInfoReturnable<Boolean> info) {
|
||||||
TriState hurtByWater = get().canBeHurtByWater();
|
TriState hurtByWater = get().canBeHurtByWater();
|
||||||
|
|
|
@ -26,7 +26,6 @@ import net.minecraft.entity.damage.DamageSource;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.stat.Stats;
|
|
||||||
import net.minecraft.util.Unit;
|
import net.minecraft.util.Unit;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
@ -48,24 +47,11 @@ abstract class MixinPlayerEntity extends LivingEntity implements Equine.Containe
|
||||||
Pony.registerAttributes(info.getReturnValue());
|
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) {
|
protected float modifyDamageAmount(float amount, DamageSource source) {
|
||||||
return get().modifyDamage(source, amount).orElse(amount);
|
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"))
|
@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) {
|
private void onEatFood(World world, ItemStack stack, CallbackInfoReturnable<ItemStack> info) {
|
||||||
get().onEat(stack);
|
get().onEat(stack);
|
||||||
|
|
Loading…
Reference in a new issue