methods = classNode.methods;
38 |
39 | if (methods == null) { // According to the documentation, methods might be null
40 | throw new VerificationException("Class has no methods to remove");
41 | }
42 |
43 | List toRemove = methods.stream().filter(method -> method.name.equals(methodName) && method.desc.equals(methodDesc)).collect(Collectors.toList());
44 | if (toRemove.isEmpty()) {
45 | //throw new VerificationException("Method to remove " + methodName + " not found, " + methodDesc);
46 | System.err.println("Method to remove " + methodName + " not found, " + methodDesc);
47 | }
48 | methods.removeAll(toRemove);
49 | }
50 |
51 | @Override
52 | public String getClassName() {
53 | return className;
54 | }
55 |
56 | @Override
57 | public boolean canBeAppliedAtRuntime() {
58 | return false;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/Hex.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils;
12 |
13 | import java.io.IOException;
14 | import java.nio.ByteBuffer;
15 |
16 | /**
17 | * Converts hexadecimal Strings. The charset used for certain operation can be set.
18 | *
19 | * This class is thread-safe.
20 | *
21 | * @since 1.1
22 | */
23 | public class Hex {
24 |
25 | /**
26 | * Used to build output as Hex
27 | */
28 | private static final char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
29 | 'e', 'f'};
30 |
31 | /**
32 | * Used to build output as Hex
33 | */
34 | private static final char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
35 | 'E', 'F'};
36 |
37 | public static byte[] decodeHex(final String data) throws IOException {
38 | return decodeHex(data.toCharArray());
39 | }
40 |
41 | public static byte[] decodeHex(final char[] data) throws IOException {
42 |
43 | final int len = data.length;
44 |
45 | if ((len & 0x01) != 0) {
46 | throw new IOException("Odd number of characters.");
47 | }
48 |
49 | final byte[] out = new byte[len >> 1];
50 |
51 | // two characters form the hex value.
52 | for (int i = 0, j = 0; j < len; i++) {
53 | int f = toDigit(data[j], j) << 4;
54 | j++;
55 | f = f | toDigit(data[j], j);
56 | j++;
57 | out[i] = (byte) (f & 0xFF);
58 | }
59 |
60 | return out;
61 | }
62 |
63 | /**
64 | * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
65 | * The returned array will be double the length of the passed array, as it takes two characters to represent any
66 | * given byte.
67 | *
68 | * @param data a byte[] to convert to Hex characters
69 | * @return A char[] containing lower-case hexadecimal characters
70 | */
71 | public static char[] encodeHex(final byte[] data) {
72 | return encodeHex(data, true);
73 | }
74 |
75 | /**
76 | * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The
77 | * returned array will be double the length of the passed array, as it takes two characters to represent any given
78 | * byte.
79 | *
80 | * @param data a byte buffer to convert to Hex characters
81 | * @return A char[] containing lower-case hexadecimal characters
82 | * @since 1.11
83 | */
84 | public static char[] encodeHex(final ByteBuffer data) {
85 | return encodeHex(data, true);
86 | }
87 |
88 | /**
89 | * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
90 | * The returned array will be double the length of the passed array, as it takes two characters to represent any
91 | * given byte.
92 | *
93 | * @param data a byte[] to convert to Hex characters
94 | * @param toLowerCase true
converts to lowercase, false
to uppercase
95 | * @return A char[] containing hexadecimal characters in the selected case
96 | * @since 1.4
97 | */
98 | public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
99 | return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
100 | }
101 |
102 | /**
103 | * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The
104 | * returned array will be double the length of the passed array, as it takes two characters to represent any given
105 | * byte.
106 | *
107 | * @param data a byte buffer to convert to Hex characters
108 | * @param toLowerCase true
converts to lowercase, false
to uppercase
109 | * @return A char[] containing hexadecimal characters in the selected case
110 | * @since 1.11
111 | */
112 | public static char[] encodeHex(final ByteBuffer data, final boolean toLowerCase) {
113 | return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
114 | }
115 |
116 | /**
117 | * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order.
118 | * The returned array will be double the length of the passed array, as it takes two characters to represent any
119 | * given byte.
120 | *
121 | * @param data a byte[] to convert to Hex characters
122 | * @param toDigits the output alphabet (must contain at least 16 chars)
123 | * @return A char[] containing the appropriate characters from the alphabet For best results, this should be either
124 | * upper- or lower-case hex.
125 | * @since 1.4
126 | */
127 | protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
128 | final int l = data.length;
129 | final char[] out = new char[l << 1];
130 | // two characters form the hex value.
131 | for (int i = 0, j = 0; i < l; i++) {
132 | out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
133 | out[j++] = toDigits[0x0F & data[i]];
134 | }
135 | return out;
136 | }
137 |
138 | /**
139 | * Converts a byte buffer into an array of characters representing the hexadecimal values of each byte in order. The
140 | * returned array will be double the length of the passed array, as it takes two characters to represent any given
141 | * byte.
142 | *
143 | * @param byteBuffer a byte buffer to convert to Hex characters
144 | * @param toDigits the output alphabet (must be at least 16 characters)
145 | * @return A char[] containing the appropriate characters from the alphabet For best results, this should be either
146 | * upper- or lower-case hex.
147 | * @since 1.11
148 | */
149 | protected static char[] encodeHex(final ByteBuffer byteBuffer, final char[] toDigits) {
150 | return encodeHex(toByteArray(byteBuffer), toDigits);
151 | }
152 |
153 | /**
154 | * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
155 | * String will be double the length of the passed array, as it takes two characters to represent any given byte.
156 | *
157 | * @param data a byte[] to convert to Hex characters
158 | * @return A String containing lower-case hexadecimal characters
159 | * @since 1.4
160 | */
161 | public static String encodeHexString(final byte[] data) {
162 | return new String(encodeHex(data));
163 | }
164 |
165 | /**
166 | * Converts an array of bytes into a String representing the hexadecimal values of each byte in order. The returned
167 | * String will be double the length of the passed array, as it takes two characters to represent any given byte.
168 | *
169 | * @param data a byte[] to convert to Hex characters
170 | * @param toLowerCase true
converts to lowercase, false
to uppercase
171 | * @return A String containing lower-case hexadecimal characters
172 | * @since 1.11
173 | */
174 | public static String encodeHexString(final byte[] data, final boolean toLowerCase) {
175 | return new String(encodeHex(data, toLowerCase));
176 | }
177 |
178 | /**
179 | * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
180 | * String will be double the length of the passed array, as it takes two characters to represent any given byte.
181 | *
182 | * @param data a byte buffer to convert to Hex characters
183 | * @return A String containing lower-case hexadecimal characters
184 | * @since 1.11
185 | */
186 | public static String encodeHexString(final ByteBuffer data) {
187 | return new String(encodeHex(data));
188 | }
189 |
190 | /**
191 | * Converts a byte buffer into a String representing the hexadecimal values of each byte in order. The returned
192 | * String will be double the length of the passed array, as it takes two characters to represent any given byte.
193 | *
194 | * @param data a byte buffer to convert to Hex characters
195 | * @param toLowerCase true
converts to lowercase, false
to uppercase
196 | * @return A String containing lower-case hexadecimal characters
197 | * @since 1.11
198 | */
199 | public static String encodeHexString(final ByteBuffer data, final boolean toLowerCase) {
200 | return new String(encodeHex(data, toLowerCase));
201 | }
202 |
203 | private static byte[] toByteArray(final ByteBuffer byteBuffer) {
204 | if (byteBuffer.hasArray()) {
205 | return byteBuffer.array();
206 | }
207 | final byte[] byteArray = new byte[byteBuffer.remaining()];
208 | byteBuffer.get(byteArray);
209 | return byteArray;
210 | }
211 |
212 | /**
213 | * Converts a hexadecimal character to an integer.
214 | *
215 | * @param ch A character to convert to an integer digit
216 | * @param index The index of the character in the source
217 | * @return An integer
218 | * @throws IOException Thrown if ch is an illegal hex character
219 | */
220 | protected static int toDigit(final char ch, final int index) throws IOException {
221 | final int digit = Character.digit(ch, 16);
222 | if (digit == -1) {
223 | throw new IOException("Illegal hexadecimal character " + ch + " at index " + index);
224 | }
225 | return digit;
226 | }
227 |
228 | }
229 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/InstructionComparator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils;
12 |
13 | import org.objectweb.asm.tree.*;
14 |
15 | import java.util.Arrays;
16 | import java.util.HashMap;
17 | import java.util.List;
18 | import java.util.Objects;
19 | import java.util.stream.Collectors;
20 |
21 | public class InstructionComparator {
22 |
23 | public static boolean isSame(InsnList insnListA, InsnList insnListB, List tryCatchA, List tryCatchB) {
24 | if (insnListA.size() != insnListB.size() || tryCatchA.size() != tryCatchB.size()) {
25 | return false;
26 | }
27 |
28 | HashMap labelIndexMap = calulateLabelIdecies(insnListA);
29 | labelIndexMap.putAll(calulateLabelIdecies(insnListB));
30 |
31 | AbstractInsnNode[] abstractInsnNodesA = insnListA.toArray();
32 | AbstractInsnNode[] abstractInsnNodesB = insnListB.toArray();
33 |
34 | for (int i = 0; i < abstractInsnNodesA.length; i++) {
35 | AbstractInsnNode a = abstractInsnNodesA[i];
36 | AbstractInsnNode b = abstractInsnNodesB[i];
37 |
38 | if (!isSame(labelIndexMap, a, b))
39 | return false;
40 | }
41 |
42 | for (int i = 0; i < tryCatchA.size(); i++) {
43 | TryCatchBlockNode a = tryCatchA.get(i);
44 | TryCatchBlockNode b = tryCatchB.get(i);
45 |
46 | if (!Objects.equals(a.type, b.type)
47 | || !labelIndexMap.get(a.start).equals(labelIndexMap.get(b.start))
48 | || !labelIndexMap.get(a.end).equals(labelIndexMap.get(b.end))
49 | || !labelIndexMap.get(a.handler).equals(labelIndexMap.get(b.handler))) {
50 | return false;
51 | }
52 | }
53 |
54 | return true;
55 | }
56 |
57 | private static boolean isSame(HashMap labelIndexMap, AbstractInsnNode a, AbstractInsnNode b) {
58 | if (a.getOpcode() != b.getOpcode() || a.getType() != b.getType() || a.getClass() != b.getClass()) {
59 | return false;
60 | }
61 |
62 | if (a instanceof FieldInsnNode) {
63 | FieldInsnNode fieldInsnNodeA = (FieldInsnNode) a;
64 | FieldInsnNode fieldInsnNodeB = (FieldInsnNode) b;
65 |
66 | return fieldInsnNodeA.owner.equals(fieldInsnNodeB.owner)
67 | && fieldInsnNodeA.name.equals(fieldInsnNodeB.name)
68 | && fieldInsnNodeA.desc.equals(fieldInsnNodeB.desc);
69 | }
70 | if (a instanceof MethodInsnNode) {
71 | MethodInsnNode methodInsnNodeA = (MethodInsnNode) a;
72 | MethodInsnNode methodInsnNodeB = (MethodInsnNode) b;
73 |
74 | return methodInsnNodeA.owner.equals(methodInsnNodeB.owner)
75 | && methodInsnNodeA.name.equals(methodInsnNodeB.name)
76 | && methodInsnNodeA.desc.equals(methodInsnNodeB.desc)
77 | && methodInsnNodeA.itf == methodInsnNodeB.itf;
78 | }
79 | if (a instanceof TableSwitchInsnNode) {
80 | TableSwitchInsnNode switchA = (TableSwitchInsnNode) a;
81 | TableSwitchInsnNode switchB = (TableSwitchInsnNode) b;
82 |
83 | if (!labelIndexMap.get(switchA.dflt).equals(labelIndexMap.get(switchB.dflt))) {
84 | return false;
85 | }
86 |
87 | if (switchA.min != switchB.min || switchA.max != switchB.max) {
88 | return false;
89 | }
90 |
91 | return switchA.labels
92 | .stream()
93 | .map(labelIndexMap::get)
94 | .collect(Collectors.toList())
95 | .equals(switchB.labels
96 | .stream()
97 | .map(labelIndexMap::get)
98 | .collect(Collectors.toList()));
99 |
100 |
101 | }
102 | if (a instanceof LineNumberNode) return true;
103 | if (a instanceof IincInsnNode) {
104 | IincInsnNode incA = (IincInsnNode) a;
105 | IincInsnNode incB = (IincInsnNode) b;
106 |
107 | return incA.incr == incB.incr && incA.var == incB.var;
108 | }
109 | if (a instanceof IntInsnNode) {
110 | return ((IntInsnNode) a).operand == ((IntInsnNode) b).operand;
111 | }
112 | if (a instanceof LabelNode) {
113 | return true;
114 | }
115 | if (a instanceof MultiANewArrayInsnNode) {
116 | MultiANewArrayInsnNode incA = (MultiANewArrayInsnNode) a;
117 | MultiANewArrayInsnNode incB = (MultiANewArrayInsnNode) b;
118 |
119 | return incA.desc.equals(incB.desc) && incA.dims == incB.dims;
120 | }
121 | if (a instanceof LdcInsnNode) {
122 | return ((LdcInsnNode) a).cst.equals(((LdcInsnNode) b).cst);
123 | }
124 | if (a instanceof TypeInsnNode) {
125 | return ((TypeInsnNode) a).desc.equals(((TypeInsnNode) b).desc);
126 | }
127 | if (a instanceof VarInsnNode) {
128 | return ((VarInsnNode) a).var == ((VarInsnNode) b).var;
129 | }
130 | if (a instanceof InvokeDynamicInsnNode) {
131 | InvokeDynamicInsnNode incA = (InvokeDynamicInsnNode) a;
132 | InvokeDynamicInsnNode incB = (InvokeDynamicInsnNode) b;
133 |
134 | return incA.bsm.equals(incB.bsm) && Arrays.equals(incA.bsmArgs, incB.bsmArgs) && incA.desc.equals(incB.desc) && incA.name.equals(incB.name);
135 | }
136 | if (a instanceof FrameNode) {
137 | return true; // Assuming true since if all instructions are the same, the frame can't be different
138 | }
139 | if (a instanceof JumpInsnNode) {
140 | JumpInsnNode incA = (JumpInsnNode) a;
141 | JumpInsnNode incB = (JumpInsnNode) b;
142 |
143 | return labelIndexMap.get(incA.label).equals(labelIndexMap.get(incB.label));
144 | }
145 | if (a instanceof LookupSwitchInsnNode) {
146 | LookupSwitchInsnNode switchA = (LookupSwitchInsnNode) a;
147 | LookupSwitchInsnNode switchB = (LookupSwitchInsnNode) b;
148 |
149 | if (!labelIndexMap.get(switchA.dflt).equals(labelIndexMap.get(switchB.dflt))) {
150 | return false;
151 | }
152 |
153 | if (!switchA.keys.equals(switchB.keys)) {
154 | return false;
155 | }
156 |
157 | return switchA.labels
158 | .stream()
159 | .map(labelIndexMap::get)
160 | .collect(Collectors.toList())
161 | .equals(switchB.labels
162 | .stream()
163 | .map(labelIndexMap::get)
164 | .collect(Collectors.toList()));
165 | }
166 |
167 | return true;
168 | }
169 |
170 | private static HashMap calulateLabelIdecies(InsnList insnListA) {
171 | HashMap ret = new HashMap<>();
172 |
173 | AbstractInsnNode[] abstractInsnNodes = insnListA.toArray();
174 |
175 | for (int i = 0; i < abstractInsnNodes.length; i++) {
176 | if (abstractInsnNodes[i] instanceof LabelNode) {
177 | ret.put((LabelNode) abstractInsnNodes[i], i);
178 | }
179 | }
180 |
181 | return ret;
182 | }
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/ScheduledRunnable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils;
12 |
13 | public interface ScheduledRunnable {
14 |
15 | /**
16 | * @return Returns true if the thread is ready to exit
17 | */
18 | boolean runTick();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/Scheduler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | public class Scheduler {
17 | private final List runningThreads = new ArrayList<>();
18 | private ScheduledRunnable runnable;
19 |
20 | public Scheduler(ScheduledRunnable runnable) {
21 | this.runnable = runnable;
22 | }
23 |
24 |
25 | public void run(int threads) {
26 | for (int i = 0; i < threads; i++) {
27 | runningThreads.add(new Thread(() -> {
28 | while (true) {
29 | if (runnable.runTick()) break;
30 | }
31 | }, "Thread-" + i));
32 | }
33 |
34 | runningThreads.forEach(Thread::start);
35 | }
36 |
37 | public void waitFor() {
38 | for (Thread runningThread : runningThreads) {
39 | try {
40 | runningThread.join();
41 | } catch (InterruptedException ignored) {
42 | break;
43 | }
44 | }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/Utils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils;
12 |
13 | import com.google.gson.Gson;
14 | import com.google.gson.GsonBuilder;
15 | import net.superblaubeere27.asmdelta.difference.AbstractDifference;
16 | import net.superblaubeere27.asmdelta.difference.methods.MethodLocalVariableDifference;
17 | import net.superblaubeere27.asmdelta.utils.typeadapter.AbstractDifferenceSerializer;
18 | import net.superblaubeere27.asmdelta.utils.typeadapter.ClassNodeSerializer;
19 | import net.superblaubeere27.asmdelta.utils.typeadapter.MethodLocalVariableDifferenceSerializer;
20 | import net.superblaubeere27.asmdelta.utils.typeadapter.MethodNodeSerializer;
21 | import org.objectweb.asm.tree.ClassNode;
22 | import org.objectweb.asm.tree.InsnList;
23 | import org.objectweb.asm.tree.MethodNode;
24 | import org.objectweb.asm.util.Printer;
25 | import org.objectweb.asm.util.Textifier;
26 | import org.objectweb.asm.util.TraceClassVisitor;
27 | import org.objectweb.asm.util.TraceMethodVisitor;
28 |
29 | import java.io.PrintWriter;
30 | import java.io.StringWriter;
31 |
32 | public class Utils {
33 | public static final Gson GSON;
34 |
35 | static {
36 | GSON = new GsonBuilder()
37 | .registerTypeAdapter(ClassNode.class, new ClassNodeSerializer())
38 | .registerTypeAdapter(MethodNode.class, new MethodNodeSerializer())
39 | .registerTypeAdapter(AbstractDifference.class, new AbstractDifferenceSerializer())
40 | .registerTypeAdapter(MethodLocalVariableDifference.class, new MethodLocalVariableDifferenceSerializer())
41 | .create();
42 | }
43 |
44 | public static String prettyprint(MethodNode insnNode) {
45 | final Printer printer = new Textifier();
46 | TraceMethodVisitor methodPrinter = new TraceMethodVisitor(printer);
47 | insnNode.accept(methodPrinter);
48 | StringWriter sw = new StringWriter();
49 | printer.print(new PrintWriter(sw));
50 | printer.getText().clear();
51 | return sw.toString().trim();
52 | }
53 |
54 | public static String prettyprint(InsnList insnNode) {
55 | final Printer printer = new Textifier();
56 | TraceMethodVisitor methodPrinter = new TraceMethodVisitor(printer);
57 | insnNode.accept(methodPrinter);
58 | StringWriter sw = new StringWriter();
59 | printer.print(new PrintWriter(sw));
60 | printer.getText().clear();
61 | return sw.toString().trim();
62 | }
63 |
64 | public static String prettyprint(ClassNode insnNode) {
65 | StringWriter sw = new StringWriter();
66 | TraceClassVisitor methodPrinter = new TraceClassVisitor(new PrintWriter(sw));
67 | insnNode.accept(methodPrinter);
68 | // printer.print(new PrintWriter(sw));
69 | // printer.getText().clear();
70 | return sw.toString().trim();
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/typeadapter/AbstractDifferenceSerializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils.typeadapter;
12 |
13 | import com.google.gson.*;
14 | import net.superblaubeere27.asmdelta.difference.AbstractDifference;
15 |
16 | import java.lang.reflect.Type;
17 |
18 | public class AbstractDifferenceSerializer implements JsonSerializer, JsonDeserializer {
19 |
20 | private static final String CLASS_META_KEY = "CLASS_META_KEY";
21 |
22 | @Override
23 | public AbstractDifference deserialize(JsonElement jsonElement, Type type,
24 | JsonDeserializationContext jsonDeserializationContext)
25 | throws JsonParseException {
26 | JsonObject jsonObj = jsonElement.getAsJsonObject();
27 | String className = jsonObj.get(CLASS_META_KEY).getAsString();
28 | if (className.equals(MethodLocalVariableDifferenceSerializer.class.getCanonicalName())) {
29 | return (new MethodLocalVariableDifferenceSerializer()).deserialize(jsonElement, type, jsonDeserializationContext);
30 | }
31 | try {
32 | Class> clz = Class.forName(className);
33 | return jsonDeserializationContext.deserialize(jsonElement, clz);
34 | } catch (ClassNotFoundException e) {
35 | throw new JsonParseException(e);
36 | }
37 | }
38 |
39 | @Override
40 | public JsonElement serialize(AbstractDifference object, Type type,
41 | JsonSerializationContext jsonSerializationContext) {
42 | JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
43 | jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
44 | object.getClass().getCanonicalName());
45 | return jsonEle;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/typeadapter/ClassNodeSerializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils.typeadapter;
12 |
13 | import com.google.gson.*;
14 | import net.superblaubeere27.asmdelta.utils.Hex;
15 | import org.objectweb.asm.ClassReader;
16 | import org.objectweb.asm.ClassWriter;
17 | import org.objectweb.asm.tree.ClassNode;
18 |
19 | import java.io.IOException;
20 | import java.lang.reflect.Type;
21 |
22 | public class ClassNodeSerializer implements JsonSerializer, JsonDeserializer {
23 |
24 | @Override
25 | public JsonElement serialize(ClassNode classNode, Type type, JsonSerializationContext jsonSerializationContext) {
26 | ClassWriter classWriter = new ClassWriter(0);
27 |
28 |
29 | classNode.accept(classWriter);
30 |
31 | return new JsonPrimitive(Hex.encodeHexString(classWriter.toByteArray()));
32 | }
33 |
34 | @Override
35 | public ClassNode deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
36 | ClassNode classNode = new ClassNode();
37 |
38 | ClassReader cr;
39 |
40 | try {
41 | cr = new ClassReader(Hex.decodeHex(jsonElement.getAsString()));
42 | } catch (IOException e) {
43 | throw new JsonParseException(e);
44 | }
45 |
46 | cr.accept(classNode, 0);
47 |
48 | return classNode;
49 | }
50 | }
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/typeadapter/MethodLocalVariableDifferenceSerializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils.typeadapter;
12 |
13 | import com.google.gson.*;
14 | import net.superblaubeere27.asmdelta.difference.AbstractDifference;
15 | import net.superblaubeere27.asmdelta.difference.methods.MethodLocalVariableDifference;
16 | import net.superblaubeere27.asmdelta.utils.Hex;
17 | import org.objectweb.asm.ClassReader;
18 | import org.objectweb.asm.ClassWriter;
19 | import org.objectweb.asm.Opcodes;
20 | import org.objectweb.asm.tree.ClassNode;
21 | import org.objectweb.asm.tree.MethodNode;
22 |
23 | import java.io.IOException;
24 | import java.lang.reflect.Type;
25 | import java.util.Collections;
26 | import java.util.Objects;
27 |
28 | public class MethodLocalVariableDifferenceSerializer implements JsonSerializer, JsonDeserializer {
29 |
30 | private static final String CLASS_META_KEY = "CLASS_META_KEY";
31 |
32 | @Override
33 | public JsonElement serialize(MethodLocalVariableDifference methodLocalVariableDifference, java.lang.reflect.Type type, JsonSerializationContext jsonSerializationContext) {
34 | ClassNode classNode = new ClassNode();
35 |
36 | classNode.version = Opcodes.V17;
37 | classNode.access = Opcodes.ACC_PRIVATE;
38 | classNode.name = methodLocalVariableDifference.getClassName();
39 | classNode.signature = null;
40 | classNode.superName = "java/lang/Object";
41 | classNode.interfaces = Collections.emptyList();
42 |
43 | MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, methodLocalVariableDifference.methodName, methodLocalVariableDifference.methodDesc, null, null);
44 | methodNode.localVariables = methodLocalVariableDifference.localVariables;
45 |
46 | methodNode.accept(classNode);
47 |
48 | ClassWriter classWriter = new ClassWriter(0);
49 |
50 |
51 | classNode.accept(classWriter);
52 |
53 | JsonElement ele = new JsonObject();
54 | ele.getAsJsonObject().addProperty("content", Hex.encodeHexString(classWriter.toByteArray()));
55 | ele.getAsJsonObject().addProperty(CLASS_META_KEY,
56 | this.getClass().getCanonicalName());
57 | return ele;
58 | }
59 |
60 | @Override
61 | public MethodLocalVariableDifference deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
62 | ClassNode classNode = new ClassNode();
63 |
64 | ClassReader cr;
65 |
66 | try {
67 | cr = new ClassReader(Hex.decodeHex(jsonElement.getAsJsonObject().get("content").getAsString()));
68 | } catch (IOException e) {
69 | System.err.println("Error while parsing method node");
70 | throw new JsonParseException(e);
71 | }
72 |
73 | cr.accept(classNode, 0);
74 |
75 | if (Objects.requireNonNull(classNode.methods).size() != 1) {
76 | System.err.println("Error while parsing method node");
77 | throw new JsonParseException("Class has more than a method");
78 | }
79 | return new MethodLocalVariableDifference(classNode.name, classNode.methods.get(0).name, classNode.methods.get(0).desc, classNode.methods.get(0).localVariables);
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/net/superblaubeere27/asmdelta/utils/typeadapter/MethodNodeSerializer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2019 superblaubeere27
3 | *
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 | *
6 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 | *
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 | */
10 |
11 | package net.superblaubeere27.asmdelta.utils.typeadapter;
12 |
13 | import com.google.gson.*;
14 | import net.superblaubeere27.asmdelta.utils.Hex;
15 | import org.objectweb.asm.ClassReader;
16 | import org.objectweb.asm.ClassWriter;
17 | import org.objectweb.asm.Opcodes;
18 | import org.objectweb.asm.tree.ClassNode;
19 | import org.objectweb.asm.tree.MethodNode;
20 |
21 | import java.io.IOException;
22 | import java.lang.reflect.Type;
23 | import java.util.Collections;
24 | import java.util.Objects;
25 |
26 | public class MethodNodeSerializer implements JsonSerializer, JsonDeserializer {
27 |
28 | @Override
29 | public JsonElement serialize(MethodNode methodNode, java.lang.reflect.Type type, JsonSerializationContext jsonSerializationContext) {
30 | ClassNode classNode = new ClassNode();
31 |
32 | classNode.version = Opcodes.V17;
33 | classNode.access = Opcodes.ACC_PRIVATE;
34 | classNode.name = "asdf";
35 | classNode.signature = null;
36 | classNode.superName = "java/lang/Object";
37 | classNode.interfaces = Collections.emptyList();
38 |
39 | methodNode.accept(classNode);
40 |
41 | ClassWriter classWriter = new ClassWriter(0);
42 |
43 |
44 | classNode.accept(classWriter);
45 |
46 | return new JsonPrimitive(Hex.encodeHexString(classWriter.toByteArray()));
47 | }
48 |
49 | @Override
50 | public MethodNode deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
51 | ClassNode classNode = new ClassNode();
52 |
53 | ClassReader cr;
54 |
55 | try {
56 | cr = new ClassReader(Hex.decodeHex(jsonElement.getAsString()));
57 | } catch (IOException e) {
58 | System.err.println("Error while parsing method node");
59 | throw new JsonParseException(e);
60 | }
61 |
62 | cr.accept(classNode, 0);
63 |
64 | if (Objects.requireNonNull(classNode.methods).size() != 1) {
65 | System.err.println("Error while parsing method node");
66 | throw new JsonParseException("Class has more than a method");
67 | }
68 |
69 | return classNode.methods.get(0);
70 | }
71 | }
--------------------------------------------------------------------------------
/src/main/resources/cursedbtw.mixins.json:
--------------------------------------------------------------------------------
1 | {
2 | "required": true,
3 | "minVersion": "0.8",
4 | "package": "btw.community.fabric.mixin",
5 | "compatibilityLevel": "JAVA_17",
6 | "mixins": [
7 | "MinecraftServerMixin"
8 | ],
9 | "client": [
10 | "MinecraftMixin",
11 | "NetClientHandlerMixin"
12 | ],
13 | "injectors": {
14 | "defaultRequire": 1
15 | },
16 | "plugin": "net.devtech.grossfabrichacks.mixin.GrossFabricHacksPlugin"
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/resources/fabric.mod.json:
--------------------------------------------------------------------------------
1 | {
2 | "schemaVersion": 1,
3 | "id": "btw",
4 | "name": "Better Than Wolves CE",
5 | "version": "3.0.0 Beta Snapshot 3",
6 | "environment": "*",
7 | "description": "This is a continuation of FlowerChild's Better than Wolves total conversion Minecraft mod.",
8 | "contact": {
9 | "issues": "https://github.com/BTW-Community/BTW-Public/issues",
10 | "sources": "https://github.com/BTW-Community/BTW-Public"
11 | },
12 | "authors": [
13 | "FlowerChild",
14 | "Better than Wolves Community"
15 | ],
16 | "license": "Creative Commons Attribution 4.0 International",
17 | "icon": "btw_logo.png",
18 | "entrypoints": {
19 | "init": [
20 | "btw.community.fabric.BTWFabricMod"
21 | ],
22 | "gfh:prePreLaunch": [
23 | "btw.community.fabric.BTWFabricMod"
24 | ],
25 | "btw:addon": [
26 | "btw.BTWMod",
27 | "emi.dev.emi.emi.EMIPostInit"
28 | ],
29 | "emi": [
30 | "emi.dev.emi.emi.api.plugin.VanillaPlugin",
31 | "emi.dev.emi.emi.api.plugin.BTWPlugin"
32 | ]
33 | },
34 | "mixins": [
35 | "cursedbtw.mixins.json"
36 | ],
37 |
38 | "depends": {
39 | "fabricloader": ">=0.7.4"
40 | },
41 | "suggests": {
42 | "flamingo": "*"
43 | },
44 | "custom": {
45 | "btw:addon_prefix": "BTW"
46 | }
47 | }
--------------------------------------------------------------------------------