Fix fall damage, ladders, hitbox calculations, clipping, camera offset, and unicorn's teleportation when in inverted gravity

This commit is contained in:
Sollace 2024-03-26 17:11:39 +00:00
parent b4a847e4b5
commit 692db5a070
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
17 changed files with 203 additions and 158 deletions

View file

@ -27,6 +27,7 @@ import net.minecraft.sound.SoundCategory;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.shape.VoxelShape; import net.minecraft.util.shape.VoxelShape;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -89,8 +90,10 @@ public class UnicornTeleportAbility implements Ability<Pos> {
return trace.getBlockOrEntityPos().map(pos -> { return trace.getBlockOrEntityPos().map(pos -> {
final BlockPos originalPos = pos; final BlockPos originalPos = pos;
Direction globalUp = player.getPhysics().isGravityNegative() ? Direction.DOWN : Direction.UP;
boolean originalPosHasSupport = exception(w, pos, player.asEntity()); 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())) { if (w.getBlockState(pos).isOf(Blocks.POWDER_SNOW) && !PowderSnowBlock.canWalkOnPowderSnow(player.asEntity())) {
return null; return null;
@ -111,11 +114,11 @@ public class UnicornTeleportAbility implements Ability<Pos> {
if (pos.getX() != originalPos.getX() || pos.getZ() != originalPos.getZ()) { if (pos.getX() != originalPos.getX() || pos.getZ() != originalPos.getZ()) {
// check support // check support
int steps = 0; int steps = 0;
while (enterable(w, pos.down())) { while (enterable(w, pos.offset(globalUp.getOpposite()))) {
pos = pos.down(); pos = pos.offset(globalUp.getOpposite());
if (++steps > 2) { if (++steps > 2) {
if (originalPosValid) { if (originalPosValid) {
pos = originalPos.up(); pos = originalPos.offset(globalUp);
break; break;
} else { } else {
return null; return null;
@ -125,7 +128,7 @@ public class UnicornTeleportAbility implements Ability<Pos> {
} }
if ((!enterable(w, pos) && exception(w, pos, player.asEntity())) 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; return null;
} }

View file

@ -175,44 +175,40 @@ public class WorldRenderDelegate {
boolean negative = pony.getPhysics().isGravityNegative(); 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.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) { if (pony instanceof Pony p) {
roll = p.getCamera().calculateRoll(); float sidewaysRoll = p.getCamera().calculateRoll();
if (negative) {
roll -= 180;
}
if (p.getAcrobatics().isFloppy()) { if (p.getAcrobatics().isFloppy()) {
matrices.translate(0, -0.5, 0); matrices.translate(0, -0.5, 0);
p.asEntity().setBodyYaw(0); p.asEntity().setBodyYaw(0);
p.asEntity().setYaw(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_Y.rotationDegrees(90));
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll)); 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_X.rotationDegrees(forwardPitch));
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(yaw));
if (p.getCompositeRace().includes(Race.SEAPONY) if (p.getCompositeRace().includes(Race.SEAPONY)
&& pony.asEntity().isSubmergedInWater() && pony.asEntity().isSubmergedInWater()
&& MineLPDelegate.getInstance().getPlayerPonyRace(p.asEntity()) != Race.SEAPONY) { && MineLPDelegate.getInstance().getPlayerPonyRace(p.asEntity()) != Race.SEAPONY) {
ModelPartHooks.startCollecting(); ModelPartHooks.startCollecting();
} }
} else if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) { } else {
float roll = negative ? 180 : 0;
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(roll));
if (pony instanceof Creature creature && smittenEyesRenderer.isSmitten(creature)) {
ModelPartHooks.startCollecting(); ModelPartHooks.startCollecting();
} }
}
matrices.translate(-x, -y - owner.getHeight() / 2, -z); matrices.translate(-x, -y - owner.getHeight() / 2, -z);
@ -224,7 +220,7 @@ public class WorldRenderDelegate {
} }
private void flipAngles(Entity entity) { private void flipAngles(Entity entity) {
if (entity instanceof PlayerEntity) { if (entity instanceof PlayerEntity player) {
entity.prevYaw *= -1; entity.prevYaw *= -1;
entity.setYaw(entity.getYaw() * -1); entity.setYaw(entity.getYaw() * -1);

View file

@ -1,15 +1,15 @@
package com.minelittlepony.unicopia.command; package com.minelittlepony.unicopia.command;
import java.util.Arrays; import java.util.Collection;
import java.util.stream.Stream; import java.util.List;
import java.util.Objects;
import com.google.common.collect.Streams; import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
@ -22,45 +22,48 @@ class GravityCommand {
return CommandManager.literal("gravity").requires(s -> s.hasPermissionLevel(2)) return CommandManager.literal("gravity").requires(s -> s.hasPermissionLevel(2))
.then(CommandManager.literal("get") .then(CommandManager.literal("get")
.executes(context -> get(context.getSource(), context.getSource().getPlayer(), true)) .executes(context -> get(context.getSource(), context.getSource().getPlayer(), true))
.then(CommandManager.argument("target", EntityArgumentType.player()) .then(CommandManager.argument("target", EntityArgumentType.entity())
.executes(context -> get(context.getSource(), EntityArgumentType.getPlayer(context, "target"), false)) .executes(context -> get(context.getSource(), EntityArgumentType.getEntity(context, "target"), false))
)) ))
.then(CommandManager.literal("set") .then(CommandManager.literal("set")
.then(CommandManager.argument("gravity", FloatArgumentType.floatArg(-99, 99)) .then(CommandManager.argument("gravity", FloatArgumentType.floatArg(-99, 99))
.executes(context -> set(context.getSource(), context.getSource().getPlayer(), FloatArgumentType.getFloat(context, "gravity"), true)) .executes(context -> set(context.getSource(), List.of(context.getSource().getPlayer()), FloatArgumentType.getFloat(context, "gravity"), true))
.then(CommandManager.argument("target", EntityArgumentType.player()) .then(CommandManager.argument("target", EntityArgumentType.entities())
.executes(context -> set(context.getSource(), EntityArgumentType.getPlayer(context, "target"), FloatArgumentType.getFloat(context, "gravity"), false)) .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 { static int get(ServerCommandSource source, Entity target, boolean isSelf) throws CommandSyntaxException {
sendFeedback(source, player, "get", false, Pony.of(player).getPhysics().getGravityModifier()); Living<?> l = Living.living(target);
return 0;
}
static int set(ServerCommandSource source, PlayerEntity player, float gravity, boolean isSelf) { float gravity = l == null ? 1 : l.getPhysics().getGravityModifier();
if (source.getEntity() == target) {
Pony iplayer = Pony.of(player); source.sendFeedback(() -> Text.translatable("commands.gravity.get.self", gravity), true);
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);
} else { } else {
if (notifyTarget && source.getWorld().getGameRules().getBoolean(GameRules.SEND_COMMAND_FEEDBACK)) { source.sendFeedback(() -> Text.translatable("commands.gravity.get.other", target.getDisplayName(), gravity), true);
player.sendMessage(Text.translatable(translationKey, arguments)); }
return 0;
} }
source.sendFeedback(() -> Text.translatable(translationKey + ".other", Streams.concat(Stream.of(player.getDisplayName()), Arrays.stream(arguments)).toArray()), true); static int set(ServerCommandSource source, Collection<? extends Entity> targets, float gravity, boolean isSelf) {
List<Entity> 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;
}
} }

View file

@ -4,18 +4,13 @@ import com.minelittlepony.unicopia.entity.mob.UEntityAttributes;
import com.minelittlepony.unicopia.util.Copyable; import com.minelittlepony.unicopia.util.Copyable;
import com.minelittlepony.unicopia.util.Tickable; import com.minelittlepony.unicopia.util.Tickable;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.FenceGateBlock; import net.minecraft.block.FenceGateBlock;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.MovementType;
import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.BlockStateParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.registry.tag.BlockTags; import net.minecraft.registry.tag.BlockTags;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -37,22 +32,12 @@ public class EntityPhysics<T extends Entity> implements Physics, Copyable<Entity
@Override @Override
public void tick() { public void tick() {
if (isGravityNegative()) { if (isGravityNegative()) {
if (isGravityNegative() && !entity.isSneaking() && entity.isInSneakingPose()) {
float currentHeight = entity.getDimensions(entity.getPose()).height;
float sneakingHeight = entity.getDimensions(EntityPose.STANDING).height;
entity.move(MovementType.SELF, new Vec3d(0, -(currentHeight - sneakingHeight), 0));
entity.setPose(EntityPose.STANDING);
}
if (entity.getY() > entity.getWorld().getHeight() + 64) { if (entity.getY() > entity.getWorld().getHeight() + 64) {
entity.damage(entity.getDamageSources().outOfWorld(), 4.0F); 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) { if (gravity != lastGravity) {
lastGravity = gravity; lastGravity = gravity;
@ -87,8 +72,6 @@ public class EntityPhysics<T extends Entity> implements Physics, Copyable<Entity
@Override @Override
public BlockPos getHeadPosition() { public BlockPos getHeadPosition() {
entity.setOnGround(false);
BlockPos pos = new BlockPos( BlockPos pos = new BlockPos(
MathHelper.floor(entity.getX()), MathHelper.floor(entity.getX()),
MathHelper.floor(entity.getY() + entity.getHeight() + 0.20000000298023224D), MathHelper.floor(entity.getY() + entity.getHeight() + 0.20000000298023224D),
@ -99,29 +82,13 @@ public class EntityPhysics<T extends Entity> implements Physics, Copyable<Entity
BlockPos below = pos.down(); BlockPos below = pos.down();
BlockState block = entity.getWorld().getBlockState(below); BlockState block = entity.getWorld().getBlockState(below);
if (block.isIn(BlockTags.FENCES) || block.isIn(BlockTags.WALLS) || block.getBlock() instanceof FenceGateBlock) { if (block.isIn(BlockTags.FENCES) || block.isIn(BlockTags.WALLS) || block.getBlock() instanceof FenceGateBlock) {
entity.setOnGround(true);
return below; return below;
} }
} else {
entity.setOnGround(true);
} }
return pos; return pos;
} }
@Override
public void spawnSprintingParticles() {
BlockState state = entity.getWorld().getBlockState(getHeadPosition());
if (state.getRenderType() != BlockRenderType.INVISIBLE) {
Vec3d vel = entity.getVelocity();
entity.getWorld().addParticle(new BlockStateParticleEffect(ParticleTypes.BLOCK, state),
entity.getX() + (entity.getWorld().random.nextFloat() - 0.5D) * entity.getWidth(),
entity.getY() + entity.getHeight() - 0.1D,
entity.getZ() + (entity.getWorld().random.nextFloat() - 0.5D) * entity.getWidth(),
vel.x * -4, -1.5D, vel.z * -4);
}
}
@Override @Override
public void setBaseGravityModifier(float constant) { public void setBaseGravityModifier(float constant) {
entity.getDataTracker().set(gravity, constant); entity.getDataTracker().set(gravity, constant);

View file

@ -476,12 +476,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
return false; return false;
} }
public void onJump() {
if (getPhysics().isGravityNegative()) {
entity.setVelocity(entity.getVelocity().multiply(1, -1, 1));
}
}
@Nullable @Nullable
public final Caster<?> getAttacker() { public final Caster<?> getAttacker() {
return attacker; return attacker;

View file

@ -21,8 +21,6 @@ public interface Physics extends NbtSerialisable {
BlockPos getHeadPosition(); BlockPos getHeadPosition();
void spawnSprintingParticles();
default boolean isGravityNegative() { default boolean isGravityNegative() {
return getGravityModifier() < 0; return getGravityModifier() < 0;
} }

View file

@ -25,11 +25,7 @@ public final class PlayerDimensions {
.or(() -> physics.isFlyingSurvival ? FLYING_EYE_HEIGHT : physics.isGravityNegative() ? Optional.of(dimensions.height) : Optional.empty()) .or(() -> physics.isFlyingSurvival ? FLYING_EYE_HEIGHT : physics.isGravityNegative() ? Optional.of(dimensions.height) : Optional.empty())
.map(h -> { .map(h -> {
if (physics.isGravityNegative()) { if (physics.isGravityNegative()) {
if (pony.asEntity().isSneaking()) { return dimensions.height - h + 0.1F;
h += 0.2F;
}
return dimensions.height - h;
} }
return h; return h;
}); });

View file

@ -301,10 +301,6 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
if (entity.isOnGround() || (!creative && entity.horizontalCollision)) { if (entity.isOnGround() || (!creative && entity.horizontalCollision)) {
cancelFlight(false); cancelFlight(false);
} }
if (entity.isClimbing() && (entity.horizontalCollision || ((LivingEntityDuck)entity).isJumping())) {
velocity.y = -0.2F;
}
} }
isFlyingSurvival = entity.getAbilities().flying && !creative; isFlyingSurvival = entity.getAbilities().flying && !creative;

View file

@ -631,7 +631,7 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
float max = 0.6F; float max = 0.6F;
return Optional.of(new Vec3d( return Optional.of(new Vec3d(
MathHelper.clamp(speed.x * factor, -max, max), 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) MathHelper.clamp(speed.z * factor, -max, max)
)); ));
} }
@ -715,11 +715,8 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
} }
public Optional<Float> onImpact(float distance, float damageMultiplier, DamageSource cause) { public Optional<Float> onImpact(float distance, float damageMultiplier, DamageSource cause) {
float originalDistance = distance; float originalDistance = distance;
distance *= gravity.getGravityModifier();
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()) {

View file

@ -128,11 +128,6 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ
get().adjustMovementSpeedInWater(info.getReturnValue()).ifPresent(info::setReturnValue); 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) @Inject(method = "tick()V", at = @At("HEAD"), cancellable = true)
private void beforeTick(CallbackInfo info) { private void beforeTick(CallbackInfo info) {
if (get().beforeUpdate()) { if (get().beforeUpdate()) {
@ -186,21 +181,4 @@ abstract class MixinLivingEntity extends Entity implements LivingEntityDuck, Equ
setLivingFlag(2, hand == Hand.OFF_HAND); 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();
}
}
} }

View file

@ -27,12 +27,6 @@ abstract class MixinKeyboardInput extends Input {
pressingRight = tmp; pressingRight = tmp;
movementSideways = -movementSideways; 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) { if (EffectUtils.getAmplifier(MinecraftClient.getInstance().player, UEffects.PARALYSIS) > 1) {

View file

@ -5,6 +5,7 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift; import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject; 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.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;
@ -12,7 +13,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.entity.Equine; import com.minelittlepony.unicopia.entity.Equine;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.MovementType; import net.minecraft.entity.MovementType;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
@Mixin(value = Entity.class, priority = 29000) @Mixin(value = Entity.class, priority = 29000)
@ -21,7 +24,7 @@ abstract class MixinEntity {
// we invert y when moving // we invert y when moving
@ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true) @ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true)
private Vec3d modifyMovement(Vec3d movement) { 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.multiply(1, -1, 1);
} }
return movement; 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<Float> 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 // invert offsets so it can properly find the block we're walking on
@ModifyVariable(method = "getPosWithYOffset", at = @At("HEAD"), argsOnly = true) @ModifyVariable(method = "getPosWithYOffset", at = @At("HEAD"), argsOnly = true)
private float onGetPosWithYOffset(float offset) { private float onGetPosWithYOffset(float offset) {
@ -53,12 +48,27 @@ abstract class MixinEntity {
} }
// fix sprinting particles // fix sprinting particles
@Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) @ModifyArg(method = "spawnSprintingParticles",
protected void spawnSprintingParticles(CallbackInfo info) { 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()) { if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
eq.get().getPhysics().spawnSprintingParticles(); Entity self = eq.get().asEntity();
info.cancel(); 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 // invert check for walking up a step
@ -68,9 +78,43 @@ abstract class MixinEntity {
argsOnly = true) argsOnly = true)
private static Vec3d modifyMovementForStepheight(Vec3d movement, @Nullable Entity entity) { 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.multiply(1, -1, 1);
} }
return movement; return movement;
} }
@Inject(method = {"calculateBoundsForPose"}, at = @At("RETURN"), cancellable = true)
private void adjustPoseBoxForGravity(EntityPose pos, CallbackInfoReturnable<Box> info) {
unicopiaReAnchorBoundingBox(info);
}
@Inject(method = {"calculateBoundingBox"}, at = @At("RETURN"), cancellable = true)
private void adjustPoseBoxForGravity(CallbackInfoReturnable<Box> info) {
if (unicopiaReAnchorBoundingBox(info)) {
Entity self = (Entity)(Object)this;
self.setPos(self.getX(), info.getReturnValue().minY, self.getZ());
}
}
private boolean unicopiaReAnchorBoundingBox(CallbackInfoReturnable<Box> 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();
}
} }

View file

@ -1,11 +1,15 @@
package com.minelittlepony.unicopia.mixin.gravity; package com.minelittlepony.unicopia.mixin.gravity;
import org.spongepowered.asm.mixin.*; 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.Constant;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.ModifyConstant;
import com.minelittlepony.unicopia.entity.*; import com.minelittlepony.unicopia.entity.*;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.BlockPos;
@Mixin(LivingEntity.class) @Mixin(LivingEntity.class)
abstract class MixinLivingEntity extends Entity implements Equine.Container<Living<?>> { abstract class MixinLivingEntity extends Entity implements Equine.Container<Living<?>> {
@ -19,4 +23,23 @@ abstract class MixinLivingEntity extends Entity implements Equine.Container<Livi
private double modifyGravity(double initial) { private double modifyGravity(double initial) {
return Math.abs(get().getPhysics().calcGravity(initial)); return Math.abs(get().getPhysics().calcGravity(initial));
} }
@ModifyArg(method = "fall",
at = @At(value = "INVOKE",
target = "net/minecraft/server/world/ServerWorld.spawnParticles(Lnet/minecraft/particle/ParticleEffect;DDDIDDDD)I"),
index = 2)
private double modifyParticleY(double y) {
if (get().getPhysics().isGravityNegative()) {
return y + getHeight();
}
return y;
}
@Override
public BlockPos getBlockPos() {
if (get().getPhysics().isGravityNegative()) {
return get().getPhysics().getHeadPosition();
}
return super.getBlockPos();
}
} }

View file

@ -0,0 +1,29 @@
package com.minelittlepony.unicopia.mixin.gravity;
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.ModifyVariable;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.network.listener.ServerPlayPacketListener;
import net.minecraft.network.listener.TickablePacketListener;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.EntityTrackingListener;
@Mixin(ServerPlayNetworkHandler.class)
abstract class MixinServerPlayNetworkHandler
implements EntityTrackingListener,
TickablePacketListener,
ServerPlayPacketListener {
@Shadow public ServerPlayerEntity player;
@ModifyVariable(method = "onPlayerMove", at = @At("STORE"), ordinal = 0)
private boolean flipLandingFlag(boolean value) {
if (Pony.of(this.player).getPhysics().isGravityNegative()) {
return !value;
}
return value;
}
}

View file

@ -0,0 +1,24 @@
package com.minelittlepony.unicopia.mixin.gravity;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import com.minelittlepony.unicopia.entity.Equine;
import net.minecraft.server.network.ServerPlayerEntity;
@Mixin(ServerPlayerEntity.class)
abstract class MixinServerPlayerEntity {
@ModifyVariable(
method = "handleFall(DDDZ)V",
at = @At("HEAD"),
ordinal = 1,
argsOnly = true)
private double modifyFallDistance(double value) {
if (this instanceof Equine.Container eq && eq.get().getPhysics().isGravityNegative()) {
return -value;
}
return value;
}
}

View file

@ -1383,6 +1383,7 @@
"commands.gravity.set": "Your gravity has been updated to %f", "commands.gravity.set": "Your gravity has been updated to %f",
"commands.gravity.set.self": "Set own gravity to %f", "commands.gravity.set.self": "Set own gravity to %f",
"commands.gravity.set.other": "Set %s's gravity to %f", "commands.gravity.set.other": "Set %s's gravity to %f",
"commands.gravity.set.multiple": "Updated %s entities",
"unicopia.options.title": "Unicopia Options", "unicopia.options.title": "Unicopia Options",
"unicopia.options.ignore_mine_lp": "Ignore Mine Little Pony", "unicopia.options.ignore_mine_lp": "Ignore Mine Little Pony",

View file

@ -59,6 +59,8 @@
"gravity.MixinMobEntity", "gravity.MixinMobEntity",
"gravity.MixinWorld", "gravity.MixinWorld",
"gravity.MixinServerWorld", "gravity.MixinServerWorld",
"gravity.MixinServerPlayerEntity",
"gravity.MixinServerPlayNetworkHandler",
"gravity.MixinWorldChunk", "gravity.MixinWorldChunk",
"trinkets.MixinTrinketSurvivalSlot", "trinkets.MixinTrinketSurvivalSlot",
"trinkets.MixinTrinketItem", "trinkets.MixinTrinketItem",