Skip to content

Mixin Library

The following functions are provided to scripts via the mixin global.

DANGER

Mixins are a very complicated topic that's very hard to grasp without a decent understanding of the JVM. If you would like to learn more about them, check out:

  1. Mixin's own wiki.
  2. The Mixin Cheatsheet.
  3. MixinExtras' Wiki.

DOUBLE DANGER

Due to a limitation in how mixins are applied, if another mod chooses to apply mixins during the preLaunch phase, all Allium script mixins will NOT apply. If a script mixin appears to not be applying properly, this might be why.

WARNING

This page is under construction

Functions

mixin.to(targetClass, interfaces, targetEnvironment, duck)

Mix into a specified class.

Parameters

  1. targetClass - string: The target class name, like what would be passed to require().
  2. interfaces - table<string>?: Optional interfaces to apply to the target class, using the require() format.
  3. targetEnvironment - string?: The target environment, one of "client" or "server". Leave nil to apply to common code.
  4. duck - boolean?: Whether to make this mixin a duck interface.

WARNING

Unlike standard class building, class names are passed as strings. This is because:

  1. mixins must not load the class they're mixing into, otherwise the application of the mixin will fail.
  2. mixins are registered before the game properly launches (mixin Allium entrypoint, preLaunch Fabric entrypoint). In this pre-launch environment it is best practice to not load any game classes.

Returns

  • userdata [instance] - A mixin class builder.

Usage

See Class Building - Mixin Class Builder


mixin.get(hookId)

Get a reference to a mixin injection with the given hookId. This function can (and should) be used in static and dynamic script entrypoints.

Parameters

  1. hookId - string: The hook ID of the injector created in the mixin entrypoint.

Returns

  • userdata [instance]: The injector's method hook. See Method Hook

Usage

Assuming there exists an injection with the ID "increase_cactus_height":

Lua
local methodHook = mixin.get("increase_cactus_height")

mixin.quack(mixinId)

Provides the duck interface associated to a given ID. Used to access the accessors and invokers on objects belonging to the duck interface's target class.

Parameters

  1. mixinId - string: The ID of a duck interface mixin.

Returns

  • userdata [class]: The mixin interface.

Usage

Provided the class:

Dummy.java
Java
package com.example;

import java.lang.String;

public class Dummy {
    private final String foobar;

    public Dummy(String foobar) {
        this.foobar = foobar + (int)(Math.random()*100);
    }

    private void bat(boolean baz) {
        // ...
    }
}

and the following mixin to access the private field foobar:

accessExampleMixin.lua
Lua
local builder = mixin.to("com.example.Dummy")
builder:getAccessor({ "foobar" })
builder:invoker({ "bat(Z)V" })
builder:build("foobar_interface")

we use mixin.quack() to access the duck interface:

main.lua
Lua
local Dummy = require("com.example.Dummy")

local AccessExample = mixin.quack("foobar_interface")
local dummy = Dummy("asd")
local accessibleDummy = java.cast(dummy, AccessExample)
local foobar = accessibleDummy:getFoobar()
accessibleDummy:invokeBat(false)

Annotation Tables

Annotation tables are used heavily in both annotation functions and sugar functions. Annotation tables are tables that gets recursively parsed and applied to the annotation interface that the function represents. The method names become keys, and the return values become the value. Arrays are a standard table with number indices.

There is a special exception to the method name value, where if it's the only key-value pair being provided, the key name can be omitted. A common example of this is the mixin @At annotation. Both:

Lua
{ value = "HEAD" }

and:

Lua
{ "HEAD" }

are valid ways to define an @At annotation.

Annotations

The following functions are provided on the annotation index of the mixin global.

Most of these functions represent injector annotations. Only one injector annotation can be provided per-method. The exceptions to this are expression() and definition(), which can be provided more than once per method.


mixin.annotation.inject(annotation)

Creates an @Inject annotation.

For more information see:

Parameters

  1. annotation - table: An annotation table that matches the @Inject annotation.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.modifyArg(annotation, targetType)

Creates a @ModifyArg annotation.

For more information see Mixin Cheatsheet - @ModifyArg.

Parameters

  1. annotation - table: An annotation table that matches the @ModifyArg annotation.
  2. targetType - string: A type descriptor string of the argument being modified.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.modifyArgs(annotation)

Creates a @ModifyArgs annotation.

