lovexyn0827
今天写的一个功能需要大概是要对MC本体进行如下修改:
原有
AbstractMinecartEntity abstractMinecartEntity = AbstractMinecartEntity.create(world,
        (double)blockPos.getX() + 0.5D,
        (double)blockPos.getY() + 0.0625D + d,
        (double)blockPos.getZ() + 0.5D, this.type);
修改后
AbstractMinecartEntity abstractMinecartEntity = AbstractMinecartEntity.create(world,
        (double)blockPos.getX() + 0.5D,
        (double)blockPos.getY() + 0.0625D + localvar$zfp000$adjustHeight(d, context),
        (double)blockPos.getZ() + 0.5D, this.type);
于是,我原以为像下面这样写就可以了
@ModifyVariable(method = "useOnBlock",
            at = @At(value = "INVOKE",
                    target = "Lnet/minecraft/entity/vehicle/AbstractMinecartEntity;"
                            + "create(Lnet/minecraft/world/World;DDDLnet/minecraft/entity/vehicle/AbstractMinecartEntity$Type;)"
                            + "Lnet/minecraft/entity/vehicle/AbstractMinecartEntity;",
                    shift = At.Shift.BEFORE
                    ),
            name = "d"
    )
但是,实际测试时却发现这样做似乎没有任何效果。开始,我在调用create()方法的那一行放置了一个断点,发现原始变量确实没有被修改。接着用JD反编译了一下Mixin的输出类,看起来注入方法似乎确实是已经被正确注入了。
d = localvar$zfp000$adjustHeight(d, context);
AbstractMinecartEntity abstractMinecartEntity = AbstractMinecartEntity.create(world,
        blockPos.getX() + 0.5D,
        blockPos.getY() + 0.0625D + d,
        blockPos.getZ() + 0.5D, this.type);
后来我确认了注入方法确实是正确的,但这样问题就变得更加扑朔迷离。干耗了将近一个小时后,我抱着试试看的想法向create()方法后面又放了一个断点,结果是这时变量d已经被正确地修改了,这给了我一个新思路:
我们知道,JVM字节码中带参数方法调用大概会长这样(以this.getStuff(2 + i1, obj1, obj2.arg)为例):
00  aload_0     //this
01  iconst_2    //2
02  iload 4     //i1
04  iadd
05  aload 5     //obj1
07  aload 6     //obj2
09  getfield #114
12  invokevirtual #514
如果我们修改参数i1,我们至少要在位置02之前,即JVM将i1的值存储为一个副本作为方法参数之前进行操作,否则变量的修改将不能再应用于实际的方法参数(除非把原来的pop出来再将新值入栈实现更新)。但是,Mixin中INVOKE在这里匹配的是invokevirtual指令之前,即11-12位置之间,这时再进行变量修改为时已晚。
回到原问题,有了这么一个思路,就用javap反汇编一下输出的类文件,果然不出所料:
     108: aload_2
     109: aload_3
     110: invokevirtual #120                // Method net/minecraft/util/math/BlockPos.getX:()I
     113: i2d
     114: ldc2_w        #113                // double 0.5d
     117: dadd
     118: aload_3
     119: invokevirtual #123                // Method net/minecraft/util/math/BlockPos.getY:()I
     122: i2d
     123: ldc2_w        #124                // double 0.0625d
     126: dadd
     127: dload         7
     129: dadd
     130: aload_3
     131: invokevirtual #128                // Method net/minecraft/util/math/BlockPos.getZ:()I
     134: i2d
     135: ldc2_w        #113                // double 0.5d
     138: dadd
     139: aload_0
     140: aload_0
     141: dload         7
     143: aload_1
     144: invokespecial #132                // Method localvar$zfp000$adjustHeight:(DLnet/minecraft/item/ItemUsageContext;)D
     147: dstore        7
     149: getfield      #32                 // Field type:Lnet/minecraft/entity/vehicle/AbstractMinecartEntity$Type;
     152: invokestatic  #136                // Method net/minecraft/entity/vehicle/AbstractMinecartEntity.create:(Lnet/minecraft/world/World;DDDLnet/minecraft/entity/vehicle/AbstractMinecartEntity$Type;)Lnet/minecraft/entity/vehicle/AbstractMinecartEntity;
其实解决起来也很容易,另找合适的注入点即可。但是,这一问题确实是一个大坑,还请大家注意。


第一页 上一页 下一页 最后一页