-
-
Notifications
You must be signed in to change notification settings - Fork 44
/
PrePatcher.java
116 lines (110 loc) · 4.1 KB
/
PrePatcher.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package me.nallar.nmsprepatcher;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.google.common.base.Splitter;
// The prepatcher adds method declarations in superclasses,
// so javac can compile the patch classes if they need to use a method/field they
// add on an instance other than this
public class PrePatcher {
private static final Logger log = Logger.getLogger("PatchLogger");
private static final Pattern privatePattern = Pattern.compile("^(\\s+?)private", Pattern.MULTILINE);
private static final Pattern extendsPattern = Pattern.compile("\\s+?extends\\s+?([\\S]+)[^\\{]+?\\{", Pattern.DOTALL | Pattern.MULTILINE);
private static final Pattern declarePattern = Pattern.compile("@Declare\\s+?(public\\s+?(\\S*?)?\\s+?(\\S*?)\\s*?\\S+?\\s*?\\([^\\{]*\\)\\s*?\\{)", Pattern.DOTALL | Pattern.MULTILINE);
public static void patch(File patchDirectory, File sourceDirectory) {
if (!patchDirectory.isDirectory()) {
throw new IllegalArgumentException("Not a directory! " + patchDirectory + ", " + sourceDirectory);
}
for (File file : patchDirectory.listFiles()) {
String contents = readFile(file);
if (contents == null) {
log.log(Level.SEVERE, "Failed to read " + file);
continue;
}
Matcher extendsMatcher = extendsPattern.matcher(contents);
if (!extendsMatcher.find()) {
log.info(file + " does not extend an NMS class.");
continue;
}
String shortClassName = extendsMatcher.group(1);
String className = null;
for (String line : Splitter.on('\n').split(contents)) {
if (line.endsWith('.' + shortClassName + ';')) {
className = line.substring(7, line.length() - 1);
}
}
if (className == null) {
log.info("Unable to find class " + shortClassName);
continue;
}
File sourceFile = new File(sourceDirectory, className.replace('.', '/') + ".java");
if (!sourceFile.exists()) {
log.severe("Can't find " + sourceFile + ", not patching.");
continue;
}
String sourceString = readFile(sourceFile).trim();
int previousIndex = sourceString.indexOf("\n//PREPATCH\n");
int cutIndex = previousIndex == -1 ? sourceString.lastIndexOf('}') : previousIndex;
StringBuilder source = new StringBuilder(sourceString.substring(0, cutIndex)).append("\n//PREPATCH\n");
log.info("Prepatching declarations for " + className);
Matcher matcher = declarePattern.matcher(contents);
while (matcher.find()) {
String type = matcher.group(2);
String ret = "null"; // TODO: Add more types.
if ("static".equals(type)) {
type = matcher.group(3);
}
if ("boolean".equals(type)) {
ret = "false";
} else if ("void".equals(type)) {
ret = "";
} else if ("int".equals(type)) {
ret = "0";
} else if ("float".equals(type)) {
ret = "0f";
}
String decl = matcher.group(1) + "return " + ret + ";}";
log.info("adding " + type + " -> " + decl);
if (source.indexOf(decl) == -1) {
source.append(decl);
}
}
source.append("\n}");
sourceString = source.toString();
Matcher privateMatcher = privatePattern.matcher(sourceString);
sourceString = privateMatcher.replaceAll("$1protected");
try {
writeFile(sourceFile, sourceString);
} catch (IOException e) {
log.log(Level.SEVERE, "Failed to save " + sourceFile, e);
}
}
}
private static String readFile(File file) {
Scanner fileReader = null;
try {
fileReader = new Scanner(file, "UTF-8").useDelimiter("\\A");
return fileReader.next().replace("\r\n", "\n");
} catch (FileNotFoundException ignored) {
} finally {
if (fileReader != null) {
fileReader.close();
}
}
return null;
}
private static void writeFile(File file, String contents) throws IOException {
FileWriter fileWriter = new FileWriter(file);
try {
fileWriter.write(contents);
} finally {
fileWriter.close();
}
}
}