LoVisual/combatant-client-26.2/src/main/java/dev/loki/lovisual/mixins/EntityMixin.java
2026-07-30 11:12:56 +02:00

189 lines
6.9 KiB
Java

/*
* This file is part of the Combatant Client distribution.
* Copyright (c) 2026 pivosos2007.
*
* Licensed under the GNU General Public License v3.0.
*/
package dev.loki.lovisual.mixins;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import dev.loki.lovisual.events.Events;
import dev.loki.lovisual.events.impl.PlayerMoveEvent;
import dev.loki.lovisual.events.impl.PlayerStepEvent;
import dev.loki.lovisual.events.impl.PlayerStepSuccessEvent;
import dev.loki.lovisual.events.impl.PlayerVelocityStrafe;
import dev.loki.lovisual.features.module.Modules;
import dev.loki.lovisual.features.module.modules.movement.NoPush;
import dev.loki.lovisual.features.module.modules.movement.NoStun;
import dev.loki.lovisual.mixininterface.IEntity;
import dev.loki.lovisual.mixins.accessors.EntityAccessor;
import dev.loki.lovisual.mixins.accessors.EntityInvoker;
import dev.loki.lovisual.render.helpers.TrailPoint;
import dev.loki.lovisual.util.aiming.RotationManager;
import java.util.ArrayList;
import java.util.List;
@Mixin(Entity.class)
public abstract class EntityMixin implements IEntity {
@Unique
private final List<TrailPoint> trails = new ArrayList<>();
@Shadow
public double xOld;
@Shadow
public double yOld;
@Shadow
public double zOld;
@Unique
private MoverType combatant$lastMoveType = MoverType.SELF;
@Unique
private Vec3 combatant$stepBeforePos = Vec3.ZERO;
@Unique
private Vec3 combatant$stepRequestedMovement = Vec3.ZERO;
@Unique
@Override
public Vec3 get$InstantRenderPos() {
return new Vec3(xOld, yOld, zOld);
}
@Unique
@Override
public List<TrailPoint> combatant$getTrails() {
return trails;
}
@Inject(method = "move", at = @At("HEAD"))
private void combatant$cacheMoveType(MoverType type, Vec3 movement, CallbackInfo ci) {
combatant$lastMoveType = type;
Entity self = (Entity) (Object) this;
if (self instanceof LocalPlayer) {
combatant$stepBeforePos = self.position();
combatant$stepRequestedMovement = movement;
}
}
@ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true, index = 2)
private Vec3 combatant$onMove(Vec3 movement) {
Entity self = (Entity) (Object) this;
if (!(self instanceof LocalPlayer)) return movement;
if (!Events.BUS.hasListeners(PlayerMoveEvent.class)) return movement;
PlayerMoveEvent event = new PlayerMoveEvent(combatant$lastMoveType, movement);
Events.BUS.post(event);
Vec3 out = event.getMovement();
return out != null ? out : movement;
}
@Inject(method = "move", at = @At("RETURN"))
private void combatant$onMoveReturn(MoverType type, Vec3 movement, CallbackInfo ci) {
Entity self = (Entity) (Object) this;
if (!(self instanceof LocalPlayer)) return;
if (!Events.BUS.hasListeners(PlayerStepSuccessEvent.class)) return;
Vec3 before = combatant$stepBeforePos;
Vec3 after = self.position();
Vec3 requested = combatant$stepRequestedMovement;
double yDelta = after.y - before.y;
double horizontalRequested = Math.hypot(requested.x, requested.z);
if (yDelta <= 0.5 || horizontalRequested <= 1.0E-5) return;
Events.BUS.post(new PlayerStepSuccessEvent(after.subtract(before)));
}
@ModifyReturnValue(method = "maxUpStep", at = @At("RETURN"))
private float combatant$modifyStepHeight(float original) {
Entity self = (Entity) (Object) this;
if (!(self instanceof LocalPlayer)) return original;
if (!Events.BUS.hasListeners(PlayerStepEvent.class)) return original;
PlayerStepEvent event = new PlayerStepEvent(original);
Events.BUS.post(event);
return event.getHeight();
}
@Redirect(
method = "moveRelative",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Entity;getInputVector(Lnet/minecraft/world/phys/Vec3;FF)Lnet/minecraft/world/phys/Vec3;"
)
)
private Vec3 combatant$velocityStrafe(Vec3 movementInput, float speed, float yaw) {
Entity self = (Entity) (Object) this;
Vec3 vanilla = EntityInvoker.combatant$movementInputToVelocity(movementInput, speed, yaw);
if (!(self instanceof LocalPlayer)) return vanilla;
if (!Events.BUS.hasListeners(PlayerVelocityStrafe.class)) return vanilla;
PlayerVelocityStrafe event = new PlayerVelocityStrafe(movementInput, speed, yaw, vanilla);
Events.BUS.post(event);
return event.getVelocity();
}
@ModifyVariable(
method = "calculateViewVector(FF)Lnet/minecraft/world/phys/Vec3;",
at = @At("HEAD"),
ordinal = 0,
argsOnly = true
)
private float combatant$rotationVectorPitch(float pitch) {
if (!((Object) this instanceof LocalPlayer)) {
return pitch;
}
return RotationManager.INSTANCE.getCurrentRotation() != null
? RotationManager.INSTANCE.getCurrentRotation().pitch()
: pitch;
}
@Redirect(
method = "push(Lnet/minecraft/world/entity/Entity;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Entity;push(DDD)V"
)
)
private void combatant$cancelEntityPush(Entity instance, double x, double y, double z) {
NoPush noPush = Modules.get(NoPush.class);
if (noPush == null || !noPush.off("players")) {
instance.push(x, y, z);
}
}
@Inject(method = "makeStuckInBlock", at = @At("HEAD"), cancellable = true)
private void nostun$cancelSlowMovement(BlockState state, Vec3 multiplier, CallbackInfo ci) {
Entity self = (Entity) (Object) this;
if (!(self instanceof LocalPlayer)) return;
NoStun ns = Modules.get(NoStun.class);
if (ns == null || !ns.isEnabled()) return;
Vec3 override = ns.getSlowMovementOverride(state, multiplier);
if (override != null && self instanceof EntityAccessor accessor) {
self.resetFallDistance();
accessor.combatant$setMovementMultiplier(override);
ci.cancel();
return;
}
if (ns.shouldCancelSlowMovement(state)) {
ci.cancel();
}
}
}