package com.llamalad7.mixinextras.sugar; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.CLASS; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; /** * The Cancellable annotation can be applied on arguments of a {@link Redirect} handler * to allow the possibility to cancel large quantities of logic within the injected method. * More specifically, this annotation may only be applied on a {@link CallbackInfo} * or {@link CallbackInfoReturnable} argument, which makes that argument behave similar * to as if the {@link CallbackInfo} was used in a traditional setting with {@link Inject} * and {@link Inject#cancellable()} set to true. Callback instances * are reused where applicable and created lazily. * *

Callback IDs

* * While {@link Inject} allows to set custom {@link CallbackInfo#getId() identifiers} for * the callback objects in the spongeian implementation, micromixin-transformer does not * allow the definition of custom callback IDs. * However, both micromixin-transformer and MixinExtras forbid the explicit definition of * these IDs. In the case of MixinExtras the resulting Id of the callback is left undefined * by the MixinExtras documentation, where as micromixin-transformer will use the name of * the method which is being targeted by the handler. As micromixin-transformer does not * support the usage of refmaps, the name of the identifier will thus be dependent on the * environment it is running under. This behaviour may cause differences between production * and development environments. As a rule of thumb, the identifier of the callback should * not be relied on for any logic except for logging and debugging. * *

Permissible uses

* * MixinExtras does not strongly define where the usage of this annotation is permissible * or not, however micromixin-transformer explicitly applies restrictions on where this * annotation can be used and where it can't. These restrictions are follows: * * * *

Example usage

* * Assume following target: * *
 *   private static int redirectStaticReturnable() {
 *       CancellableTest.counter1 = 1;
 *       CancellableTest.counter1 = new MutableInt(2).intValue();
 *       CancellableTest.counter1 = 3;
 *       return 0;
 *   }
 * 
* * Execution of this method can be aborted after the redirected invocation of intValue * using following mixin handler: *
 *  @Redirect(at = @At(value = "INVOKE", target = "intValue"), method = "redirectStaticReturnable")
 *  private static int handleRedirectStaticReturnable(@NotNull MutableInt caller, @Cancellable CallbackInfoReturnable<Integer> ci) {
 *      ci.setReturnValue(1);
 *      return 4;
 *  }
 * 
* * This results in following code: * *
 *  @CommonCIInstance(index=1)
 *  private static void redirectStatic() {
 *      CallbackInfo callbackInfo = null;
 *      counter0 = 1;
 *      MutableInt mutableInt = new MutableInt(2);
 *      if (callbackInfo == null) {
 *          callbackInfo = new CallbackInfo("redirectStatic", true);
 *      }
 *      int i = CancellableTest.$handler$0$redirect$handleRedirectStatic(mutableInt, callbackInfo);
 *      if (callbackInfo.isCancelled()) {
 *          return;
 *      }
 *      counter0 = i;
 *      counter0 = 3;
 *  }
 * 
* * Note that in this case the assignment to counter0 will be cancelled, too. * * @since 0.6.3 */ @Documented @Retention(CLASS) @Target(PARAMETER) public @interface Cancellable { }