diff --git a/src/main/java/net/xevianlight/aphelion/mixins/common/EntityMixin.java b/src/main/java/net/xevianlight/aphelion/mixins/common/EntityMixin.java new file mode 100644 index 0000000..b537035 --- /dev/null +++ b/src/main/java/net/xevianlight/aphelion/mixins/common/EntityMixin.java @@ -0,0 +1,67 @@ +package net.xevianlight.aphelion.mixins.common; + +import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.sugar.Local; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.neoforge.attachment.AttachmentHolder; +import net.xevianlight.aphelion.systems.GravityService; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import org.spongepowered.asm.util.Locals; + +import java.io.ObjectOutputStream; + +@Mixin(Entity.class) +public abstract class EntityMixin extends AttachmentHolder { + + + @Shadow + public float fallDistance; + + // @At("RETURN") injects at all points IMMEDIATELY before a "return" opcode. + // Immediately before means IMMEDIATELY BEFORE, + // so even in a method like: + // + // return gravity; + // + // What's ACTUALLY happening is: + // + // $value = gravity; + // return $value; + // + // So, when we inject, we get: + // + // $value = gravity; + // [RETURN INJECT POINT] + // return $value; + // + // so we get to edit $value. + @Inject(method = "getGravity", at = @At("RETURN"), cancellable = true) + public void aphelion$getGravity(CallbackInfoReturnable cir) { + cir.setReturnValue(cir.getReturnValue() * GravityService.getGravityFactor((Entity) (Object) this)); + } + + // Should only break if the code that increases fall distance is moved outside Entity$checkFallDamage. + @WrapMethod(method = "checkFallDamage") + public void aphelion$checkFallDamage(double y, boolean onGround, BlockState state, BlockPos pos, Operation original) { + float prevFallDistance = this.fallDistance; + + original.call(y, onGround, state, pos); + + float newFallDistance = this.fallDistance; + if (newFallDistance > prevFallDistance && newFallDistance > 0) { + float fallDistanceGained = newFallDistance - prevFallDistance; + this.fallDistance = prevFallDistance + (fallDistanceGained * Math.min(GravityService.getGravityFactor((Entity) (Object) this), 1)); + } + } +} diff --git a/src/main/java/net/xevianlight/aphelion/mixins/common/LivingEntityMixin.java b/src/main/java/net/xevianlight/aphelion/mixins/common/LivingEntityMixin.java index e55737a..64de1e6 100644 --- a/src/main/java/net/xevianlight/aphelion/mixins/common/LivingEntityMixin.java +++ b/src/main/java/net/xevianlight/aphelion/mixins/common/LivingEntityMixin.java @@ -31,6 +31,7 @@ public abstract class LivingEntityMixin extends Entity { @Inject(method = "travel", at = @At("HEAD")) public void aphelion$travel(Vec3 travelVector, CallbackInfo ci) { - if (this.isControlledByLocalInstance()) GravityService.onEntityTravel(level(), (LivingEntity) (Object) this); + // temporarily disabled in favor of aphelion$getGravity mixin + //if (this.isControlledByLocalInstance()) GravityService.onEntityTravel(level(), (LivingEntity) (Object) this); } } diff --git a/src/main/java/net/xevianlight/aphelion/systems/GravityService.java b/src/main/java/net/xevianlight/aphelion/systems/GravityService.java index 3804947..0a269cb 100644 --- a/src/main/java/net/xevianlight/aphelion/systems/GravityService.java +++ b/src/main/java/net/xevianlight/aphelion/systems/GravityService.java @@ -39,6 +39,16 @@ public class GravityService { return getGravityAccel(entity.level(), entityBlockPos); } + public static float getGravityFactor(Entity entity) { + float gravityAccelReal = getGravityAccel(entity); + + // How many times normal gravity you're experiencing. + // "normal gravity" varies across different entities. Thankfully, minecraft slaps a "protected" status + // on LivingEntity.getGravity(), so i graciously get to go fuck myself and not care. + // Players are 0.08 units/second/travel() of gravity (from what i've gathered) + return gravityAccelReal / GravityData.ONE_G; + } + /// Called by LivingEntity$travel mixin public static void onEntityTravel(Level level, LivingEntity entity) { if ( diff --git a/src/main/resources/aphelion.mixins.json b/src/main/resources/aphelion.mixins.json index 29e0967..73333d7 100644 --- a/src/main/resources/aphelion.mixins.json +++ b/src/main/resources/aphelion.mixins.json @@ -4,6 +4,7 @@ "package": "net.xevianlight.aphelion.mixins", "compatibilityLevel": "JAVA_21", "mixins": [ + "common.EntityMixin", "common.LivingEntityMixin" ], "client": [