Skip to content

Initialization

fishstiz edited this page Feb 5, 2025 · 6 revisions

Create custom cursor types and register your elements using the MinecraftCursorInitializer interface.

Setup

Create your API Implementation class and implement MinecraftCursorInitializer which is initialized in the client environment.

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
    }
}

Add the entrypoint in minecraft-cursor

fabric.mod.json:

"entrypoints": {
  "minecraft-cursor": ["com.example.modid.MinecraftCursorApiImpl"]
}

MinecraftCursorInitializer#init() will be invoked on Minecraft Cursor client initialization.

Create Custom Cursor Types

Follow the Resource Pack Support section in README.md for more info on the asset creation of your custom cursor.

Once you have prepared the custom cursor's assets, use CursorTypeFactory#of(key) to initialize the custom cursor type.

Note: You should only initialize your custom cursor type within MinecraftCursorInitializer#init(cursorTypeFactory, cursorTypeRegistrar) to ensure that your custom cursor type will be loaded on the initial resource load of Minecraft.

Example usage of CursorTypeFactory#of(key)

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
        CursorType customCursorType = cursorTypeFactory.of("custom-cursor");
    }
}

The CursorType#key property

The key serves as the cursor type's identifier.

  • This should be the filename of the cursor type.
    assets/
    └── minecraft-cursor/
        └── textures/
            └── cursors/
                └── <key>.png
    
  • This is the key for custom settings in cursors.json.
    {
      "settings": {
        "<key>": {
          "xhot": 3,
          "yhot": 6
        }
      }
    }
  • Add the translation entry for your cursor type:
    {
      "minecraft-cursor.options.cursor-type.<key>": "Custom"
    }

Element Registration

Once you have initialized your cursor types, you can register your elements with a cursor type function which determines the cursor type to be applied when the mouse is over the registered element.

Note: The element must be an instance of net.minecraft.gui.Element. It must either be the current screen itself or be accessible from the current screen or from its parent element using the ParentElement#children() method.

Any container or nested container must be an instance of net.minecraft.gui.ParentElement and accessible via the ParentElement#children() method. This accessibility must be maintained through the entire element hierarchy, starting from the current screen down to the deepest nested parent element.

Register with a Class Reference

For most cases, registering elements directly using their class is the simplest approach.

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
        CursorType customCursorType = cursorTypeFactory.of("custom-cursor");

        // Register MyButton with the built-in pointer cursor type
        cursorTypeRegistrar.register(MyButton.class, (myButton, mouseX, mouseY) -> CursorType.POINTER);

        // You can use the built-in static methods of CursorTypeRegistrar when no additional logic is needed
        cursorTypeRegistrar.register(MyOtherButton.class, CursorTypeRegistrar::elementToPointer);

        // Register MyCustomElement with the custom cursor type
        cursorTypeRegistrar.register(MyCustomElement.class, (myCustomElement, mouseX, mouseY) -> customCursorType);
    }
}

Register with a Fully Qualified Class Name (FQCN)

If you cannot access a class directly, you can register it using its fully qualified class name (FQCN)

Note: Use the intermediary mappings when registering a native Minecraft Element.

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
        // ...

        // Register PressableWidget with the built-in pointer cursor type using its fully qualified class name
        cursorTypeRegistrar.register("net.minecraft.class_4264", (pressableWidget, mouseX, mouseY) -> CursorType.POINTER);
    }
}

Register with a CursorHandler

Mostly used for when the cursor type computing logic gets too large or complex, or you simply want to it to be in a separate class file.

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
        // ...

        cursorTypeRegistrar.register(new CursorHandler<MyButton>() {
            @Override
            public CursorType getCursorType(MyButton myButton, double mouseX, double mouseY) {
                return CursorType.POINTER;
            }
        });
    }
}

In a separate class

MyElementCursorHandler:

public class MyElementCursorHandler implements CursorHandler<MyElement> {
    @Override
    public CursorType getCursorType(MyElement myElement, double mouseX, double mouseY) {
        return CursorType.POINTER;
    }
}

MinecraftCursorApiImpl:

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
        // ...

        cursorTypeRegistrar.register(new MyElementCursorHandler());
    }
}

Using the Fully Qualified Class Name (FQCN) of the Element

When the target element is inaccessible, you can simply pass the Element generic type and override the CursorHandler#getTargetElement() method to return the FQCN of the target element.

Note: Use the intermediary mappings when registering a native Minecraft Element.

MerchantScreenButtonCursorHandler:

public class MerchantScreenButtonCursorHandler implements CursorHandler<Element> {
    @Override
    public @NotNull TargetElement<Element> getTargetElement() {
        return TargetElement.fromClassName("net.minecraft.class_492$class_493");
    }

    @Override
    public CursorType getCursorType(Element element, double mouseX, double mouseY) {
        return CursorTypeUtil.canShift() ? CursorType.SHIFT : CursorType.POINTER;
    }
}

MinecraftCursorApiImpl:

public class MinecraftCursorApiImpl implements MinecraftCursorInitializer {
    @Override
    public void init(CursorTypeFactory cursorTypeFactory, CursorTypeRegistrar cursorTypeRegistrar) {
        // ...

        cursorTypeRegistrar.register(new MerchantScreenButtonCursorHandler());
    }
}

Clone this wiki locally