|
1 | 1 | package org.mcphackers.mcp.tasks; |
2 | 2 |
|
3 | | -import java.io.BufferedReader; |
4 | | -import java.io.IOException; |
5 | | -import java.nio.file.Files; |
6 | | -import java.nio.file.Path; |
7 | | -import java.nio.file.Paths; |
8 | | -import java.util.HashMap; |
9 | | -import java.util.Map; |
10 | | - |
| 3 | +import net.fabricmc.mappingio.adapter.MappingNsCompleter; |
| 4 | +import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; |
| 5 | +import net.fabricmc.mappingio.tree.MappingTree; |
| 6 | +import net.fabricmc.mappingio.tree.MemoryMappingTree; |
11 | 7 | import org.mcphackers.mcp.MCPConfig; |
12 | 8 | import org.mcphackers.mcp.ProgressInfo; |
13 | 9 | import org.mcphackers.mcp.tasks.info.TaskInfo; |
14 | 10 | import org.mcphackers.mcp.tools.FileUtil; |
15 | 11 | import org.mcphackers.mcp.tools.Util; |
16 | 12 | import org.mcphackers.mcp.tools.mappings.MappingUtil; |
17 | 13 |
|
18 | | -import net.fabricmc.mappingio.adapter.MappingNsCompleter; |
19 | | -import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; |
20 | | -import net.fabricmc.mappingio.tree.MappingTree; |
21 | | -import net.fabricmc.mappingio.tree.MemoryMappingTree; |
| 14 | +import java.io.BufferedReader; |
| 15 | +import java.io.IOException; |
| 16 | +import java.nio.file.Files; |
| 17 | +import java.nio.file.Path; |
| 18 | +import java.nio.file.Paths; |
| 19 | +import java.util.HashMap; |
| 20 | +import java.util.Map; |
22 | 21 |
|
23 | 22 | public class TaskReobfuscate extends Task { |
24 | | - private Map<String, String> recompHashes = new HashMap<>(); |
25 | | - private Map<String, String> originalHashes = new HashMap<>(); |
26 | | - |
27 | | - private MemoryMappingTree mappingTree = new MemoryMappingTree(); |
28 | | - |
29 | | - private Map<String, String> reobfPackages = new HashMap<>(); |
30 | | - |
31 | | - private TaskUpdateMD5 md5Task = new TaskUpdateMD5(side, info); |
32 | | - |
33 | | - public TaskReobfuscate(int side, TaskInfo info) { |
34 | | - super(side, info); |
35 | | - } |
36 | | - |
37 | | - @Override |
38 | | - public void doTask() throws Exception { |
39 | | - |
40 | | - Path reobfJar = Paths.get(chooseFromSide(MCPConfig.CLIENT_REOBF_JAR, MCPConfig.SERVER_REOBF_JAR)); |
41 | | - Path reobfBin = Paths.get(chooseFromSide(MCPConfig.CLIENT_BIN, MCPConfig.SERVER_BIN)); |
42 | | - Path reobfDir = Paths.get(chooseFromSide(MCPConfig.CLIENT_REOBF, MCPConfig.SERVER_REOBF)); |
43 | | - Path reobfMappings = Paths.get(chooseFromSide(MCPConfig.CLIENT_MAPPINGS_RO, MCPConfig.SERVER_MAPPINGS_RO)); |
44 | | - Path deobfMappings = Paths.get(chooseFromSide(MCPConfig.CLIENT_MAPPINGS_DO, MCPConfig.SERVER_MAPPINGS_DO)); |
45 | | - |
46 | | - step(); |
47 | | - md5Task.updateMD5(true); |
48 | | - |
49 | | - if (Files.exists(reobfBin)) { |
50 | | - boolean hasMappings = Files.exists(deobfMappings); |
51 | | - FileUtil.deleteDirectoryIfExists(reobfDir); |
52 | | - step(); |
53 | | - gatherMD5Hashes(true); |
54 | | - gatherMD5Hashes(false); |
55 | | - |
56 | | - step(); |
57 | | - if(hasMappings) { |
58 | | - MappingUtil.readMappings(deobfMappings, mappingTree); |
59 | | - flipMappingTree(); |
60 | | - MappingUtil.modifyMappings(mappingTree, reobfBin, className -> { |
61 | | - if (mappingTree.getClass(className) == null) { // Class isn't present in original mappings |
62 | | - String packageName = className.lastIndexOf("/") >= 0 ? className.substring(0, className.lastIndexOf("/") + 1) : null; |
63 | | - String obfPackage = reobfPackages.get(packageName); |
64 | | - if(obfPackage == null) { |
65 | | - obfPackage = ""; |
66 | | - } |
67 | | - return obfPackage + (className.lastIndexOf("/") >= 0 ? className.substring(className.lastIndexOf("/") + 1) : className); |
68 | | - } |
69 | | - return null; // Returning null skips remapping this class |
70 | | - }); |
71 | | - MappingUtil.writeMappings(reobfMappings, mappingTree); |
72 | | - |
73 | | - } |
74 | | - |
75 | | - Files.deleteIfExists(reobfJar); |
76 | | - if(hasMappings) { |
77 | | - MappingUtil.remap(reobfMappings, reobfBin, reobfJar, TaskDecompile.getLibraryPaths(side)); |
78 | | - } |
79 | | - else { |
80 | | - FileUtil.compress(reobfBin, reobfJar); |
81 | | - } |
82 | | - step(); |
83 | | - unpack(reobfJar, reobfDir); |
84 | | - } else { |
85 | | - throw new IOException(chooseFromSide("Client", "Server") + " classes not found!"); |
86 | | - } |
87 | | - } |
88 | | - |
89 | | - private void flipMappingTree() throws IOException { |
90 | | - ((MappingTree)mappingTree).getClasses().stream().forEach(classEntry -> { |
91 | | - String obfName = classEntry.getName("official"); |
92 | | - String deobfName = classEntry.getName("named"); |
93 | | - String obfPackage = obfName.lastIndexOf("/") >= 0 ? obfName.substring(0, obfName.lastIndexOf("/") + 1) : ""; |
94 | | - String deobfPackage = deobfName.lastIndexOf("/") >= 0 ? deobfName.substring(0, deobfName.lastIndexOf("/") + 1) : ""; |
95 | | - if(!reobfPackages.containsKey(deobfPackage)) { |
96 | | - reobfPackages.put(deobfPackage, obfPackage); |
97 | | - } |
98 | | - }); |
99 | | - |
100 | | - Map namespaces = new HashMap(); |
101 | | - namespaces.put("named", "official"); |
102 | | - MemoryMappingTree namedTree = new MemoryMappingTree(); |
103 | | - MappingNsCompleter nsCompleter = new MappingNsCompleter(namedTree, namespaces); |
104 | | - MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsCompleter, "named"); |
105 | | - mappingTree.accept(nsSwitch); |
106 | | - mappingTree = namedTree; |
107 | | - } |
108 | | - |
109 | | - @Override |
110 | | - public ProgressInfo getProgress() { |
111 | | - int total = 100; |
112 | | - int current; |
113 | | - switch (step) { |
114 | | - case 1: { |
115 | | - current = 1; |
116 | | - ProgressInfo info = md5Task.getProgress(); |
117 | | - int percent = info.getCurrent() / info.getTotal() * 50; |
118 | | - return new ProgressInfo(info.getMessage(), current + percent, total); |
119 | | - } |
120 | | - case 2: |
121 | | - current = 51; |
122 | | - return new ProgressInfo("Gathering MD5 hashes...", current, total); |
123 | | - case 3: |
124 | | - current = 52; |
125 | | - return new ProgressInfo("Reobfuscating...", current, total); |
126 | | - case 4: |
127 | | - current = 54; |
128 | | - return new ProgressInfo("Unpacking...", current, total); |
129 | | - default: |
130 | | - return super.getProgress(); |
131 | | - } |
132 | | - } |
133 | | - |
134 | | - private void gatherMD5Hashes(boolean reobf) throws IOException { |
135 | | - Path md5 = Paths.get(reobf ? chooseFromSide(MCPConfig.CLIENT_MD5_RO, MCPConfig.SERVER_MD5_RO) |
136 | | - : chooseFromSide(MCPConfig.CLIENT_MD5, MCPConfig.SERVER_MD5)); |
137 | | - |
138 | | - try (BufferedReader reader = Files.newBufferedReader(md5)) { |
139 | | - String line = reader.readLine(); |
140 | | - while (line != null) { |
141 | | - String[] tokens = line.split(" "); |
142 | | - if (reobf) { |
143 | | - recompHashes.put(tokens[0], tokens[1]); |
144 | | - } else { |
145 | | - originalHashes.put(tokens[0], tokens[1]); |
146 | | - } |
147 | | - |
148 | | - // Read next line |
149 | | - line = reader.readLine(); |
150 | | - } |
151 | | - } |
152 | | - } |
153 | | - |
154 | | - private void unpack(final Path src, final Path destDir) throws IOException { |
155 | | - Map<String, String> reobfClasses = new HashMap<>(); |
156 | | - ((MappingTree) mappingTree).getClasses().forEach(classEntry -> { |
157 | | - reobfClasses.put(classEntry.getName("named"), classEntry.getDstName(0)); |
158 | | - }); |
159 | | - FileUtil.unzip(src, destDir, entry -> { |
160 | | - String name = entry.getName().replace(".class", ""); |
161 | | - String deobfName = Util.getKey(reobfClasses, name); |
162 | | - if(deobfName == null) deobfName = name.replace("\\", "/"); |
163 | | - String hash = originalHashes.get(deobfName); |
164 | | - return !entry.isDirectory() && (hash == null || !hash.equals(recompHashes.get(deobfName))); |
165 | | - }); |
166 | | - } |
| 23 | + private final Map<String, String> recompHashes = new HashMap<>(); |
| 24 | + private final Map<String, String> originalHashes = new HashMap<>(); |
| 25 | + |
| 26 | + private MemoryMappingTree mappingTree = new MemoryMappingTree(); |
| 27 | + |
| 28 | + private final Map<String, String> reobfPackages = new HashMap<>(); |
| 29 | + |
| 30 | + private final TaskUpdateMD5 md5Task = new TaskUpdateMD5(side, info); |
| 31 | + |
| 32 | + public TaskReobfuscate(int side, TaskInfo info) { |
| 33 | + super(side, info); |
| 34 | + } |
| 35 | + |
| 36 | + @Override |
| 37 | + public void doTask() throws Exception { |
| 38 | + |
| 39 | + Path reobfJar = Paths.get(chooseFromSide(MCPConfig.CLIENT_REOBF_JAR, MCPConfig.SERVER_REOBF_JAR)); |
| 40 | + Path reobfBin = Paths.get(chooseFromSide(MCPConfig.CLIENT_BIN, MCPConfig.SERVER_BIN)); |
| 41 | + Path reobfDir = Paths.get(chooseFromSide(MCPConfig.CLIENT_REOBF, MCPConfig.SERVER_REOBF)); |
| 42 | + Path reobfMappings = Paths.get(chooseFromSide(MCPConfig.CLIENT_MAPPINGS_RO, MCPConfig.SERVER_MAPPINGS_RO)); |
| 43 | + Path deobfMappings = Paths.get(chooseFromSide(MCPConfig.CLIENT_MAPPINGS_DO, MCPConfig.SERVER_MAPPINGS_DO)); |
| 44 | + |
| 45 | + step(); |
| 46 | + md5Task.updateMD5(true); |
| 47 | + |
| 48 | + if (Files.exists(reobfBin)) { |
| 49 | + boolean hasMappings = Files.exists(deobfMappings); |
| 50 | + FileUtil.deleteDirectoryIfExists(reobfDir); |
| 51 | + step(); |
| 52 | + gatherMD5Hashes(true); |
| 53 | + gatherMD5Hashes(false); |
| 54 | + |
| 55 | + step(); |
| 56 | + if (hasMappings) { |
| 57 | + MappingUtil.readMappings(deobfMappings, mappingTree); |
| 58 | + flipMappingTree(); |
| 59 | + MappingUtil.modifyMappings(mappingTree, reobfBin, className -> { |
| 60 | + if (mappingTree.getClass(className) == null) { // Class isn't present in original mappings |
| 61 | + String packageName = className.lastIndexOf("/") >= 0 ? className.substring(0, className.lastIndexOf("/") + 1) : null; |
| 62 | + String obfPackage = reobfPackages.get(packageName); |
| 63 | + if (obfPackage == null) { |
| 64 | + obfPackage = ""; |
| 65 | + } |
| 66 | + return obfPackage + (className.lastIndexOf("/") >= 0 ? className.substring(className.lastIndexOf("/") + 1) : className); |
| 67 | + } |
| 68 | + return null; // Returning null skips remapping this class |
| 69 | + }); |
| 70 | + MappingUtil.writeMappings(reobfMappings, mappingTree); |
| 71 | + |
| 72 | + } |
| 73 | + |
| 74 | + Files.deleteIfExists(reobfJar); |
| 75 | + if (hasMappings) { |
| 76 | + MappingUtil.remap(reobfMappings, reobfBin, reobfJar, TaskDecompile.getLibraryPaths(side)); |
| 77 | + } else { |
| 78 | + FileUtil.compress(reobfBin, reobfJar); |
| 79 | + } |
| 80 | + step(); |
| 81 | + unpack(reobfJar, reobfDir); |
| 82 | + } else { |
| 83 | + throw new IOException(chooseFromSide("Client", "Server") + " classes not found!"); |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + private void flipMappingTree() throws IOException { |
| 88 | + ((MappingTree) mappingTree).getClasses().stream().forEach(classEntry -> { |
| 89 | + String obfName = classEntry.getName("official"); |
| 90 | + String deobfName = classEntry.getName("named"); |
| 91 | + if (deobfName != null) { |
| 92 | + String obfPackage = obfName.lastIndexOf("/") >= 0 ? obfName.substring(0, obfName.lastIndexOf("/") + 1) : ""; |
| 93 | + String deobfPackage = deobfName.lastIndexOf("/") >= 0 ? deobfName.substring(0, deobfName.lastIndexOf("/") + 1) : ""; |
| 94 | + if (!reobfPackages.containsKey(deobfPackage)) { |
| 95 | + reobfPackages.put(deobfPackage, obfPackage); |
| 96 | + } |
| 97 | + } |
| 98 | + }); |
| 99 | + |
| 100 | + Map<String, String> namespaces = new HashMap<>(); |
| 101 | + namespaces.put("named", "official"); |
| 102 | + MemoryMappingTree namedTree = new MemoryMappingTree(); |
| 103 | + MappingNsCompleter nsCompleter = new MappingNsCompleter(namedTree, namespaces); |
| 104 | + MappingSourceNsSwitch nsSwitch = new MappingSourceNsSwitch(nsCompleter, "named"); |
| 105 | + mappingTree.accept(nsSwitch); |
| 106 | + mappingTree = namedTree; |
| 107 | + } |
| 108 | + |
| 109 | + @Override |
| 110 | + public ProgressInfo getProgress() { |
| 111 | + int total = 100; |
| 112 | + int current; |
| 113 | + switch (step) { |
| 114 | + case 1: { |
| 115 | + current = 1; |
| 116 | + ProgressInfo info = md5Task.getProgress(); |
| 117 | + int percent = info.getCurrent() / info.getTotal() * 50; |
| 118 | + return new ProgressInfo(info.getMessage(), current + percent, total); |
| 119 | + } |
| 120 | + case 2: |
| 121 | + current = 51; |
| 122 | + return new ProgressInfo("Gathering MD5 hashes...", current, total); |
| 123 | + case 3: |
| 124 | + current = 52; |
| 125 | + return new ProgressInfo("Reobfuscating...", current, total); |
| 126 | + case 4: |
| 127 | + current = 54; |
| 128 | + return new ProgressInfo("Unpacking...", current, total); |
| 129 | + default: |
| 130 | + return super.getProgress(); |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + private void gatherMD5Hashes(boolean reobf) throws IOException { |
| 135 | + Path md5 = Paths.get(reobf ? chooseFromSide(MCPConfig.CLIENT_MD5_RO, MCPConfig.SERVER_MD5_RO) |
| 136 | + : chooseFromSide(MCPConfig.CLIENT_MD5, MCPConfig.SERVER_MD5)); |
| 137 | + |
| 138 | + try (BufferedReader reader = Files.newBufferedReader(md5)) { |
| 139 | + String line = reader.readLine(); |
| 140 | + while (line != null) { |
| 141 | + String[] tokens = line.split(" "); |
| 142 | + if (reobf) { |
| 143 | + recompHashes.put(tokens[0], tokens[1]); |
| 144 | + } else { |
| 145 | + originalHashes.put(tokens[0], tokens[1]); |
| 146 | + } |
| 147 | + |
| 148 | + // Read next line |
| 149 | + line = reader.readLine(); |
| 150 | + } |
| 151 | + } |
| 152 | + } |
| 153 | + |
| 154 | + private void unpack(final Path src, final Path destDir) throws IOException { |
| 155 | + Map<String, String> reobfClasses = new HashMap<>(); |
| 156 | + ((MappingTree) mappingTree).getClasses().forEach(classEntry -> { |
| 157 | + reobfClasses.put(classEntry.getName("named"), classEntry.getDstName(0)); |
| 158 | + }); |
| 159 | + FileUtil.unzip(src, destDir, entry -> { |
| 160 | + String name = entry.getName().replace(".class", ""); |
| 161 | + String deobfName = Util.getKey(reobfClasses, name); |
| 162 | + if (deobfName == null) deobfName = name.replace("\\", "/"); |
| 163 | + String hash = originalHashes.get(deobfName); |
| 164 | + return !entry.isDirectory() && (hash == null || !hash.equals(recompHashes.get(deobfName))); |
| 165 | + }); |
| 166 | + } |
167 | 167 | } |
0 commit comments