youyihj
本帖最后由 youyihj 于 2023-1-9 10:33 编辑

mojang 判断 UUID 相等居然用 == 的(


1.12.2 ItemStack 的 getTooltip 方法。

用 ASM 也能接受

gooding300
本帖最后由 gooding300 于 2023-1-9 14:03 编辑

思路就是把if_acmpne改成ifeq再在前面加一个invokestatic java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z

ASM的话,比较简单的办法是用TreeAPI,具体来说先拿到ItemStack的getTooltip方法的MethodNode,遍历instruments找到if_acmpne,然后判断一下上面2个instruments有没有invokevirtual net.minecraft.entity.ai.attributes.getID ()Ljava/util/UUID;,有的话就把指令替换成ifeq(跳转地址不变),再在前面加一个invokestatic java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z
因为涉及到上下文关系,用CoreAPI没想到有什么比较干净的办法,等其他大佬的解答。

我的Mixin水平你也知道.jpg
Mixin的话有人写了可以戳我一下。

适用于1.12.2的CoreMod教程,有帮助的话可以点个star:https://github.com/xfl03/CoreModTutor/blob/master/book/4.2.md



无敌三脚猫
gooding300 发表于 2023-1-9 11:43
思路就是把if_acmpne改成ifeq再在前面加一个invokestatic java/util/Objects.equals:(Ljava/lang/Object;Lj ...

我是sb,为什么以前我连equals都不知道我以前写的是在getID()后面,以及getID()后面的后面,加上getLeastSignificantBits(),变成比较半边UUID
  1. var Opcodes = Java.type('org.objectweb.asm.Opcodes');
  2. var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode');
  3. var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode');

  4. function initializeCoreMod() {
  5.         return {
  6.                 'uuid': {
  7.                         'target': {
  8.                                 'type': 'METHOD',
  9.                                 'class': 'net.minecraft.item.ItemStack',
  10.                                 'methodName': 'func_82840_a',
  11.                                 'methodDesc': '(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/client/util/ITooltipFlag;)Ljava/util/List;'
  12.                         },
  13.                         'transformer': function(node) {
  14.                                 node.maxStack+=2;
  15.                                 var flag=0;
  16.                                 var arrayLength = node.instructions.size();
  17.                                 for (var i = 0; i < arrayLength; ++i) {
  18.                                         if (node.instructions.get(i).getOpcode() == Opcodes.INVOKEVIRTUAL)
  19.                                                 if (node.instructions.get(i).name == "func_111167_a"){
  20.                                                         flag++;
  21.                                                         node.instructions.insert(node.instructions.get(i),new MethodInsnNode(Opcodes.INVOKEVIRTUAL,"java/util/UUID","getLeastSignificantBits","()J"));
  22.                                                         node.instructions.insert(node.instructions.get(i+2),new MethodInsnNode(Opcodes.INVOKEVIRTUAL,"java/util/UUID","getLeastSignificantBits","()J"));
  23.                                                         node.instructions.get(i+4).setOpcode(Opcodes.IFNE);
  24.                                                         node.instructions.insertBefore(node.instructions.get(i+4),new InsnNode(Opcodes.LCMP));
  25.                                                         if(flag==2)break;
  26.                                         }
  27.                                 }
  28.                                 return node;
  29.                         }
  30.                 }
  31.         };
  32. }
  33. ''
复制代码

gooding300
无敌三脚猫 发表于 2023-1-9 17:45
我是sb,为什么以前我连equals都不知道我以前写的是在getID()后面,以及getID()后面的后面,加上getLeast ...

也算是个办法,就是如果getID()有别的用途的话(比如不只是用来比较的话),可能会出问题

youyihj
gooding300 发表于 2023-1-9 11:43
思路就是把if_acmpne改成ifeq再在前面加一个invokestatic java/util/Objects.equals:(Ljava/lang/Object;Lj ...

我 Mixin 就看你的教程学的,ASM 你教程没写,催更

后来我就用 ASM Core API 解决的,参考 Mixin At 的 ordinal 参数的思路。我就重载了 MethodVisitor#visitJumpInsn 使其替换了第 2 和第 3 个 if_acmpne 指令(需要替换的这两个 ==)。

gooding300
youyihj 发表于 2023-1-10 14:36
我 Mixin 就看你的教程学的,ASM 你教程没写,催更

后来我就用 ASM Core API 解决的,参考 Mixin ...

我觉得这样的做法不可取,万一这个类被其他mod改了,需要替换的这两个 ==不再是第2、第3个if_acmpne就出问题了,还是根据上下文关系进行判断会比较靠谱

youyihj
gooding300 发表于 2023-1-10 17:20
我觉得这样的做法不可取,万一这个类被其他mod改了,需要替换的这两个 ==不再是第2、第3个if_acmpne就出 ...

合理,如果是上下文处理的话。给自定义的 MethodVisitor 加一个 flag 字段,visitMethodInsn 方法中如果方法是 getID 方法,就把这个字段设为 true,然后 visitJumpInsn 检查这个字段为 true 后再进行操作。

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