User Tools

Site Tools


tutorial:mixin_accessors

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorial:mixin_accessors [2020/09/06 10:34] – Add how to access static fields and methods siglongtutorial: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 ====== 
-Mixin Accessors allow you to access fields and methods that are not visible (private) or final.+FIXME //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 ===== ===== Accessor =====
-''@Accessor'' allows you to access fields. Suppose we want to access ''itemUseCooldown'' field of ''MinecraftClient'' class.+''@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 ==== ==== Getting a value from the field ====
-<code java> +<yarncode java> 
-@Mixin(MinecraftClient.class) +@Mixin(class_310.class) 
-public interface MinecraftClientAccessor +public interface class_310Accessor 
-    @Accessor("itemUseCooldown") +    @Accessor("field_1752") 
-    public int getItemUseCooldown();+    int modid$getItemUseCooldown();
 } }
-</code>+</yarncode>
  
 Usage: Usage:
  
-<code java> +<yarncode java> 
-int itemUseCooldown = ((MinecraftClientAccessorMinecraftClient.getInstance()).getItemUseCooldown(); +int field_1752 = ((class_310Accessorclass_310.method_1551()).modid$getItemUseCooldown(); 
-</code>+</yarncode>
  
 ==== Setting a value to the field ==== ==== Setting a value to the field ====
-<code java> +<yarncode java> 
-@Mixin(MinecraftClient.class) +@Mixin(class_310.class) 
-public interface MinecraftClientAccessor +public interface class_310Accessor 
-    @Accessor("itemUseCooldown") +    @Accessor("field_1752") 
-    public void setItemUseCooldown(int itemUseCooldown);+    void modid$setItemUseCooldown(int field_1752);
 } }
-</code>+</yarncode>
  
 Usage: Usage:
  
-<code java> +<yarncode java> 
-((MinecraftClientAccessorMinecraftClient.getInstance()).setItemUseCooldown(100); +((class_310Accessorclass_310.method_1551()).modid$setItemUseCooldown(100); 
-</code>+</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 ===== ===== Accessor for static fields =====
-Suppose we want to access ''BIOMES'' field of ''VanillaLayeredBiomeSource'' class.+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 ==== ==== Getting a value from the field ====
Line 43: Line 54:
 public interface VanillaLayeredBiomeSourceAccessor { public interface VanillaLayeredBiomeSourceAccessor {
   @Accessor("BIOMES")   @Accessor("BIOMES")
-  public static List<RegistryKey<Biome>> getBiomes() {+  static List<RegistryKey<Biome>> modid$getBiomes() {
     throw new AssertionError();     throw new AssertionError();
   }   }
Line 52: Line 63:
  
 <code java> <code java>
-List<RegistryKey<Biome>> biomes = VanillaLayeredBiomeSourceAccessor.getBiomes();+List<RegistryKey<Biome>> biomes = VanillaLayeredBiomeSourceAccessor.modid$getBiomes();
 </code> </code>
  
Line 60: Line 71:
 public interface VanillaLayeredBiomeSourceAccessor { public interface VanillaLayeredBiomeSourceAccessor {
   @Accessor("BIOMES")   @Accessor("BIOMES")
-  public static void setBiomes(List<RegistryKey<Biome>> biomes) {+  static void modid$setBiomes(List<RegistryKey<Biome>> biomes) {
     throw new AssertionError();     throw new AssertionError();
   }   }
Line 69: Line 80:
  
 <code java> <code java>
-VanillaLayeredBiomeSourceAccessor.setBiomes(biomes);+VanillaLayeredBiomeSourceAccessor.modid$setBiomes(biomes);
 </code> </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 =====
-''@Invoker'' allows you to access methods. Suppose we want to invoke ''teleportTo'' method of ''EndermanEntity'' class.+''@Invoker'' allows you to access methods. Suppose we want to invoke ''<yarn method_7024>'' method of ''<yarn class_1560>'' class.
  
-<code java> +<yarncode java> 
-@Mixin(EndermanEntity.class) +@Mixin(class_1560.class) 
-public interface EndermanEntityInvoker +public interface class_1560Invoker 
-  @Invoker("teleportTo") +  @Invoker("method_7024") 
-  public boolean invokeTeleportTo(double x, double y, double z);+  boolean modid$invokeTeleportTo(double x, double y, double z);
 } }
-</code>+</yarncode>
  
 Usage: Usage:
  
-<code java> +<yarncode java> 
-EndermanEntity enderman = ...; +class_1560 enderman = ...; 
-((EndermanEntityInvoker) enderman).invokeTeleportTo(0.0D, 70.0D, 0.0D); +((class_1560Invoker) enderman).modid$invokeTeleportTo(0.0D, 70.0D, 0.0D); 
-</code>+</yarncode>
  
 ===== Invoker for static methods ===== ===== 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. Suppose we want to invoke ''registerPotionType'' method of ''BrewingRecipeRegistry'' class.
  
Line 97: Line 111:
 public interface BrewingRecipeRegistryInvoker { public interface BrewingRecipeRegistryInvoker {
   @Invoker("registerPotionType")   @Invoker("registerPotionType")
-  public static void invokeRegisterPotionType(Item item) {+  static void modid$invokeRegisterPotionType(Item item) {
     throw new AssertionError();     throw new AssertionError();
   }   }
Line 106: Line 120:
  
 <code java> <code java>
-BrewingRecipeRegistryInvoker.invokeRegisterPotionType(item);+BrewingRecipeRegistryInvoker.modid$invokeRegisterPotionType(item);
 </code> </code>
tutorial/mixin_accessors.1599388498.txt.gz · Last modified: 2020/09/06 10:34 by siglong