WrapOperation - LlamaLad7/MixinExtras GitHub Wiki
Allows you to wrap many kinds of operations.
It accepts these injection points:
INVOKE
,
FIELD
,
@Constant
,
NEW
and
MIXINEXTRAS:EXPRESSION
.
Your handler method receives the targeted instruction's arguments and an Operation
representing the operation being wrapped (optionally followed by the enclosing method's parameters). You should return the same type as the wrapped operation does.
Should be used in favour of Redirect
s when you are wrapping the original operation and not replacing it outright, as unlike Redirect
s, this chains when used by multiple people.
Targeted operation | Handler signature |
---|---|
Non-static method call | private ReturnType yourHandlerMethod(OwnerType instance, <arguments of the original call>, Operation<ReturnType> original) |
super. method call |
private ReturnType yourHandlerMethod(ThisClass instance, <arguments of the original call>, Operation<ReturnType> original) |
Static method call | private ReturnType yourHandlerMethod(<arguments of the original call>, Operation<ReturnType> original) |
Non-static field get | private FieldType yourHandlerMethod(OwnerType instance, Operation<FieldType> original) |
Static field get | private FieldType yourHandlerMethod(Operation<FieldType> original) |
Non-static field write | private void yourHandlerMethod(OwnerType instance, FieldType newValue, Operation<Void> original) |
Static field write | private void yourHandlerMethod(FieldType newValue, Operation<Void> original) |
instanceof check |
private boolean yourHandlerMethod(Object obj, Operation<Boolean> original) |
Object instantiation | private ObjectType yourHandlerMethod(<arguments of the relevant constructor>, Operation<ObjectType> original) |
Primitive comparison | private boolean yourHandlerMethod(theType left, theType right, Operation<Boolean> original) |
Reference comparison | private boolean yourHandlerMethod(Object left, Object right, Operation<Boolean> original) |
Array element get | private ElementType yourHandlerMethod(ElementType[] array, int index, Operation<ElementType> original) |
Array element set | private void yourHandlerMethod(ElementType[] array, int index, ElementType value, Operation<Void> original) |
Object cast | private CastType yourHandlerMethod(Object object, Operation<CastType> original) |
In all of these cases, you can optionally add the enclosing method's parameters to the end, should you require them for additional context.
When call
ing the original
, you must pass everything before the original
in your handler's parameters. You can optionally pass different values to change what the original
uses.
When targeting code such as the following:
int number = this.expensiveCalculation(flag);
you may wish to wrap the call such that it is bypassed if a setting is enabled.
This could be done like so:
@WrapOperation(
method = "targetMethod",
at = @At(value = "INVOKE", target = "Lsome/package/TargetClass;expensiveCalculation(Z)I")
)
private int bypassExpensiveCalculationIfNecessary(TargetClass instance, boolean flag, Operation<Integer> original) {
if (YourMod.bypassExpensiveCalculation) {
return 10;
} else {
return original.call(instance, flag);
}
}
expensiveCalculation
would then only be called if you called it yourself via the original.call(...)
invocation.
Multiple mods can do this at the same time, and the wrapping will chain. The first to be applied receives an Operation
representing the vanilla call, if another is applied it receives an Operation
representing the first one's wrapping, etc.
- int number = this.expensiveCalculation(flag);
+ int number = this.bypassExpensiveCalculationIfNecessary(this, flag, args -> {
+ return ((TargetClass) args[0]).expensiveCalculation((Boolean) args[1]);
+ });