Commit 3340467d961b639381483255b3d01009a21aee66
1 parent
00d2ffc1
separating event proxy generation to improve resilience against bad transformers
Showing
4 changed files
with
95 additions
and
67 deletions
java/client/com/mumfrey/liteloader/client/api/LiteLoaderCoreAPIClient.java
| ... | ... | @@ -22,9 +22,10 @@ import com.mumfrey.liteloader.interfaces.ObjectFactory; |
| 22 | 22 | */ |
| 23 | 23 | public class LiteLoaderCoreAPIClient extends LiteLoaderCoreAPI |
| 24 | 24 | { |
| 25 | - private static final String PKG_LITELOADER_CLIENT = LiteLoaderCoreAPI.PKG_LITELOADER + ".client"; | |
| 25 | + private static final String PKG_LITELOADER_CLIENT = LiteLoaderCoreAPI.PKG_LITELOADER + ".client"; | |
| 26 | 26 | |
| 27 | 27 | private static final String[] requiredTransformers = { |
| 28 | + LiteLoaderCoreAPI.PKG_LITELOADER + ".transformers.event.EventProxyTransformer", | |
| 28 | 29 | LiteLoaderCoreAPI.PKG_LITELOADER + ".launch.LiteLoaderTransformer", |
| 29 | 30 | LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.CrashReportTransformer" |
| 30 | 31 | }; | ... | ... |
java/common/com/mumfrey/liteloader/launch/RealmsJsonUpdateThread.java
| ... | ... | @@ -106,11 +106,7 @@ public class RealmsJsonUpdateThread extends Thread |
| 106 | 106 | |
| 107 | 107 | private boolean writeLocalVersionJson(Map<String, ?> localJson) |
| 108 | 108 | { |
| 109 | - File versionDir = new File(this.versionsDir, this.version); | |
| 110 | - if (!versionDir.exists() || !versionDir.isDirectory()) return false; | |
| 111 | - | |
| 112 | - File versionJsonFile = new File(versionDir, this.version + ".json"); | |
| 113 | - | |
| 109 | + File versionJsonFile = this.getLocalVersionJsonFile(); | |
| 114 | 110 | FileWriter writer = null; |
| 115 | 111 | |
| 116 | 112 | try |
| ... | ... | @@ -227,11 +223,8 @@ public class RealmsJsonUpdateThread extends Thread |
| 227 | 223 | @SuppressWarnings("unchecked") |
| 228 | 224 | private Map<String, ?> getLocalVersionJson() |
| 229 | 225 | { |
| 230 | - File versionDir = new File(this.versionsDir, this.version); | |
| 231 | - if (!versionDir.exists() || !versionDir.isDirectory()) return null; | |
| 232 | - | |
| 233 | - File versionJsonFile = new File(versionDir, this.version + ".json"); | |
| 234 | - if (!versionJsonFile.exists()) return null; | |
| 226 | + File versionJsonFile = this.getLocalVersionJsonFile(); | |
| 227 | + if (versionJsonFile == null || !versionJsonFile.exists()) return null; | |
| 235 | 228 | |
| 236 | 229 | FileReader reader = null; |
| 237 | 230 | |
| ... | ... | @@ -254,13 +247,22 @@ public class RealmsJsonUpdateThread extends Thread |
| 254 | 247 | |
| 255 | 248 | private boolean isLocalJsonUpToDate() |
| 256 | 249 | { |
| 257 | - File versionDir = new File(this.versionsDir, this.version); | |
| 258 | - if (!versionDir.exists() || !versionDir.isDirectory()) return false; | |
| 259 | - | |
| 260 | - File versionJsonFile = new File(versionDir, this.version + ".json"); | |
| 261 | - if (!versionJsonFile.exists()) return false; | |
| 250 | + File versionJsonFile = this.getLocalVersionJsonFile(); | |
| 251 | + if (versionJsonFile == null || !versionJsonFile.exists()) return false; | |
| 262 | 252 | |
| 263 | 253 | long deltaTime = System.currentTimeMillis() - versionJsonFile.lastModified(); |
| 264 | 254 | return deltaTime < 86400000; |
| 265 | 255 | } |
| 256 | + | |
| 257 | + /** | |
| 258 | + * @return | |
| 259 | + */ | |
| 260 | + private File getLocalVersionJsonFile() | |
| 261 | + { | |
| 262 | + File versionDir = new File(this.versionsDir, this.version); | |
| 263 | + if (!versionDir.exists() || !versionDir.isDirectory()) return null; | |
| 264 | + | |
| 265 | + File versionJsonFile = new File(versionDir, this.version + ".json"); | |
| 266 | + return versionJsonFile; | |
| 267 | + } | |
| 266 | 268 | } | ... | ... |
java/common/com/mumfrey/liteloader/transformers/event/EventInjectionTransformer.java
| ... | ... | @@ -10,14 +10,11 @@ import java.util.Set; |
| 10 | 10 | import java.util.TreeSet; |
| 11 | 11 | |
| 12 | 12 | import org.objectweb.asm.ClassWriter; |
| 13 | -import org.objectweb.asm.Opcodes; | |
| 14 | 13 | import org.objectweb.asm.tree.AbstractInsnNode; |
| 15 | 14 | import org.objectweb.asm.tree.ClassNode; |
| 16 | -import org.objectweb.asm.tree.InsnNode; | |
| 17 | 15 | import org.objectweb.asm.tree.MethodNode; |
| 18 | 16 | import org.objectweb.asm.util.CheckClassAdapter; |
| 19 | 17 | |
| 20 | -import com.mumfrey.liteloader.core.runtime.Obf; | |
| 21 | 18 | import com.mumfrey.liteloader.transformers.ClassTransformer; |
| 22 | 19 | import com.mumfrey.liteloader.util.log.LiteLoaderLogger; |
| 23 | 20 | |
| ... | ... | @@ -59,7 +56,7 @@ public abstract class EventInjectionTransformer extends ClassTransformer |
| 59 | 56 | /** |
| 60 | 57 | * Multiple event injection transformers may exist but to allow co-operation the events themselves are registered |
| 61 | 58 | * statically. The first EventInjectionTransformer instance to be created becomes the "master" and is actually responsible |
| 62 | - * for injecting the events and transforming the EventProxy class. | |
| 59 | + * for injecting the events | |
| 63 | 60 | */ |
| 64 | 61 | private static EventInjectionTransformer master; |
| 65 | 62 | |
| ... | ... | @@ -156,23 +153,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer |
| 156 | 153 | { |
| 157 | 154 | if (EventInjectionTransformer.master == this) |
| 158 | 155 | { |
| 159 | - if (transformedName != null && transformedName.startsWith(Obf.EventProxy.name)) | |
| 160 | - { | |
| 161 | - int dollarPos = transformedName.indexOf('$'); | |
| 162 | - int proxyIndex = (dollarPos > -1) ? Integer.parseInt(transformedName.substring(dollarPos + 1)) : 0; | |
| 163 | - if (proxyIndex != 1) | |
| 164 | - { | |
| 165 | - try | |
| 166 | - { | |
| 167 | - return this.transformEventProxy(transformedName, basicClass, proxyIndex); | |
| 168 | - } | |
| 169 | - catch (Throwable th) | |
| 170 | - { | |
| 171 | - th.printStackTrace(); | |
| 172 | - } | |
| 173 | - } | |
| 174 | - } | |
| 175 | - | |
| 176 | 156 | if (basicClass != null && EventInjectionTransformer.eventMappings.containsKey(transformedName)) |
| 177 | 157 | { |
| 178 | 158 | return this.injectEvents(basicClass, EventInjectionTransformer.eventMappings.get(transformedName)); |
| ... | ... | @@ -182,36 +162,6 @@ public abstract class EventInjectionTransformer extends ClassTransformer |
| 182 | 162 | return basicClass; |
| 183 | 163 | } |
| 184 | 164 | |
| 185 | - private byte[] transformEventProxy(String transformedName, byte[] basicClass, int proxyIndex) | |
| 186 | - { | |
| 187 | - ClassNode classNode = this.getProxyByteCode(transformedName, basicClass, proxyIndex); | |
| 188 | - return this.writeClass(Event.populateProxy(classNode, proxyIndex == 0 ? 1 : proxyIndex)); | |
| 189 | - } | |
| 190 | - | |
| 191 | - private ClassNode getProxyByteCode(String transformedName, byte[] basicClass, int proxyIndex) | |
| 192 | - { | |
| 193 | - if (proxyIndex == 0 || basicClass != null) | |
| 194 | - { | |
| 195 | - ClassNode classNode = this.readClass(basicClass, true); | |
| 196 | - | |
| 197 | - for (MethodNode method : classNode.methods) | |
| 198 | - { | |
| 199 | - // Strip the sanity code out of the EventProxy class initialiser | |
| 200 | - if ("<clinit>".equals(method.name)) | |
| 201 | - { | |
| 202 | - method.instructions.clear(); | |
| 203 | - method.instructions.add(new InsnNode(Opcodes.RETURN)); | |
| 204 | - } | |
| 205 | - } | |
| 206 | - | |
| 207 | - return classNode; | |
| 208 | - } | |
| 209 | - | |
| 210 | - ClassNode classNode = new ClassNode(); | |
| 211 | - classNode.visit(50, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, transformedName.replace('.', '/'), null, "java/lang/Object", null); | |
| 212 | - return classNode; | |
| 213 | - } | |
| 214 | - | |
| 215 | 165 | private byte[] injectEvents(byte[] basicClass, Map<String, Map<Event, InjectionPoint>> mappings) |
| 216 | 166 | { |
| 217 | 167 | if (mappings == null) return basicClass; | ... | ... |
java/common/com/mumfrey/liteloader/transformers/event/EventProxyTransformer.java
0 → 100644
| 1 | +package com.mumfrey.liteloader.transformers.event; | |
| 2 | + | |
| 3 | +import org.objectweb.asm.Opcodes; | |
| 4 | +import org.objectweb.asm.tree.ClassNode; | |
| 5 | +import org.objectweb.asm.tree.InsnNode; | |
| 6 | +import org.objectweb.asm.tree.MethodNode; | |
| 7 | + | |
| 8 | +import com.mumfrey.liteloader.core.runtime.Obf; | |
| 9 | +import com.mumfrey.liteloader.transformers.ClassTransformer; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * Transformer responsible for transforming/generating the EventProxy inner classes, separated from the Event Transformer | |
| 13 | + * itself so that we can place it higher up the tranformer chain to avoid broken mod transformers screwing things up. | |
| 14 | + * | |
| 15 | + * @author Adam Mummery-Smith | |
| 16 | + */ | |
| 17 | +public class EventProxyTransformer extends ClassTransformer | |
| 18 | +{ | |
| 19 | + public EventProxyTransformer() | |
| 20 | + { | |
| 21 | + } | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public byte[] transform(String name, String transformedName, byte[] basicClass) | |
| 25 | + { | |
| 26 | + if (transformedName != null && transformedName.startsWith(Obf.EventProxy.name)) | |
| 27 | + { | |
| 28 | + int dollarPos = transformedName.indexOf('$'); | |
| 29 | + int proxyIndex = (dollarPos > -1) ? Integer.parseInt(transformedName.substring(dollarPos + 1)) : 0; | |
| 30 | + if (proxyIndex != 1) | |
| 31 | + { | |
| 32 | + try | |
| 33 | + { | |
| 34 | + return this.transformEventProxy(transformedName, basicClass, proxyIndex); | |
| 35 | + } | |
| 36 | + catch (Throwable th) | |
| 37 | + { | |
| 38 | + th.printStackTrace(); | |
| 39 | + } | |
| 40 | + } | |
| 41 | + } | |
| 42 | + | |
| 43 | + return basicClass; | |
| 44 | + } | |
| 45 | + | |
| 46 | + private byte[] transformEventProxy(String transformedName, byte[] basicClass, int proxyIndex) | |
| 47 | + { | |
| 48 | + ClassNode classNode = this.getProxyByteCode(transformedName, basicClass, proxyIndex); | |
| 49 | + return this.writeClass(Event.populateProxy(classNode, proxyIndex == 0 ? 1 : proxyIndex)); | |
| 50 | + } | |
| 51 | + | |
| 52 | + private ClassNode getProxyByteCode(String transformedName, byte[] basicClass, int proxyIndex) | |
| 53 | + { | |
| 54 | + if (proxyIndex == 0 || basicClass != null) | |
| 55 | + { | |
| 56 | + ClassNode classNode = this.readClass(basicClass, true); | |
| 57 | + | |
| 58 | + for (MethodNode method : classNode.methods) | |
| 59 | + { | |
| 60 | + // Strip the sanity code out of the EventProxy class initialiser | |
| 61 | + if ("<clinit>".equals(method.name)) | |
| 62 | + { | |
| 63 | + method.instructions.clear(); | |
| 64 | + method.instructions.add(new InsnNode(Opcodes.RETURN)); | |
| 65 | + } | |
| 66 | + } | |
| 67 | + | |
| 68 | + return classNode; | |
| 69 | + } | |
| 70 | + | |
| 71 | + ClassNode classNode = new ClassNode(); | |
| 72 | + classNode.visit(50, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, transformedName.replace('.', '/'), null, "java/lang/Object", null); | |
| 73 | + return classNode; | |
| 74 | + } | |
| 75 | +} | ... | ... |