Mixins

Bemerkung

Diese Seite bezieht sich auf SpongeCommon, SpongeForge und SpongeVanilla, da sich diese drei Repositories Mixins zu Nutze machen, um sich in die zugrundeliegende Implementierung (Vanilla Minecraft Server und Forge) einzuklinken.

Mixins sind eine Möglichkeit Java-Code während der Laufzeit zu modifizieren, indem Zusatzfunktionen zu Klassen hinzugefügt werden. Sie erlauben es neues, beabsichtigtes Verhalten in existierenden Minecraft-Klassen zu ergänzen. Mixins werden für die Funktion aller offiziellen Sponge Implementierungen unbedingt benötigt.

Eine grundlegende Einführung zu einigen Kernkonzepten der Mixin-Funktionalität, die benutzt wird, um Sponge zu implementieren, ist im Mixin Wiki verfügbar

Das Wiki beginnt mit der Erklärung von Grundlagen. Fortgeschrittene Java-Entwickler können direkt zu Kapitel 4 wechseln. Dort werden die Mixins an sich behandelt.

If you’re looking to get started writing mixins, we also strongly recommend carefully examining all of the examples in the SpongeCommon repository which are extensively documented and cover many of the more complex scenarios. You should also consult the Javadoc of the Mixin repository itself, since almost everything is already documented.

Bemerkung

The Mixin project will be servicing a number of other projects in addition to Sponge itself. Therefore, Mixin has its own documentation together with the repository.

Mixins und innere Klassen

Während du Lambdas, anonyme und innere Klassen in Mixins verwenden kannst, kannst du keine anonyme und innere Klassen verwenden, die sich in einer anonymen oder inneren Klasse befindet, die sich in einem Mixin befinden, es sei denn einer der inneren Klassen ist static.

Dies bedeutet, dass Ausdrücke wie der Folgende Mixins fürchterlich fehlschlagen lassen und Tod und Zerstörung über all jene bringen, die versuchen, Sponge zu verwenden.

return new Collection<ItemStack>() {
    @Override
    public Iterator<ItemStack> iterator() {
        return new Iterator<ItemStack>() {
            // THIS WILL NOT WORK!

            @Override
            public boolean hasNext() {
                // Code skipped
            }

            @Override
            public ItemStack next() {
                // Code skipped
            }
        };
    }

    // Other methods skipped
};

Dies gilt für alle Klassen, die mit @Mixin gekennzeichnet sind. Klassen, die vom Mixin-Prozessor nicht berührt werden, können diese Funktionen verwenden. Es gibt zwei Möglichkeiten, dies zu umgehen.

Die eine Möglichkeit besteht in der Verwendung einer seperaten Dienstklasse, denn die Dienstklasse wird im Gegensatz zu der Mixin-Klasse immer noch als Laufzeit existieren, während die Mixin-Klasse in die Zielklasse eingeführt wird. Der folgende Code wird daher funktionieren.

public class SampleCollection implements Collection<ItemStack> {

    private final TargetClass target;

    public SampleCollection(TargetClass target) {
        this.target = target;
    }

    @Override
    public Iterator<ItemStack> iterator() {
        return new Iterator<ItemStack>() {

            @Override
            public boolean hasNext() {
                // Code skipped
            }

            @Override
            public ItemStack next() {
                // Code skipped
            }
        };
    }

    // Other methods skipped
}

@Mixin(TargetClass.class)
public abstract class SomeMixin {
    public Collection<ItemStack> someFunction() {
        return new SampleCollection((TargetClass) (Object) this);
    }
}

Die andere Möglichkeit ist es, alle inneren, geschachtelten Klassen direkt in die Mixin-Klasse oder eine ihrer Methoden zu platzieren, im Gegensatz zu einer in eine andere, Zum Beispiel:

@Mixin(TargetClass.class)
public abstract class SomeMixin {

    private final class SampleIterator implements Iterator<ItemStack> {

        @Override
        public boolean hasNext() {
            // Code skipped
        }

        @Override
        public ItemStack next() {
            // Code skipped
        }
    }

    public Collection<ItemStack> someFunction() {
        return new Collection<ItemStack>() {
            @Override
            public Iterator<ItemStack> iterator() {
                return new SampleIterator();
            }

            // Other methods skipped
        };
    }
}