KajetansTransformer.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. package me.kcm;
  2. import java.util.ListIterator;
  3. import me.kcm.events.*;
  4. import net.minecraft.launchwrapper.IClassTransformer;
  5. import net.minecraftforge.fml.common.asm.transformers.DeobfuscationTransformer;
  6. import net.minecraftforge.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper;
  7. import org.objectweb.asm.ClassReader;
  8. import org.objectweb.asm.ClassWriter;
  9. import org.objectweb.asm.Opcodes;
  10. import org.objectweb.asm.tree.AbstractInsnNode;
  11. import org.objectweb.asm.tree.ClassNode;
  12. import org.objectweb.asm.tree.FieldInsnNode;
  13. import org.objectweb.asm.tree.FrameNode;
  14. import org.objectweb.asm.tree.InsnList;
  15. import org.objectweb.asm.tree.InsnNode;
  16. import org.objectweb.asm.tree.JumpInsnNode;
  17. import org.objectweb.asm.tree.LabelNode;
  18. import org.objectweb.asm.tree.LineNumberNode;
  19. import org.objectweb.asm.tree.MethodInsnNode;
  20. import org.objectweb.asm.tree.MethodNode;
  21. import org.objectweb.asm.tree.VarInsnNode;
  22. public class KajetansTransformer implements IClassTransformer
  23. {
  24. private void printPatch(Class c)
  25. {
  26. System.out.println("|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾");
  27. System.out.println("| Patching " + c.getSimpleName());
  28. System.out.println("|___________________________________________________");
  29. }
  30. @Override
  31. public byte[] transform(String old, String searge, byte[] bytes)
  32. {
  33. switch(searge)
  34. {
  35. case "net.minecraft.entity.EntityLivingBase":
  36. printPatch(LivingDamageCalculationEvent.class);
  37. return patchDamageHook(old, bytes, !old.equals(searge));
  38. case "net.minecraft.entity.player.EntityPlayerMP":
  39. printPatch(PlayerTabListNameEvent.class);
  40. return patchTabList(old, bytes, !old.equals(searge));
  41. case "net.minecraft.entity.Entity":
  42. printPatch(FarmlandTrampleEvent.class);
  43. return patchEntityCanTrample(old, bytes, !old.equals(searge));
  44. case "net.minecraft.server.management.PlayerList":
  45. printPatch(PlayerConnectionEvent.class);
  46. return patchPlayerList(old, bytes, !old.equals(searge));
  47. }
  48. return bytes;
  49. }
  50. /*ListIterator<AbstractInsnNode> list = ins.iterator();
  51. while(list.hasNext())
  52. {
  53. AbstractInsnNode next = list.next();
  54. System.out.println(getString(next));
  55. }*/
  56. public byte[] patchDamageHook(String c, byte[] bytes, boolean obfuscated)
  57. {
  58. try
  59. {
  60. ClassNode classNode = new ClassNode();
  61. ClassReader classReader = new ClassReader(bytes);
  62. classReader.accept(classNode, 0);
  63. // EntityLivingBase <--> vp
  64. // damageEntity <--> func_70665_d <--> d
  65. MethodNode mn;
  66. if(obfuscated)
  67. {
  68. mn = classNode.methods.stream().filter(me -> me.name.equals("d")).filter(me -> "(Lur;F)V".equals(me.desc)).findAny().get();
  69. }
  70. else
  71. {
  72. mn = classNode.methods.stream().filter(me -> me.name.equals("damageEntity")).findAny().get();
  73. }
  74. InsnList ins = mn.instructions;
  75. ins.insert(ins.get(3), new VarInsnNode(Opcodes.FLOAD, 2));
  76. if(obfuscated)
  77. {
  78. ins.insert(ins.get(4), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onDamageCalculation", "(Lvp;Lur;F)V", false));
  79. }
  80. else
  81. {
  82. ins.insert(ins.get(4), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks",
  83. "onDamageCalculation", "(Lnet/minecraft/entity/EntityLivingBase;Lnet/minecraft/util/DamageSource;F)V", false));
  84. }
  85. while(ins.size() > 8)
  86. {
  87. ins.remove(ins.get(6));
  88. }
  89. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  90. classNode.accept(writer);
  91. return writer.toByteArray();
  92. }
  93. catch(Exception ex)
  94. {
  95. ex.printStackTrace();
  96. }
  97. return bytes;
  98. }
  99. public byte[] patchTabList(String c, byte[] bytes, boolean obfuscated)
  100. {
  101. try
  102. {
  103. ClassNode classNode = new ClassNode();
  104. ClassReader classReader = new ClassReader(bytes);
  105. classReader.accept(classNode, 0);
  106. // EntityPlayerMP <--> oq
  107. // getTabListDisplayName <--> func_175396_E <--> K
  108. // MD: oq/K ()Lhh; net/minecraft/entity/player/EntityPlayerMP/func_175396_E ()Lnet/minecraft/util/text/ITextComponent;
  109. MethodNode mn;
  110. if(obfuscated)
  111. {
  112. mn = classNode.methods.stream().filter(me -> me.name.equals("K")).filter(me -> "()Lhh;".equals(me.desc)).findAny().get();
  113. }
  114. else
  115. {
  116. mn = classNode.methods.stream().filter(me -> me.name.equals("getTabListDisplayName")).findAny().get();
  117. }
  118. InsnList ins = mn.instructions;
  119. ins.remove(ins.get(2));
  120. ins.insert(ins.get(1), new VarInsnNode(Opcodes.ALOAD, 0));
  121. if(obfuscated)
  122. {
  123. ins.insert(ins.get(2), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onGetTabListDisplayName", "(Loq;)Lhh;", false));
  124. }
  125. else
  126. {
  127. ins.insert(ins.get(2), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks",
  128. "onGetTabListDisplayName", "(Lnet/minecraft/entity/player/EntityPlayerMP;)Lnet/minecraft/util/text/ITextComponent;", false));
  129. }
  130. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  131. classNode.accept(writer);
  132. return writer.toByteArray();
  133. }
  134. catch(Exception ex)
  135. {
  136. ex.printStackTrace();
  137. }
  138. return bytes;
  139. }
  140. public byte[] patchEntityCanTrample(String c, byte[] bytes, boolean obfuscated)
  141. {
  142. try
  143. {
  144. ClassNode classNode = new ClassNode();
  145. ClassReader classReader = new ClassReader(bytes);
  146. classReader.accept(classNode, 0);
  147. // CL: vg net/minecraft/entity/Entity
  148. // Entity <--> vg
  149. // canTrample is forge function
  150. // Lnet/minecraft/world/World;Lnet/minecraft/block/Block;Lnet/minecraft/util/math/BlockPos;F
  151. // World <--> amu
  152. // Block <--> aow
  153. // BlockPos <--> et
  154. MethodNode mn = classNode.methods.stream().filter(me -> me.name.equals("canTrample")).findAny().get();
  155. InsnList ins = mn.instructions;
  156. int i = ins.size();
  157. LabelNode label = null;
  158. int counter = 0;
  159. while(counter < 3)
  160. {
  161. i--;
  162. if(ins.get(i) instanceof LabelNode)
  163. {
  164. counter++;
  165. label = (LabelNode) ins.get(i);
  166. }
  167. }
  168. while(ins.get(i).getOpcode() != Opcodes.IFLE)
  169. {
  170. i--;
  171. }
  172. ins.insert(ins.get(i), new JumpInsnNode(Opcodes.IFEQ, label));
  173. if(obfuscated)
  174. {
  175. ins.insert(ins.get(i), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks",
  176. "onEntityCanTrample", "(Lvg;Lamu;Laow;Let;F)Z", false));
  177. }
  178. else
  179. {
  180. ins.insert(ins.get(i), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks",
  181. "onEntityCanTrample", "(Lnet/minecraft/entity/Entity;Lnet/minecraft/world/World;"
  182. + "Lnet/minecraft/block/Block;Lnet/minecraft/util/math/BlockPos;F)Z", false));
  183. }
  184. ins.insert(ins.get(i), new VarInsnNode(Opcodes.FLOAD, 4));
  185. ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 3));
  186. ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 2));
  187. ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 1));
  188. ins.insert(ins.get(i), new VarInsnNode(Opcodes.ALOAD, 0));
  189. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  190. classNode.accept(writer);
  191. return writer.toByteArray();
  192. }
  193. catch(Exception ex)
  194. {
  195. ex.printStackTrace();
  196. }
  197. return bytes;
  198. }
  199. public byte[] patchPlayerList(String c, byte[] bytes, boolean obfuscated)
  200. {
  201. try
  202. {
  203. ClassNode classNode = new ClassNode();
  204. ClassReader classReader = new ClassReader(bytes);
  205. classReader.accept(classNode, 0);
  206. // EntityPlayerMP <--> oq
  207. // initializeConnectionToPlayer <--> func_72355_a <--> a
  208. //MD: pl/a (Lgw;Loq;)V net/minecraft/server/management/PlayerList/func_72355_a
  209. // (Lnet/minecraft/network/NetworkManager;Lnet/minecraft/entity/player/EntityPlayerMP;)V
  210. // CL: pa net/minecraft/network/NetHandlerPlayServer
  211. // public void initializeConnectionToPlayer(NetworkManager netManager, EntityPlayerMP playerIn, NetHandlerPlayServer nethandlerplayserver)
  212. // its something else: (Lgw;Loq;Lpa;)V
  213. // it seems forge is already overwriting this method
  214. MethodNode mn = classNode.methods.stream().filter(me -> me.name.equals("initializeConnectionToPlayer")).findAny().get();
  215. InsnList ins = mn.instructions;
  216. int index = 0;
  217. AbstractInsnNode node;
  218. // first part - inserting PlayerConnectionEvent hook
  219. // connection <--> field_71135_a <--> a
  220. // FD: oq/a net/minecraft/entity/player/EntityPlayerMP/field_71135_a
  221. String search = obfuscated ? "a" : "connection";
  222. String playerOwner = obfuscated ? "oq" : "net/minecraft/entity/player/EntityPlayerMP";
  223. boolean found = false;
  224. while(index < ins.size())
  225. {
  226. node = ins.get(index);
  227. if(node instanceof FieldInsnNode)
  228. {
  229. FieldInsnNode field = (FieldInsnNode) node;
  230. if(field.name.equals(search) && field.owner.equals(playerOwner))
  231. {
  232. found = true;
  233. break;
  234. }
  235. }
  236. index++;
  237. }
  238. if(!found)
  239. {
  240. System.out.println("Start of player connection was not found");
  241. return bytes;
  242. }
  243. if(obfuscated)
  244. {
  245. ins.insert(ins.get(index), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks", "onPlayerConnection", "(Loq;)V", false));
  246. }
  247. else
  248. {
  249. ins.insert(ins.get(index), new MethodInsnNode(Opcodes.INVOKESTATIC, "me/kcm/events/Hooks",
  250. "onPlayerConnection", "(Lnet/minecraft/entity/player/EntityPlayerMP;)V", false));
  251. }
  252. ins.insert(ins.get(index), new VarInsnNode(Opcodes.ALOAD, 2));
  253. // end of first part - inserting PlayerConnectionEvent hook
  254. // second part - removing join message
  255. // func_70005_c_
  256. // MD: aed/h_ ()Ljava/lang/String; net/minecraft/entity/player/EntityPlayer/func_70005_c_ ()Ljava/lang/String;
  257. String start = "equalsIgnoreCase";
  258. String startDesc = "(Ljava/lang/String;)Z";
  259. // func_148539_a
  260. // MD: pl/a (Lhh;)V net/minecraft/server/management/PlayerList/func_148539_a (Lnet/minecraft/util/text/ITextComponent;)V
  261. String end = obfuscated ? "a" : "sendMessage";
  262. String endDesc = obfuscated ? "(Lhh;)V" : "(Lnet/minecraft/util/text/ITextComponent;)V";
  263. found = false;
  264. while(index < ins.size())
  265. {
  266. node = ins.get(index);
  267. if(node instanceof MethodInsnNode)
  268. {
  269. MethodInsnNode mnode = (MethodInsnNode) node;
  270. if(mnode.name.equals(start) && mnode.desc.equals(startDesc))
  271. {
  272. found = true;
  273. break;
  274. }
  275. }
  276. index++;
  277. }
  278. if(!found)
  279. {
  280. System.out.println("Start of player join message was not found");
  281. return bytes;
  282. }
  283. // moving to real start of the block "p.getName()..."
  284. index -= 3;
  285. while(true)
  286. {
  287. node = ins.get(index);
  288. if(node instanceof MethodInsnNode)
  289. {
  290. MethodInsnNode mnode = (MethodInsnNode) node;
  291. if(mnode.name.equals(end) && mnode.desc.equals(endDesc))
  292. {
  293. ins.remove(node);
  294. break;
  295. }
  296. }
  297. ins.remove(node);
  298. }
  299. // End of second Part - Removing join message
  300. ListIterator<AbstractInsnNode> list = ins.iterator();
  301. while(list.hasNext())
  302. {
  303. AbstractInsnNode next = list.next();
  304. System.out.println(getString(next));
  305. }
  306. ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
  307. classNode.accept(writer);
  308. return writer.toByteArray();
  309. }
  310. catch(Exception ex)
  311. {
  312. ex.printStackTrace();
  313. }
  314. return bytes;
  315. }
  316. public String getString(AbstractInsnNode node)
  317. {
  318. StringBuilder sb = new StringBuilder();
  319. sb.append(node.getClass().getSimpleName());
  320. sb.append(" ");
  321. sb.append(node.getOpcode());
  322. sb.append(" ");
  323. sb.append(node.getType());
  324. sb.append(" ");
  325. if(node instanceof LineNumberNode)
  326. {
  327. LineNumberNode n = (LineNumberNode) node;
  328. sb.append(n.line);
  329. sb.append(" ");
  330. sb.append(n.start);
  331. }
  332. else if(node instanceof VarInsnNode)
  333. {
  334. VarInsnNode n = (VarInsnNode) node;
  335. sb.append(n.var);
  336. }
  337. else if(node instanceof MethodInsnNode)
  338. {
  339. MethodInsnNode n = (MethodInsnNode) node;
  340. sb.append(n.desc);
  341. sb.append(" ");
  342. sb.append(n.itf);
  343. sb.append(" ");
  344. sb.append(n.name);
  345. sb.append(" ");
  346. sb.append(n.owner);
  347. }
  348. else if(node instanceof FrameNode)
  349. {
  350. FrameNode n = (FrameNode) node;
  351. if(n.local != null)
  352. {
  353. n.local.forEach(s -> {sb.append(s); sb.append(" ");});
  354. }
  355. if(n.stack != null)
  356. {
  357. n.stack.forEach(s -> {sb.append(s); sb.append(" ");});
  358. }
  359. }
  360. else if(node instanceof InsnNode)
  361. {
  362. }
  363. else if(node instanceof FieldInsnNode)
  364. {
  365. FieldInsnNode n = (FieldInsnNode) node;
  366. sb.append(n.desc);
  367. sb.append(" ");
  368. sb.append(n.name);
  369. sb.append(" ");
  370. sb.append(n.owner);
  371. }
  372. return sb.toString();
  373. }
  374. }