For more information see Mixin Cheatsheet - @ModifyArgs.

Parameters

  1. annotation - table: An annotation table that matches the @ModifyArgs annotation.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.modifyExpressionValue(annotation, targetType)

Creates a @ModifyExpressionValue annotation.

For more information see MixinExtras - ModifyExpressionValue

Parameters

  1. annotation - table: An annotation table that matches the @ModifyExpressionValue annotation.
  2. targetType - string: A type descriptor string of the argument being modified.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.modifyReturnValue(annotation)

Creates a @ModifyReturnValue annotation.

For more information see MixinExtras - ModifyReturnValue

Parameters

  1. annotation - table: An annotation table that matches the @ModifyReturnValue annotation.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.wrapMethod(annotation)

Creates a @WrapMethod annotation.

For more information see MixinExtras - WrapMethod

Parameters

  1. annotation - table: An annotation table that matches the @WrapMethod annotation.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.custom(annotation, annotationType, methodDescriptor, parameterTypes, returnType)

Creates a custom injector annotation.

Parameters

  1. annotation - table: An annotation table that matches the given annotationType.
  2. annotationType - userdata [class]: The annotation class to be used.
  3. methodDescriptor - string: The target method's descriptor string.
  4. parameterTypes - table<string>: The parameters of the injector method. These may differ from the target method's descriptor.
  5. returnType - string: The return type of the injector method. This may differ from the target method's dscriptor.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.expression(annotation)

Creates an @Expression annotation. This method does not produce an injector annotation and may be used multiple times within an inject method.

For more information see MixinExtras - Expressions

Parameters

  1. annotation - table: An annotation table that matches the @Expression annotation.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

mixin.annotation.definition(annotation)

Creates a @Definition annotation. This method does not produce an injector annotation and may be used multiple times within an inject method.

For more information see MixinExtras - Expressions

Parameters

  1. annotation - table: An annotation table that matches the @Definition annotation.

Returns

  • userdata [instance]: A reference to the annotation for use in mixin method building.

Sugars

The following functions are provided on the sugar index of the mixin global.

Sugars are annotations that are applied to additional parameters that are applied to the end of the injector method's parameter list.


mixin.sugar.localref(type, annotation, mutable)

Creates a parameter with a @Local annotation.

See MixinExtras Wiki - Local for more information.

Parameters

  1. type - string: A type descriptor string of the parameter.
  2. annotation - table?: An optional annotation table that matches the @Local annotation.
  3. mutable - boolean?: Whether this parameter should be mutable.

WARNING

Setting mutable to true changes the parameter's type from the one passed in type to one from the LocalRef family.

Returns

  • userdata [instance]: A reference to the parameter and annotation for use in mixin method building.

mixin.sugar.share(type, annotation)

Creates a parameter with a @Share annotation.

See MixinExtras Wiki - Share for more information.

Parameters

  1. type - string: A type descriptor string of the parameter.
  2. annotation - table?: An optional annotation table that matches the @Share annotation.

Returns

  • userdata [instance]: A reference to the parameter and annotation for use in mixin method building.

mixin.sugar.cancellable()

Creates a parameter with a @Cancellable annotation.

See MixinExtras Wiki - Cancellable for more information.

Returns

  • userdata [instance]: A reference to the parameter and annotation for use in mixin method building.

Method Hook

Because of the restrictions of the mixin entrypoint, the Lua function that is to be put into the injector has to be hooked in from the static or dynamic entrypoints. The method hook is how this is done. It has a single function:

methodHook:hook(func)

Hooks the given function into the given mixin injection.

Parameters

  1. func - function: The function to be run when the injector gets invoked. Parameters passed into this function depend on the injector. If the injection does not target a static method, the first parameter passed to the function is this, followed by the remaining parameters specified by the injection annotation.

TIP

It can be hard to visualize where a mixin should be made and what parameters it will provide. Scaffolding out the mixin in java first, where linting and auto-fill can help guide to the correct results, is a good idea.

HELP WANTED

It would be nice to be able to auto-fill in the parameters using the mixin annotation information right in the Lua file itself. If you have extension development experience in any IDE, and have an interest in contributing to an IDE extension for Allium, join the Discord linked in the top right!

Usage

TODO: A better example

Lua
methodHook:hook(function(this, ...)
    -- your code
end)