I Didn't Update the AutoRun Minecraft Mod to 1.17 but I Did Add a Feature

I sought out auto run functionality in the form of a Minecraft mod earlier this year. I found AutoRun which was exactly what I was looking for. In this mod, you hit a keybind and start moving, so you don't have to hold down 'w' or whatever direction you were moving. This also applies to elytra movement.

Originally, I was going to update it to 1.17, but the author beat me to the punch because my development environment was broken. However, I ran into an issue that convinced me to contribute in another way.

https://i.imgur.com/FNZiGH9.png

AutoRun on CurseForge

The Problem

Usually, when I want to auto run, it's because I'm lazy and don't want to hold down a key, or I want to take a sip of water or scroll through my phone or write something down. Notice each of these things occupies one hand. If I want a sip of water, I use my right hand. If I want to write something down, I use my left hand. And of course usually I want to sprint while autorunning. The default sprint key is left-ctrl on the keyboard, but I typically use a keybind on my mouse to sprint. However, I still like having the option to use ctrl in case one of the described scenarios occurs and the sprint gets canceled from some other in-game factor. This presents a minor annoyance, because you can only bind one key to each action. If one of my hands is occupied, I have to reach over with the other or put down what I am holding. Well, I say it was minor, but it was major enough for me to spend time programming a solution.

Nearly every other game can double up keybinds on a single action, why can't Minecraft??

https://i.imgur.com/IhyOrcM.png

PUBG keybinds. Notice how you can have two keybinds for the same action

The Solution

Since half the time this issue comes up before, during or after autorunning, especially when I bump into things and the sprint is cancelled, I decided that the AutoRun mod might be a good place to solve the problem.

I registered a StickyKeyBinding in the initializeClient function with the id key.autorun.altsprint that defaults to mouse 5. Since I used KeyBindingHelper the keybind automatically shows up in the Controls menu.

public static KeyBinding altSprintKeybinding;
......
......
AutoRun.altSprintKeybinding = KeyBindingHelper.registerKeyBinding(new StickyKeyBinding(
        "key.autorun.altsprint",
        GLFW.GLFW_MOUSE_BUTTON_5,
        "key.categories.movement",
        () -> {return false;}
));
AutoRun.java snippet

This keybinding will tell you a few things about they key it is relevant to, but most importantly whether it is pressed or not. Nothing consumed it yet, so I had to find a suitable place for some logic that sprints the player when the key is pressed.

I decided to inject it in KeyBinding.isPressed, this way anything that looks to see if the sprint key is being pressed will contain our desired behavior. I ended up with a very short mixin.

@Mixin(KeyBinding.class)
public abstract class AltSprintMixin {
    @Shadow public abstract String getTranslationKey();

    @Inject(method="isPressed", at = @At("HEAD"), cancellable = true)
    private void injectAltSprint(CallbackInfoReturnable<Boolean> cir) {
        if (this.getTranslationKey().equals("key.sprint")
                && AutoRun.altSprintKeybinding.isPressed()) {
            cir.setReturnValue(true);
        }
    }
}
AltSprintMixin.java snippet

Here you can see the logic is pretty simple. The function is injected at the head of the isPressed method. If it's checking the sprint key, and the alternate keybind is being pressed, the function returns early with true; it doesn't need to check the actual sprint key. The isPressed method will carry on as normal if both of these conditions are not met.

https://i.imgur.com/5TKIAuB.png

My "Sprint Alternate" keybind below the "Sprint" keybind

If you would like more details about the code you can view the pull request here.

Other Solutions?

The opposite method would have been to inject our code in all the places sprint behavior happens. Not really easy to maintain.

I believe I could hyper-optimize this by creating a class extending StickyKeyBinding, overriding isPressed and using polymorphism so I can target just the single instance of StickyKeyBinding that is the sprint key bind. However, I think this would be a waste of time; this is "fast enough" and will have no noticeable effect on performance as far as I can tell, even though it runs on all key press checks.

Will It Get Merged?

https://i.imgur.com/uUKJrXE.png

The pull request I submitted to Emonadeo/AutoRun on Github

If emonadeo is concerned about performance, I will implement another solution. If emonadeo doesn't think this is a good fit for the AutoRun project, I might maintain my own fork.

I am currently considering creating a mod that provides this functionality for all keybinds. This would be presented in a side-by-side manner in the GUI like most games. Obviously, I would stop maintaining my fork if it existed at this point.

This is a small mid-week article to make up for my missing a week.

See you on Sunday

  • Fractured