User Tools

Site Tools


tutorial:mixin_accessors

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
tutorial:mixin_accessors [2020/08/05 22:26] – created emmanuelmesstutorial:mixin_accessors [2025/10/17 13:47] (current) – Add warnings for outdated examples, use yarncode plugin for most refs to vanilla code. gauntrecluse
Line 1: Line 1:
-====== Mixin Accessors ======+====== Accessor Mixins ====== 
 +FIXME //This page is under revison. This page may change suddenly and should be taken with a grain of salt.//
  
-===== Introduction =====+**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.
  
-A type of mixin allows to you to access variables that are not visible (private) or final:+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 ===== 
 +''@Accessor'' allows you to access or mutate fields. Suppose we want to access ''<yarn field_1752>'' field of ''<yarn class_310>'' class. 
 + 
 +==== Getting a value from the field ==== 
 +<yarncode java> 
 +@Mixin(class_310.class) 
 +public interface class_310Accessor { 
 +    @Accessor("field_1752"
 +    int modid$getItemUseCooldown(); 
 +
 +</yarncode> 
 + 
 +Usage: 
 + 
 +<yarncode java> 
 +int field_1752 = ((class_310Accessor) class_310.method_1551()).modid$getItemUseCooldown(); 
 +</yarncode> 
 + 
 +==== Setting a value to the field ==== 
 +<yarncode java> 
 +@Mixin(class_310.class) 
 +public interface class_310Accessor { 
 +    @Accessor("field_1752"
 +    void modid$setItemUseCooldown(int field_1752); 
 +
 +</yarncode> 
 + 
 +Usage: 
 + 
 +<yarncode java> 
 +((class_310Accessor) class_310.method_1551()).modid$setItemUseCooldown(100); 
 +</yarncode> 
 + 
 +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. 
 + 
 +===== Accessor for static fields ===== 
 +FIXME //VanillaLayeredBiomeSource no longer exists since 1.18, this example cannot be directly replicated on recent versions.//\\ 
 +Suppose we want to access the ''BIOMES'' field of ''VanillaLayeredBiomeSource'' class. 
 + 
 +==== Getting a value from the field ====
 <code java> <code java>
-@Mixin(StructuresConfig.class) +@Mixin(VanillaLayeredBiomeSource.class) 
-public interface StructuresConfigAccessor +public interface VanillaLayeredBiomeSourceAccessor 
-    @Accessor("DEFAULT_STRUCTURES") +  @Accessor("BIOMES") 
-    public static void setDefaultStructures(ImmutableMap<StructureFeature<?>, StructureConfigdefaultStructures) { +  static List<RegistryKey<Biome>> modid$getBiomes() { 
-        throw new IllegalAccessError(); +    throw new AssertionError(); 
-    }+  }
 } }
 </code> </code>
-The error will never be thrown, you can use the function. 
  
 +Usage:
  
 +<code java>
 +List<RegistryKey<Biome>> biomes = VanillaLayeredBiomeSourceAccessor.modid$getBiomes();
 +</code>
 +
 +==== Setting a value to the field ====
 +<code java>
 +@Mixin(VanillaLayeredBiomeSource.class)
 +public interface VanillaLayeredBiomeSourceAccessor {
 +  @Accessor("BIOMES")
 +  static void modid$setBiomes(List<RegistryKey<Biome>> biomes) {
 +    throw new AssertionError();
 +  }
 +}
 +</code>
 +
 +Usage:
 +
 +<code java>
 +VanillaLayeredBiomeSourceAccessor.modid$setBiomes(biomes);
 +</code>
 +
 +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 =====
 +''@Invoker'' allows you to access methods. Suppose we want to invoke ''<yarn method_7024>'' method of ''<yarn class_1560>'' class.
 +
 +<yarncode java>
 +@Mixin(class_1560.class)
 +public interface class_1560Invoker {
 +  @Invoker("method_7024")
 +  boolean modid$invokeTeleportTo(double x, double y, double z);
 +}
 +</yarncode>
 +
 +Usage:
 +
 +<yarncode java>
 +class_1560 enderman = ...;
 +((class_1560Invoker) enderman).modid$invokeTeleportTo(0.0D, 70.0D, 0.0D);
 +</yarncode>
 +
 +===== Invoker for static methods =====
 +FIXME //This example is not fully accurate to latest versions, ''registerPotionType'' exists now within the ''Builder'' nested class within ''BrewingRecipeRegistry''//\\
 +Suppose we want to invoke ''registerPotionType'' method of ''BrewingRecipeRegistry'' class.
 +
 +<code java>
 +@Mixin(BrewingRecipeRegistry.class)
 +public interface BrewingRecipeRegistryInvoker {
 +  @Invoker("registerPotionType")
 +  static void modid$invokeRegisterPotionType(Item item) {
 +    throw new AssertionError();
 +  }
 +}
 +</code>
 +
 +Usage:
 +
 +<code java>
 +BrewingRecipeRegistryInvoker.modid$invokeRegisterPotionType(item);
 +</code>
tutorial/mixin_accessors.1596666389.txt.gz · Last modified: 2020/08/05 22:26 by emmanuelmess