From 692db5a0707c3731aaddf1af5daa0996f3a6084c Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 26 Mar 2024 17:11:39 +0000 Subject: [PATCH] Fix fall damage, ladders, hitbox calculations, clipping, camera offset, and unicorn's teleportation when in inverted gravity --- .../ability/UnicornTeleportAbility.java | 13 ++-- .../client/render/WorldRenderDelegate.java | 36 ++++----- .../unicopia/command/GravityCommand.java | 75 ++++++++++--------- .../unicopia/entity/EntityPhysics.java | 35 +-------- .../unicopia/entity/Living.java | 6 -- .../unicopia/entity/Physics.java | 2 - .../entity/player/PlayerDimensions.java | 6 +- .../unicopia/entity/player/PlayerPhysics.java | 4 - .../unicopia/entity/player/Pony.java | 5 +- .../unicopia/mixin/MixinLivingEntity.java | 22 ------ .../mixin/client/MixinKeyboardInput.java | 6 -- .../unicopia/mixin/gravity/MixinEntity.java | 72 ++++++++++++++---- .../mixin/gravity/MixinLivingEntity.java | 23 ++++++ .../MixinServerPlayNetworkHandler.java | 29 +++++++ .../gravity/MixinServerPlayerEntity.java | 24 ++++++ .../resources/assets/unicopia/lang/en_us.json | 1 + src/main/resources/unicopia.mixin.json | 2 + 17 files changed, 203 insertions(+), 158 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinServerPlayNetworkHandler.java create mode 100644 src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinServerPlayerEntity.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java index 3401632f..7f75d688 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java @@ -27,6 +27,7 @@ import net.minecraft.sound.SoundCategory; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.util.shape.VoxelShape; import net.minecraft.world.World; @@ -89,8 +90,10 @@ public class UnicornTeleportAbility implements Ability { return trace.getBlockOrEntityPos().map(pos -> { final BlockPos originalPos = pos; + Direction globalUp = player.getPhysics().isGravityNegative() ? Direction.DOWN : Direction.UP; + boolean originalPosHasSupport = exception(w, pos, player.asEntity()); - boolean originalPosValid = enterable(w, pos.up()) && enterable(w, pos.up(2)); + boolean originalPosValid = enterable(w, pos.offset(globalUp)) && enterable(w, pos.offset(globalUp, 2)); if (w.getBlockState(pos).isOf(Blocks.POWDER_SNOW) && !PowderSnowBlock.canWalkOnPowderSnow(player.asEntity())) { return null; @@ -111,11 +114,11 @@ public class UnicornTeleportAbility implements Ability { if (pos.getX() != originalPos.getX() || pos.getZ() != originalPos.getZ()) { // check support int steps = 0; - while (enterable(w, pos.down())) { - pos = pos.down(); + while (enterable(w, pos.offset(globalUp.getOpposite()))) { + pos = pos.offset(globalUp.getOpposite()); if (++steps > 2) { if (originalPosValid) { - pos = originalPos.up(); + pos = originalPos.offset(globalUp); break; } else { return null; @@ -125,7 +128,7 @@ public class UnicornTeleportAbility implements Ability { } if ((!enterable(w, pos) && exception(w, pos, player.asEntity())) - || (!enterable(w, pos.up()) && exception(w, pos.up(), player.asEntity()))) { + || (!enterable(w, pos.offset(globalUp)) && exception(w, pos.offset(globalUp), player.asEntity()))) { return null; } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java index ac9c3cdb..17594ba0 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java @@ -175,43 +175,39 @@ public class WorldRenderDelegate { boolean negative = pony.getPhysics().isGravityNegative(); - float roll = negative ? 180 : 0; - - roll = pony instanceof Pony ? ((Pony)pony).getInterpolator().interpolate("g_roll", roll, 15) : roll; - matrices.translate(x, y + owner.getHeight() / 2, z); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(roll)); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(roll)); - if (pony instanceof Pony p) { - roll = p.getCamera().calculateRoll(); - if (negative) { - roll -= 180; - } + float sidewaysRoll = p.getCamera().calculateRoll(); if (p.getAcrobatics().isFloppy()) { matrices.translate(0, -0.5, 0); p.asEntity().setBodyYaw(0); p.asEntity().setYaw(0); - matrices.multiply(RotationAxis.NEGATIVE_X.rotationDegrees(90)); + sidewaysRoll += 90; } - matrices.multiply(RotationAxis.NEGATIVE_Y.rotationDegrees(yaw)); - matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(90)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(sidewaysRoll)); + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(-90)); - float diveAngle = p.getInterpolator().interpolate("g_kdive", p.getMotion().isDiving() ? 80 : 0, 15); + float forwardPitch = p.getInterpolator().interpolate("g_kdive", p.getMotion().isDiving() ? 80 : 0, 15); - matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(diveAngle)); - matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(forwardPitch)); if (p.getCompositeRace().includes(Race.SEAPONY) && pony.asEntity().isSubmergedInWater() && MineLPDelegate.getInstance().getPlayerPonyRace(p.asEntity()) != Race.SEAPONY) { ModelPartHooks.startCollecting(); } - } else if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) { - ModelPartHooks.startCollecting(); + } else { + float roll = negative ? 180 : 0; + + matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll)); + + if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) { + ModelPartHooks.startCollecting(); + } } matrices.translate(-x, -y - owner.getHeight() / 2, -z); @@ -224,7 +220,7 @@ public class WorldRenderDelegate { } private void flipAngles(Entity entity) { - if (entity instanceof PlayerEntity) { + if (entity instanceof PlayerEntity player) { entity.prevYaw *= -1; entity.setYaw(entity.getYaw() * -1); diff --git a/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java b/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java index c99aa75b..c5249dcb 100644 --- a/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java +++ b/src/main/java/com/minelittlepony/unicopia/command/GravityCommand.java @@ -1,15 +1,15 @@ package com.minelittlepony.unicopia.command; -import java.util.Arrays; -import java.util.stream.Stream; - -import com.google.common.collect.Streams; -import com.minelittlepony.unicopia.entity.player.Pony; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import com.minelittlepony.unicopia.entity.Living; import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.command.argument.EntityArgumentType; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; @@ -22,45 +22,48 @@ class GravityCommand { return CommandManager.literal("gravity").requires(s -> s.hasPermissionLevel(2)) .then(CommandManager.literal("get") .executes(context -> get(context.getSource(), context.getSource().getPlayer(), true)) - .then(CommandManager.argument("target", EntityArgumentType.player()) - .executes(context -> get(context.getSource(), EntityArgumentType.getPlayer(context, "target"), false)) + .then(CommandManager.argument("target", EntityArgumentType.entity()) + .executes(context -> get(context.getSource(), EntityArgumentType.getEntity(context, "target"), false)) )) .then(CommandManager.literal("set") .then(CommandManager.argument("gravity", FloatArgumentType.floatArg(-99, 99)) - .executes(context -> set(context.getSource(), context.getSource().getPlayer(), FloatArgumentType.getFloat(context, "gravity"), true)) - .then(CommandManager.argument("target", EntityArgumentType.player()) - .executes(context -> set(context.getSource(), EntityArgumentType.getPlayer(context, "target"), FloatArgumentType.getFloat(context, "gravity"), false)) + .executes(context -> set(context.getSource(), List.of(context.getSource().getPlayer()), FloatArgumentType.getFloat(context, "gravity"), true)) + .then(CommandManager.argument("target", EntityArgumentType.entities()) + .executes(context -> set(context.getSource(), EntityArgumentType.getEntities(context, "target"), FloatArgumentType.getFloat(context, "gravity"), false)) ))); } - static int get(ServerCommandSource source, PlayerEntity player, boolean isSelf) throws CommandSyntaxException { - sendFeedback(source, player, "get", false, Pony.of(player).getPhysics().getGravityModifier()); - return 0; - } + static int get(ServerCommandSource source, Entity target, boolean isSelf) throws CommandSyntaxException { + Living l = Living.living(target); - static int set(ServerCommandSource source, PlayerEntity player, float gravity, boolean isSelf) { - - Pony iplayer = Pony.of(player); - - iplayer.getPhysics().setBaseGravityModifier(gravity); - iplayer.setDirty(); - - sendFeedback(source, player, "set", true, gravity); - return 0; - } - - - static void sendFeedback(ServerCommandSource source, PlayerEntity player, String key, boolean notifyTarget, Object...arguments) { - String translationKey = "commands.gravity." + key; - - if (source.getEntity() == player) { - source.sendFeedback(() -> Text.translatable(translationKey + ".self", arguments), true); + float gravity = l == null ? 1 : l.getPhysics().getGravityModifier(); + if (source.getEntity() == target) { + source.sendFeedback(() -> Text.translatable("commands.gravity.get.self", gravity), true); } else { - if (notifyTarget && source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { - player.sendMessage(Text.translatable(translationKey, arguments)); - } - - source.sendFeedback(() -> Text.translatable(translationKey + ".other", Streams.concat(Stream.of(player.getDisplayName()), Arrays.stream(arguments)).toArray()), true); + source.sendFeedback(() -> Text.translatable("commands.gravity.get.other", target.getDisplayName(), gravity), true); } + return 0; + } + + static int set(ServerCommandSource source, Collection targets, float gravity, boolean isSelf) { + List affected = targets.stream().map(Living::living).filter(Objects::nonNull).map(l -> { + l.getPhysics().setBaseGravityModifier(gravity); + l.setDirty(); + if (l.asEntity() instanceof PlayerEntity player) { + if (source.getEntity() == player) { + player.sendMessage(Text.translatable("commands.gravity.set.self", gravity)); + } else if (source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { + player.sendMessage(Text.translatable("commands.gravity.set.other", l.asEntity().getDisplayName(), gravity)); + } + } + return (Entity)l.asEntity(); + }).toList(); + + if (affected.size() == 1) { + source.sendFeedback(() -> Text.translatable("commands.gravity.set.other", affected.get(0).getDisplayName()), true); + } else { + source.sendFeedback(() -> Text.translatable("commands.gravity.set.multiple", affected.size()), true); + } + return 0; } } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java index 538e7e4a..749ee3cf 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntityPhysics.java @@ -4,18 +4,13 @@ import com.minelittlepony.unicopia.entity.mob.UEntityAttributes; import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.Tickable; -import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; import net.minecraft.block.FenceGateBlock; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityPose; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.MovementType; import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.mob.MobEntity; import net.minecraft.nbt.NbtCompound; -import net.minecraft.particle.BlockStateParticleEffect; -import net.minecraft.particle.ParticleTypes; import net.minecraft.registry.tag.BlockTags; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; @@ -37,22 +32,12 @@ public class EntityPhysics implements Physics, Copyable entity.getWorld().getHeight() + 64) { entity.damage(entity.getDamageSources().outOfWorld(), 4.0F); } - - entity.setOnGround(entity.verticalCollision && entity.getVelocity().getY() > 0); } - float gravity = this.getGravityModifier(); + float gravity = getGravityModifier(); if (gravity != lastGravity) { lastGravity = gravity; @@ -87,8 +72,6 @@ public class EntityPhysics implements Physics, Copyable implements Physics, Copyable implements Equine, Caste return false; } - public void onJump() { - if (getPhysics().isGravityNegative()) { - entity.setVelocity(entity.getVelocity().multiply(1, -1, 1)); - } - } - @Nullable public final Caster getAttacker() { return attacker; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Physics.java b/src/main/java/com/minelittlepony/unicopia/entity/Physics.java index c7aff817..bbc2d1ce 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Physics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Physics.java @@ -21,8 +21,6 @@ public interface Physics extends NbtSerialisable { BlockPos getHeadPosition(); - void spawnSprintingParticles(); - default boolean isGravityNegative() { return getGravityModifier() < 0; } diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java index 70eee553..a2e5a329 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerDimensions.java @@ -25,11 +25,7 @@ public final class PlayerDimensions { .or(() -> physics.isFlyingSurvival ? FLYING_EYE_HEIGHT : physics.isGravityNegative() ? Optional.of(dimensions.height) : Optional.empty()) .map(h -> { if (physics.isGravityNegative()) { - if (pony.asEntity().isSneaking()) { - h += 0.2F; - } - - return dimensions.height - h; + return dimensions.height - h + 0.1F; } return h; }); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java index f6c82b63..8ac41371 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/PlayerPhysics.java @@ -301,10 +301,6 @@ public class PlayerPhysics extends EntityPhysics implements Tickab if (entity.isOnGround() || (!creative && entity.horizontalCollision)) { cancelFlight(false); } - - if (entity.isClimbing() && (entity.horizontalCollision || ((LivingEntityDuck)entity).isJumping())) { - velocity.y = -0.2F; - } } isFlyingSurvival = entity.getAbilities().flying && !creative; diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 3cb7f3cf..0c78666f 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -631,7 +631,7 @@ public class Pony extends Living implements Copyable, Update float max = 0.6F; return Optional.of(new Vec3d( MathHelper.clamp(speed.x * factor, -max, max), - speed.y * ((speed.y * getPhysics().getGravitySignum()) > 0 ? 1.2 : 1.101), + speed.y * (speed.y > 0 ? 1.2 : 1.101), MathHelper.clamp(speed.z * factor, -max, max) )); } @@ -715,11 +715,8 @@ public class Pony extends Living implements Copyable, Update } public Optional onImpact(float distance, float damageMultiplier, DamageSource cause) { - float originalDistance = distance; - distance *= gravity.getGravityModifier(); - boolean extraProtection = getSpellSlot().get(SpellType.SHIELD, false).isPresent(); if (!entity.isCreative() && !entity.isSpectator()) { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java index b1e811b0..7d41f099 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinLivingEntity.java @@ -128,11 +128,6 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ get().adjustMovementSpeedInWater(info.getReturnValue()).ifPresent(info::setReturnValue); } - @Inject(method = "jump()V", at = @At("RETURN")) - private void onJump(CallbackInfo info) { - get().onJump(); - } - @Inject(method = "tick()V", at = @At("HEAD"), cancellable = true) private void beforeTick(CallbackInfo info) { if (get().beforeUpdate()) { @@ -186,21 +181,4 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ setLivingFlag(2, hand == Hand.OFF_HAND); } } - - @Override - public BlockPos getBlockPos() { - if (get().getPhysics().isGravityNegative()) { - return get().getPhysics().getHeadPosition(); - } - return super.getBlockPos(); - } - - @Override - protected void spawnSprintingParticles() { - if (get().getPhysics().isGravityNegative()) { - get().getPhysics().spawnSprintingParticles(); - } else { - super.spawnSprintingParticles(); - } - } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java index 55c8a70b..6b4240d3 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/client/MixinKeyboardInput.java @@ -27,12 +27,6 @@ abstract class MixinKeyboardInput extends Input { pressingRight = tmp; movementSideways = -movementSideways; - - /*if (player.asEntity().getAbilities().flying && !player.getPhysics().isFlying()) { - tmp = jumping; - jumping = sneaking; - sneaking = tmp; - }*/ } if (EffectUtils.getAmplifier(MinecraftClient.getInstance().player, UEffects.PARALYSIS) > 1) { diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinEntity.java index c0725d94..fe2eef70 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinEntity.java @@ -5,6 +5,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyVariable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -12,7 +13,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.entity.Equine; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityPose; import net.minecraft.entity.MovementType; +import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; @Mixin(value = Entity.class, priority = 29000) @@ -21,7 +24,7 @@ abstract class MixinEntity { // we invert y when moving @ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true) private Vec3d modifyMovement(Vec3d movement) { - if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) { + if (unicopiaIsGravityInverted()) { return movement.multiply(1, -1, 1); } return movement; @@ -35,14 +38,6 @@ abstract class MixinEntity { } } - // invert jumping velocity so we can jump - @Inject(method = "getJumpVelocityMultiplier", at = @At("RETURN"), cancellable = true) - private void onGetJumpVelocityMultiplier(CallbackInfoReturnable info) { - if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) { - info.setReturnValue(-info.getReturnValue()); - } - } - // invert offsets so it can properly find the block we're walking on @ModifyVariable(method = "getPosWithYOffset", at = @At("HEAD"), argsOnly = true) private float onGetPosWithYOffset(float offset) { @@ -53,12 +48,27 @@ abstract class MixinEntity { } // fix sprinting particles - @Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) - protected void spawnSprintingParticles(CallbackInfo info) { + @ModifyArg(method = "spawnSprintingParticles", + at = @At(value = "INVOKE", + target = "net/minecraft/world/World.addParticle(Lnet/minecraft/particle/ParticleEffect;DDDDDD)V"), + index = 2) + private double modifyParticleY(double y) { if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) { - eq.get().getPhysics().spawnSprintingParticles(); - info.cancel(); + Entity self = eq.get().asEntity(); + return self.getHeight() - y + (self.getY() * 2); } + return y; + } + + // fix fall damage + @ModifyArg( + method = "move", + at = @At(value = "INVOKE", target = "net/minecraft/entity/Entity.fall(DZLnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;)V")) + private double modifyFallDistance(double heightDifference) { + if (unicopiaIsGravityInverted()) { + return -heightDifference; + } + return heightDifference; } // invert check for walking up a step @@ -68,9 +78,43 @@ abstract class MixinEntity { argsOnly = true) private static Vec3d modifyMovementForStepheight(Vec3d movement, @Nullable Entity entity) { - if (entity != null && movement.getY() == entity.getStepHeight()) { + if (entity instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative() && movement.getY() == entity.getStepHeight()) { return movement.multiply(1, -1, 1); } return movement; } + + @Inject(method = {"calculateBoundsForPose"}, at = @At("RETURN"), cancellable = true) + private void adjustPoseBoxForGravity(EntityPose pos, CallbackInfoReturnable info) { + unicopiaReAnchorBoundingBox(info); + } + + @Inject(method = {"calculateBoundingBox"}, at = @At("RETURN"), cancellable = true) + private void adjustPoseBoxForGravity(CallbackInfoReturnable info) { + if (unicopiaReAnchorBoundingBox(info)) { + Entity self = (Entity)(Object)this; + self.setPos(self.getX(), info.getReturnValue().minY, self.getZ()); + } + } + + private boolean unicopiaReAnchorBoundingBox(CallbackInfoReturnable info) { + if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) { + Entity self = eq.get().asEntity(); + Box box = info.getReturnValue(); + Box oldBox = self.getBoundingBox(); + double newHeight = box.getYLength(); + if (newHeight > oldBox.getYLength()) { + double targetMaxY = oldBox.maxY; + Vec3d min = new Vec3d(box.minX, targetMaxY - newHeight, box.minZ); + Vec3d max = new Vec3d(box.maxX, targetMaxY, box.maxZ); + info.setReturnValue(new Box(min, max)); + return true; + } + } + return false; + } + + private boolean unicopiaIsGravityInverted() { + return this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative(); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinLivingEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinLivingEntity.java index 2d9dfe6c..368eb0d8 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinLivingEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/gravity/MixinLivingEntity.java @@ -1,11 +1,15 @@ package com.minelittlepony.unicopia.mixin.gravity; import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyArg; import org.spongepowered.asm.mixin.injection.ModifyConstant; import com.minelittlepony.unicopia.entity.*; + import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.BlockPos; @Mixin(LivingEntity.class) abstract class MixinLivingEntity extends Entity implements Equine.Container> { @@ -19,4 +23,23 @@ abstract class MixinLivingEntity extends Entity implements Equine.Container