Mixin-Accessors 26.1.2
Lerne, wie du mit Mixins Accessors und Invokers auf Methoden und Felder zugreifst.
Mixins werden typischerweise verwendet, um bestehenden Code zu verändern und dessen Verhalten anzupassen oder zu erweitern. Mixin bietet jedoch auch Werkzeuge in Form von Accessor-Mixins, mit denen auf unzugängliche Felder und Methoden zugegriffen werden kann.
Klassenoptimierer bieten mit Zugriffserweiterern ein ähnliches Werkzeug, wobei die Accessors von Mixin kein Neuladen von Gradle erfordern und auch auf Ziele außerhalb von Minecraft angewendet werden können.
Eine Zugriffserweiterung ist weiterhin erforderlich, um finale Methoden zu überschreiben, finale Klassen zu Unterklassen zu machen oder auf private Klassen zu verweisen, da Accessors nur Felder und Methoden als Ziel haben können.
Das Accessor-Interface erstellen
Accessor-Mixins müssen immer ein Interface sein und dürfen nur Methoden enthalten, die mit @Accessor oder @Invoker annotiert sind. Das Interface muss ähnlich wie andere Mixin-Klassen mit @Mixin annotiert werden.
Accessor-Interfaces werden üblicherweise nach deren Zielklasse mit dem Suffix Accessor benannt und in einem Unterpaket accessor innerhalb deines Mixin-Pakets abgelegt. Zum Beispiel: your.package.mixin.accessor
Feld-Accessors
Auf Felder kann über mit @Accessor annotierte Getter- und/oder Setter-Methoden zugegriffen werden:
Getter-/Setter-Syntax:
Accessor-Methoden für Instanzfelder sollten mit deiner Mod-ID und einem Trennzeichen (üblicherweise $ oder _) beginnen, um sicherzustellen, dass sie nicht mit irgendeiner anderen Methode kollidieren.
java
@Accessor("<field name>")
FieldType example_mod$getFieldName();
@Accessor("<field name>")
void example_mod$setFieldName(FieldType value);1
2
3
4
5
2
3
4
5
Beispiel:
java
@Mixin(Gui.class)
public interface GuiAccessor {
@Accessor("overlayMessageTime")
int example_mod$getOverlayMessageTime();
@Accessor("overlayMessageTime")
void example_mod$setOverlayMessageTime(int messageTime);
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Verwendung:
java
void exampleInstanceFieldAccessorUsage(Gui gui, int newMessageTime) {
int oldMessageTime = ((GuiAccessor) gui).example_mod$getOverlayMessageTime();
((GuiAccessor) gui).example_mod$setOverlayMessageTime(newMessageTime);
}1
2
3
4
5
2
3
4
5
Finale Felder setzen
Ist das Zielfeld final, annotiere die Setter-Methode zusätzlich mit @Mutable, um das final-Flag während der Anwendung zu entfernen:
java
@Mixin(Villager.class)
public interface VillagerAccessor {
@Accessor("FOOD_POINTS")
@Mutable
void example_mod$setItemFoodValues(Map<Item, Integer> items);
}1
2
3
4
5
6
2
3
4
5
6
Methoden-Invoker
Um auf unzugängliche Methoden oder Konstruktoren zuzugreifen, erstelle eine Methode mit derselben Signatur und annotiere sie mit @Invoker:
Syntax:
Invoker-Methoden für Instanzmethoden sollten mit deiner Mod-ID und einem Trennzeichen (üblicherweise $ oder _) beginnen, damit sie nicht mit anderen Methoden kollidieren.
Invoker-Methoden werden üblicherweise entweder direkt nach der Zielmethode benannt oder beginnen mit invoke oder call, gefolgt vom Methodennamen.
java
@Invoker("<method name>")
MethodReturnType example_mod$methodName(/* matching parameters */)1
2
2
Beispiel:
java
@Mixin(Inventory.class)
public interface InventoryAccessor {
@Invoker("hasRemainingSpaceForItem")
boolean example_mod$hasRemainingSpaceForItem(ItemStack slotItemStack, ItemStack newItemStack);
}1
2
3
4
5
2
3
4
5
Verwendung:
java
void exampleInstanceMethodInvokerUsage(Inventory inventory, ItemStack slotItemStack, ItemStack newItemStack) {
if (((InventoryAccessor) inventory).example_mod$hasRemainingSpaceForItem(slotItemStack, newItemStack)) {
/* ... */
}
}1
2
3
4
5
2
3
4
5
Accessors für final-Klassen verwenden
Da der Java-Compiler bei final-Klassen strenger ist, erlaubt er uns nicht direkt die Instanzen in ein Accessor-Interface umwandeln.
Um dies zu umgehen, müssen wir zunächst nur in Object und anschließend in das Accessor-Interface umwandeln:
java
((TargetClassAccessor) (Object) targetClassInstance).example_mod$accessorMethod(/* ... */)1




