This page is under revison. This page may change suddenly and should be taken with a grain of salt.
Accessor Mixins are special mixins defined as interfaces which must only contain @Accessor
and @Invoker
handlers. Unlike normal mixins however, Accessor Mixins are accessible via user code directly.
The @Accessor
and @Invoker
annotations allow you to access fields or invoke methods that are not visible (private) or mutable (final).
Unlike typical injectors, accessors do not prefix the merged methods with the modid of the mod that contains them. Additionally as the Accessor Mixins are used in user code, the names of the handlers are not mangled, these differences are important to keep in mind when writing Accessor Mixins for compatibility and debugging purposes.
@Accessor
s and @Invoker
s can infer the field/method name if they are called getFieldName
/ call/invokeMethodName
, omitting the requirement for the value
attribute to be specified, however, all handlers should be prefixed as so: modid$getFieldName
instead. This is because when the Accessor Mixin is merged the handler will remain unchanged and if there is a problem related to the handler, it's useful to know who owns it. Additionally, if another mod decides to create a Duck interface with a method called getFieldName
, when that is merged alongside your Accessor Mixin whichever one applies last will overwrite the other and you end up with a conflict that may crash or cause unintended behaviour.
@Accessor
allows you to access or mutate fields. Suppose we want to access itemUseCooldown
field of MinecraftClient
class.
@Mixin(MinecraftClient.class) public interface MinecraftClientAccessor { @Accessor("itemUseCooldown") int modid$getItemUseCooldown(); }
Usage:
int itemUseCooldown = ((MinecraftClientAccessor) MinecraftClient.getInstance()).modid$getItemUseCooldown();
@Mixin(MinecraftClient.class) public interface MinecraftClientAccessor { @Accessor("itemUseCooldown") void modid$setItemUseCooldown(int itemUseCooldown); }
Usage:
((MinecraftClientAccessor) MinecraftClient.getInstance()).modid$setItemUseCooldown(100);
When the field is final and you need to set it, use @Mutable
as well. Note that this may not work as expected if the field is set to a constant literal value in its initializer, such as 42
or “Hello World”
. This is because the compiler inlines constant fields.
Suppose we want to access BIOMES
field of VanillaLayeredBiomeSource
class.
@Mixin(VanillaLayeredBiomeSource.class) public interface VanillaLayeredBiomeSourceAccessor { @Accessor("BIOMES") static List<RegistryKey<Biome>> modid$getBiomes() { throw new AssertionError(); } }
Usage:
List<RegistryKey<Biome>> biomes = VanillaLayeredBiomeSourceAccessor.modid$getBiomes();
@Mixin(VanillaLayeredBiomeSource.class) public interface VanillaLayeredBiomeSourceAccessor { @Accessor("BIOMES") static void modid$setBiomes(List<RegistryKey<Biome>> biomes) { throw new AssertionError(); } }
Usage:
VanillaLayeredBiomeSourceAccessor.modid$setBiomes(biomes);
When the field is final and you need to set it, use @Mutable
as well. Note that this may not work as expected if the field is set to a constant literal value in its initializer, such as 42
or “Hello World”
. This is because the compiler inlines constant fields.
@Invoker
allows you to access methods. Suppose we want to invoke teleportTo
method of EndermanEntity
class.
@Mixin(EndermanEntity.class) public interface EndermanEntityInvoker { @Invoker("teleportTo") boolean modid$invokeTeleportTo(double x, double y, double z); }
Usage:
EndermanEntity enderman = ...; ((EndermanEntityInvoker) enderman).modid$invokeTeleportTo(0.0D, 70.0D, 0.0D);
Suppose we want to invoke registerPotionType
method of BrewingRecipeRegistry
class.
@Mixin(BrewingRecipeRegistry.class) public interface BrewingRecipeRegistryInvoker { @Invoker("registerPotionType") static void modid$invokeRegisterPotionType(Item item) { throw new AssertionError(); } }
Usage:
BrewingRecipeRegistryInvoker.modid$invokeRegisterPotionType(item);