Skip to content

Cancellable

LlamaLad7 edited this page Jul 9, 2024 · 2 revisions

Allows you to receive a cancellable CallbackInfo or CallbackInfoReturnable as appropriate from any kind of injector. This allows you to optionally cancel the target method without being forced to use @Inject.

Possible parameters could look like:

  • @Cancellable CallbackInfo ci (for a void method)
  • @Cancellable CallbackInfoReturnable<Integer> cir (for a int or Integer method)

Example

When targeting code such as the following:

public void renderHeart(MatrixStack matrices, HeartType type) {
	Identifier texture = type.getTexture();
	// ... Draw logic using `texture`
}

you may wish to conditionally skip the rendering based on the texture.

This could be done like so:

@ModifyExpressionValue(method = "renderHeart", at = @At(value = "INVOKE", target = "Lsome/package/HeartType;getTexture()Lsome/package/Identifier;"))
private Identifier dontRenderPoisonHearts(Identifier texture, @Cancellable CallbackInfo ci) {
	if (texture.equals(Textures.POSION_HEART)) {
		ci.cancel();
	}
	return texture;
}

The target method would then return early if the texture matches.

Code Diff

  public void targetMethod() {
+ 	  CallbackInfo ci = new CallbackInfo(...);
- 	  Identifier texture = type.getTexture();
+	  Identifier texture = dontRenderPoisonHearts(type.getTexture(), ci);
+	  if (ci.isCancelled()) {
+	      return;
+	  }
      // ... Draw logic using `texture`
  }

Niche interactions with @WrapOperation

The same CallbackInfo(Returnable)s will be passed to every handler method in a chain of @WrapOperations (i.e. any number of @WrapOperations and at most one inner @Redirect / @ModifyConstant). This means you can choose to use the CallbackInfo#isCancelled() and CallbackInfoReturnable#getReturnValue() methods to see if the wrapped handler cancelled, so you can respond accordingly.