diff --git a/src/main/java/nekiplay/meteorplus/MeteorPlusAddon.java b/src/main/java/nekiplay/meteorplus/MeteorPlusAddon.java index f506920..70915e3 100644 --- a/src/main/java/nekiplay/meteorplus/MeteorPlusAddon.java +++ b/src/main/java/nekiplay/meteorplus/MeteorPlusAddon.java @@ -113,6 +113,7 @@ public void onInitialize() { Modules modules = Modules.get(); modules.add(new HologramModule()); + modules.add(new SprintPlus()); modules.add(new ChatPrefix()); modules.add(new ChatGPT()); modules.add(new ItemHighlightPlus()); diff --git a/src/main/java/nekiplay/meteorplus/features/modules/movement/SprintPlus.java b/src/main/java/nekiplay/meteorplus/features/modules/movement/SprintPlus.java new file mode 100644 index 0000000..a7a50d9 --- /dev/null +++ b/src/main/java/nekiplay/meteorplus/features/modules/movement/SprintPlus.java @@ -0,0 +1,38 @@ +package nekiplay.meteorplus.features.modules.movement; + +import meteordevelopment.meteorclient.settings.BoolSetting; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.systems.modules.Categories; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.player.Rotations; + +public class SprintPlus extends Module { + public SprintPlus() { + super(Categories.Movement, "sprint+", "Better sprint module."); + } + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final Setting allDirections = sgGeneral.add(new BoolSetting.Builder() + .name("All-directions") + .defaultValue(false) + .build() + ); + private final Setting ignoreBlindness = sgGeneral.add(new BoolSetting.Builder() + .name("Ignore-blindness") + .defaultValue(false) + .build() + ); + + private final Setting ignoreHunger = sgGeneral.add(new BoolSetting.Builder() + .name("Ignore-hunger") + .defaultValue(false) + .build() + ); + + public boolean shouldSprintOmnidirectionally() { return isActive() && allDirections.get(); } + + public boolean shouldIgnoreBlindness() { return isActive() && ignoreBlindness.get(); } + + public boolean shouldIgnoreHunger() { return isActive() && ignoreHunger.get(); } + +} diff --git a/src/main/java/nekiplay/meteorplus/mixin/minecraft/ClientPlayerEntityMixin.java b/src/main/java/nekiplay/meteorplus/mixin/minecraft/ClientPlayerEntityMixin.java index 2fc8e1d..838ec71 100644 --- a/src/main/java/nekiplay/meteorplus/mixin/minecraft/ClientPlayerEntityMixin.java +++ b/src/main/java/nekiplay/meteorplus/mixin/minecraft/ClientPlayerEntityMixin.java @@ -1,22 +1,29 @@ package nekiplay.meteorplus.mixin.minecraft; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.movement.Sprint; import nekiplay.meteorplus.events.PlayerUseMultiplierEvent; +import nekiplay.meteorplus.features.modules.movement.SprintPlus; import nekiplay.meteorplus.features.modules.movement.noslow.NoSlowPlus; import net.minecraft.client.input.Input; import net.minecraft.client.network.ClientPlayerEntity; 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.Inject; +import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(value = ClientPlayerEntity.class, priority = 1001) -public class ClientPlayerEntityMixin { +public abstract class ClientPlayerEntityMixin { @Shadow public Input input; + @Shadow + public abstract boolean isSubmergedInWater(); + @Shadow + protected abstract boolean isWalking(); + @Inject(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isUsingItem()Z", ordinal = 0)) private void hookCustomMultiplier(CallbackInfo ci) { final PlayerUseMultiplierEvent playerUseMultiplier = new PlayerUseMultiplierEvent(0.2f, 0.2f); @@ -44,4 +51,33 @@ private void hookSprintAffectStart(CallbackInfoReturnable cir) { cir.setReturnValue(true); } } + @Redirect(method = "tickMovement", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isWalking()Z")) + private boolean hookOmnidirectionalSprintB(ClientPlayerEntity instance) { + return isOmniWalking(instance); + } + + @ModifyConstant(method = "canSprint", constant = @Constant(floatValue = 6.0F), slice = @Slice(from = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/HungerManager;getFoodLevel()I", ordinal = 0))) + private float hookSprintIgnoreHunger(float constant) { + SprintPlus sprintPlus = Modules.get().get(SprintPlus.class); + return sprintPlus.shouldIgnoreHunger() ? -1F : constant; + } + + @ModifyExpressionValue(method = "canStartSprinting", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;hasStatusEffect(Lnet/minecraft/entity/effect/StatusEffect;)Z")) + private boolean hookSprintIgnoreBlindness(boolean original) { + SprintPlus sprintPlus = Modules.get().get(SprintPlus.class); + return !sprintPlus.shouldIgnoreBlindness() && original; + } + + @Redirect(method = "canStartSprinting", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isWalking()Z")) + private boolean hookOmnidirectionalSprintC(ClientPlayerEntity instance) { + return isOmniWalking(instance); + } + + private boolean isOmniWalking(ClientPlayerEntity instance) { + boolean hasMovement = Math.abs(instance.input.movementForward) > 1.0E-5F || Math.abs(instance.input.movementSideways) > 1.0E-5F; + boolean isWalking = (double) Math.abs(instance.input.movementForward) >= 0.8 || (double) Math.abs(instance.input.movementSideways) >= 0.8; + boolean modifiedIsWalking = this.isSubmergedInWater() ? hasMovement : isWalking; + SprintPlus sprintPlus = Modules.get().get(SprintPlus.class); + return sprintPlus.shouldSprintOmnidirectionally() ? modifiedIsWalking : this.isWalking(); + } }