关于Mixin注入时机:能否将RETURN注入点调整至return指令后执行?
嘿,我来帮你捋清楚这个Mixin注入时机的问题~
先直接给你核心结论:你没法把RETURN注入点“移到”return指令之后——因为@At("RETURN")本身就是设计在对应return指令执行完毕、方法即将退出的位置插入代码的。不过结合你的代码场景,我感觉你可能对注入点的使用场景有点误解,咱们拆解开说:
首先明确RETURN注入点的实际行为:
- 当你写
@At(value="RETURN", ordinal=0)时,Mixin会定位到方法里第一个出现的return指令,然后把你的注入代码插在这个return指令执行之后、方法从该分支退出前的位置。 - 要是你想拿到这个return语句的返回值,只需要在注入方法的参数里加个
@Return ItemInteractionResult result,就能直接获取到PASS_TO_DEFAULT_BLOCK_INTERACTION这个返回值。
不过看你代码里的注释,你真正想注入的位置是跳过那个if分支之后(就是//I want to inject some code here的地方,也就是当player.isShiftKeyDown() || !player.mayBuild()为false时,才会走到的代码段开头)。这种情况用RETURN注入点就不合适了,因为RETURN会在触发return的分支里执行,而你要的是“不触发这个return”时才运行注入代码。这时候你有两个更合适的选项:
选项1:基于后续方法调用的注入点
你的代码在if分支之后的第一行是boolean isWrench = AllItems.WRENCH.isIn(stack);,你可以针对这个isIn方法的调用做注入,精准定位到目标位置:
@Inject( method = "useItemOn", at = @At( value = "INVOKE", target = "L你的模组包路径/AllItems$WRENCH;isIn(Lnet/minecraft/world/item/ItemStack;)Z", shift = At.Shift.BEFORE ) ) private void injectAfterIfCheck(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult, CallbackInfoReturnable<ItemInteractionResult> cir) { // 这里的代码会在不进入if分支时,在isIn方法调用前执行,完全对应你注释的位置 }
记得把target里的包路径换成你实际的AllItems.WRENCH的完整路径哦。
选项2:基于标签的注入点
如果AllItems.WRENCH.isIn()在方法里有多处调用,或者你不想依赖这个方法,也可以用标签注入点:
@Inject( method = "useItemOn", at = @At(value = "LABEL", ordinal = 0) )
不过这个需要你先反编译原方法,找到if分支结束后对应的标签序号(ordinal从0开始数),优点是不依赖后续方法调用,但缺点是如果原方法编译后标签序号变化,注入就会失效,所以更推荐第一种选项。
最后补个小误区澄清
很多新手会误以为RETURN是在return指令之前插入代码,但实际上Mixin的RETURN注入点就是在return指令执行完成后(比如返回值已经准备好)、方法退出前插入的。如果你确实需要在某个特定return指令执行后触发逻辑,@At(value="RETURN", ordinal=N)就是正确的选择,N是该return语句在方法中的出现顺序序号。
内容来源于stack exchange

