Preparing junit tests
This commit is contained in:
parent
6cfbaf91de
commit
e693b7254a
17 changed files with 112 additions and 50 deletions
13
build.gradle
13
build.gradle
|
@ -1,6 +1,5 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'eclipse'
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
|
@ -21,13 +20,23 @@ group = 'org.mcphackers'
|
|||
archivesBaseName = 'launchwrapper'
|
||||
version = '1.0-SNAPSHOT'
|
||||
sourceCompatibility = 1.5
|
||||
targetCompatibility = 1.5
|
||||
|
||||
dependencies {
|
||||
implementation 'org.mcphackers.rdi:rdi:1.0'
|
||||
implementation 'org.ow2.asm:asm:9.3'
|
||||
implementation 'org.ow2.asm:asm-tree:9.3'
|
||||
implementation 'org.json:json:20230311'
|
||||
// implementation name: 'discord-rpc-1.6.2'
|
||||
// I'll bring discord RPC support later, when I have an environment to compile natives
|
||||
|
||||
testCompileOnly 'junit:junit:4.12'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.0.0'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
workingDir = "build"
|
||||
testLogging.showStandardStreams = true
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
|
|
|
@ -6,6 +6,10 @@ import java.awt.Image;
|
|||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
import org.mcphackers.launchwrapper.tweak.AppletWrapper;
|
||||
|
||||
/**
|
||||
* Runs an applet
|
||||
* (For example net.minecraft.client.MinecraftApplet)
|
||||
*/
|
||||
public class AppletLaunchTarget extends LaunchTarget {
|
||||
|
||||
private final String targetClass;
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
package org.mcphackers.launchwrapper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
import org.mcphackers.launchwrapper.tweak.Tweak;
|
||||
|
||||
public class Launch {
|
||||
|
||||
/**
|
||||
* Class loader where overwritten classes are stored
|
||||
* Class loader where overwritten classes will be stored
|
||||
*/
|
||||
public static final LaunchClassLoader CLASS_LOADER = LaunchClassLoader.instantiate();
|
||||
static {
|
||||
|
@ -36,7 +34,6 @@ public class Launch {
|
|||
}
|
||||
|
||||
public void launch() {
|
||||
Launch.CLASS_LOADER.setDebugOutput(new File(config.gameDir.get(), "debug"));
|
||||
Tweak mainTweak = Tweak.get(CLASS_LOADER, config);
|
||||
if(mainTweak == null) {
|
||||
System.err.println("Could not find launch target");
|
||||
|
@ -46,6 +43,7 @@ public class Launch {
|
|||
if(config.discordRPC.get()) {
|
||||
setupDiscordRPC();
|
||||
}
|
||||
mainTweak.clear(); // Clearing some garbage
|
||||
mainTweak.getLaunchTarget().launch(CLASS_LOADER);
|
||||
} else {
|
||||
System.err.println("Tweak could not be applied");
|
||||
|
@ -53,38 +51,7 @@ public class Launch {
|
|||
}
|
||||
|
||||
protected void setupDiscordRPC() {
|
||||
// String applicationId = "356875570916753438";
|
||||
// DiscordEventHandlers handlers = new DiscordEventHandlersAdapter() {};
|
||||
// DiscordRPC.discordInitialize(applicationId, handlers, true);
|
||||
// DiscordRichPresence presence = new DiscordRichPresence();
|
||||
// if(config.version.get() != null) {
|
||||
// presence.state = "Version: " + config.version.get();
|
||||
// }
|
||||
// if(config.username.get() != null) {
|
||||
// presence.details = "Username: " + config.username.get();
|
||||
// }
|
||||
// presence.startTimestamp = System.currentTimeMillis() / 1000;
|
||||
// presence.largeImageKey = "https://cdn.discordapp.com/app-icons/356875570916753438/166fbad351ecdd02d11a3b464748f66b.png?size=256";
|
||||
// DiscordRPC.discordUpdatePresence(presence);
|
||||
// final Thread thread =
|
||||
// new Thread("Discord RPC") {
|
||||
// public void run() {
|
||||
// while(true) {
|
||||
// DiscordRPC.discordRunCallbacks();
|
||||
// try {
|
||||
// Thread.sleep(2000);
|
||||
// } catch (InterruptedException e) {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
// public void run() {
|
||||
// DiscordRPC.discordShutdown();
|
||||
// thread.interrupt();
|
||||
// }
|
||||
// });
|
||||
// thread.start();
|
||||
// TODO
|
||||
}
|
||||
|
||||
public static Launch getInstance() {
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.mcphackers.launchwrapper.util.OS;
|
|||
|
||||
public class LaunchConfig {
|
||||
private static final File defaultGameDir = getDefaultGameDir();
|
||||
//TODO allow arbitary parameters instead of the ones documented below
|
||||
private Map<String, LaunchParameter<?>> parameters = new HashMap<String, LaunchParameter<?>>();
|
||||
|
||||
public LaunchParameterSwitch demo = new LaunchParameterSwitch("demo", false);
|
||||
|
|
|
@ -2,6 +2,9 @@ package org.mcphackers.launchwrapper;
|
|||
|
||||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
|
||||
/**
|
||||
* Different types of entry point (main method, applet, etc)
|
||||
*/
|
||||
public abstract class LaunchTarget {
|
||||
|
||||
public abstract void launch(LaunchClassLoader classLoader);
|
||||
|
|
|
@ -2,6 +2,10 @@ package org.mcphackers.launchwrapper;
|
|||
|
||||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
|
||||
/**
|
||||
* Invokes MainClass.main(String[] args)
|
||||
* (For example net.minecraft.client.main.Main)
|
||||
*/
|
||||
public class MainLaunchTarget extends LaunchTarget {
|
||||
|
||||
public String targetClass;
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.mcphackers.launchwrapper.util.Util;
|
|||
/**
|
||||
* DO NOT use this class under any circumstances. This class is meant to be
|
||||
* initialized in the context of LaunchClassLoader
|
||||
* This class contains methods which are used in different game classes, sort of like mixins
|
||||
*
|
||||
* @author Lassebq
|
||||
*
|
||||
|
|
|
@ -39,6 +39,7 @@ public class SaveLevelURLConnection extends HttpURLConnection {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unused")
|
||||
public InputStream getInputStream() throws IOException {
|
||||
Exception exception = null;
|
||||
try {
|
||||
|
|
|
@ -4,5 +4,10 @@ import org.objectweb.asm.tree.ClassNode;
|
|||
|
||||
public abstract class ClassLoaderTweak {
|
||||
|
||||
/**
|
||||
* Called on every class node loaded by LaunchClassLoader
|
||||
* @param node
|
||||
* @return true if the given ClassNode was modified
|
||||
*/
|
||||
public abstract boolean tweakClass(ClassNode node);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package org.mcphackers.launchwrapper.tweak;
|
||||
|
||||
/**
|
||||
* Info about features applied by a tweak
|
||||
* Useful for tests
|
||||
*/
|
||||
public class FeatureInfo {
|
||||
public final String feature;
|
||||
public String[] info;
|
||||
|
||||
public FeatureInfo(String name) {
|
||||
feature = name;
|
||||
}
|
||||
|
||||
public FeatureInfo(String name, String[] additionalInfo) {
|
||||
feature = name;
|
||||
info = additionalInfo;
|
||||
}
|
||||
}
|
|
@ -13,10 +13,15 @@ import org.objectweb.asm.tree.LabelNode;
|
|||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
/**
|
||||
* Compatibility fixes for Java 5
|
||||
* Replaces most of Java 6 API used by Minecraft with Java 5 alternative
|
||||
*/
|
||||
public class LegacyClassLoaderTweak extends ClassLoaderTweak {
|
||||
|
||||
public boolean tweakClass(ClassNode node) {
|
||||
boolean changed = false;
|
||||
// Decrease class version
|
||||
if(node.version > LaunchClassLoader.CLASS_VERSION) {
|
||||
node.version = LaunchClassLoader.CLASS_VERSION;
|
||||
changed = true;
|
||||
|
@ -25,6 +30,7 @@ public class LegacyClassLoaderTweak extends ClassLoaderTweak {
|
|||
AbstractInsnNode insn = m.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fill(insn, 3);
|
||||
// Replace String.isEmpty() with String.length == 0
|
||||
if(compareInsn(insns[0], INVOKEVIRTUAL, "java/lang/String", "isEmpty", "()Z")) {
|
||||
MethodInsnNode invoke = new MethodInsnNode(INVOKEVIRTUAL, "java/lang/String", "length", "()I");
|
||||
m.instructions.set(insns[0], invoke);
|
||||
|
@ -42,6 +48,7 @@ public class LegacyClassLoaderTweak extends ClassLoaderTweak {
|
|||
changed = true;
|
||||
continue;
|
||||
}
|
||||
// Replace String.getBytes(Charset.forName(charset)) with String.getBytes(charset)
|
||||
if(compareInsn(insns[1], INVOKESTATIC, "java/nio/charset/Charset", "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;")
|
||||
&& compareInsn(insns[2], INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/nio/charset/Charset;)[B")
|
||||
&& compareInsn(insns[0], LDC)) {
|
||||
|
@ -49,6 +56,7 @@ public class LegacyClassLoaderTweak extends ClassLoaderTweak {
|
|||
m.instructions.remove(insns[1]);
|
||||
changed = true;
|
||||
}
|
||||
// Same thing but for new String()
|
||||
if(compareInsn(insns[1], INVOKESTATIC, "java/nio/charset/Charset", "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;")
|
||||
&& compareInsn(insns[2], INVOKESPECIAL, "java/lang/String", "<init>", "([BLjava/nio/charset/Charset;)V")
|
||||
&& compareInsn(insns[0], LDC)) {
|
||||
|
|
|
@ -553,7 +553,7 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
|
||||
if(!foundTitle && launch.title.get() != null) {
|
||||
//TODO
|
||||
//TODO figure out where to insert title
|
||||
}
|
||||
|
||||
if(afterLabel != null
|
||||
|
@ -936,7 +936,7 @@ public class LegacyTweak extends Tweak {
|
|||
}
|
||||
}
|
||||
}
|
||||
tweakInfo("MouseHelper fixed in " + (System.currentTimeMillis() - i) + " ms");
|
||||
tweakInfo("MouseHelper fix", (System.currentTimeMillis() - i) + " ms");
|
||||
source.overrideClass(mouseHelper);
|
||||
}
|
||||
|
||||
|
@ -987,7 +987,7 @@ public class LegacyTweak extends Tweak {
|
|||
&& containsInvoke(m.instructions, new MethodInsnNode(INVOKESTATIC, "org/lwjgl/input/Keyboard", "destroy", "()V"))
|
||||
&& containsInvoke(m.instructions, new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "destroy", "()V"))) {
|
||||
destroy = m;
|
||||
tweakInfo(destroy.name + destroy.desc + " is the destroy() method");
|
||||
tweakInfo("destroy()", destroy.name + destroy.desc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1048,7 +1048,7 @@ public class LegacyTweak extends Tweak {
|
|||
MethodInsnNode invoke = (MethodInsnNode) insns2[2];
|
||||
if(Type.getReturnType(invoke.desc).getSort() == Type.VOID) {
|
||||
addTryCatch(destroy, insns2[0], insns2[2], "java/lang/Throwable");
|
||||
tweakInfo("Fixed sound manager shutdown (b1.0 - b1.3)");
|
||||
tweakInfo("SoundManager shutdown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1085,7 +1085,7 @@ public class LegacyTweak extends Tweak {
|
|||
insn = insn.getPrevious();
|
||||
}
|
||||
if(lbl2 != null) {
|
||||
tweakInfo("Indev launch tweak");
|
||||
tweakInfo("Indev launch");
|
||||
removeRange(setLevel.instructions, handler.start.getNext(), lbl2);
|
||||
setLevel.tryCatchBlocks.remove(handler);
|
||||
}
|
||||
|
@ -1323,6 +1323,7 @@ public class LegacyTweak extends Tweak {
|
|||
&& compareInsn(insns3[1], LDC, "DemoUser")
|
||||
&& compareInsn(insns3[2], LDC, "n/a")
|
||||
&& compareInsn(insns3[3], INVOKESPECIAL, node.superName, "<init>", "(Ljava/lang/String;Ljava/lang/String;)V")) {
|
||||
tweakInfo("DemoUser");
|
||||
InsnList insert = new InsnList();
|
||||
insert.add(new LdcInsnNode(launch.username.get()));
|
||||
insert.add(new LdcInsnNode(launch.sessionid.get()));
|
||||
|
@ -1359,6 +1360,7 @@ public class LegacyTweak extends Tweak {
|
|||
insert.add(new JumpInsnNode(IFNULL, label));
|
||||
init.instructions.insertBefore(insns2[0], insert);
|
||||
init.instructions.insert(insns2[4], label);
|
||||
tweakInfo("Custom server fix");
|
||||
}
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package org.mcphackers.launchwrapper.tweak;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mcphackers.launchwrapper.LaunchConfig;
|
||||
import org.mcphackers.launchwrapper.LaunchTarget;
|
||||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
|
@ -7,16 +10,25 @@ import org.mcphackers.launchwrapper.util.ClassNodeSource;
|
|||
|
||||
public abstract class Tweak {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
protected ClassNodeSource source;
|
||||
protected LaunchConfig launch;
|
||||
private List<FeatureInfo> features = new ArrayList<FeatureInfo>();
|
||||
|
||||
/**
|
||||
* Every tweak must implement this constructor
|
||||
* Overloads are not supported!!!
|
||||
* @param source
|
||||
* @param launch
|
||||
*/
|
||||
public Tweak(ClassNodeSource source, LaunchConfig launch) {
|
||||
this.source = source;
|
||||
this.launch = launch;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does return true even if some of the changes weren't applied, even when they should've been
|
||||
* @return true if given ClassNodeSource was modified without fatal errors
|
||||
*/
|
||||
public abstract boolean transform();
|
||||
|
||||
public abstract ClassLoaderTweak getLoaderTweak();
|
||||
|
@ -34,6 +46,7 @@ public abstract class Tweak {
|
|||
private static Tweak getTweak(LaunchClassLoader classLoader, LaunchConfig launch) {
|
||||
if(launch.tweakClass.get() != null) {
|
||||
try {
|
||||
// Instantiate custom tweak if it's present on classpath;
|
||||
return (Tweak)Class.forName(launch.tweakClass.get())
|
||||
.getConstructor(ClassNodeSource.class, LaunchConfig.class)
|
||||
.newInstance(classLoader, launch);
|
||||
|
@ -41,6 +54,7 @@ public abstract class Tweak {
|
|||
return null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if(launch.isom.get()) {
|
||||
|
@ -62,8 +76,11 @@ public abstract class Tweak {
|
|||
return null; // Tweak not found
|
||||
}
|
||||
|
||||
protected void tweakInfo(String msg) {
|
||||
if(DEBUG)
|
||||
System.out.println("TWEAK: " + msg);
|
||||
protected void tweakInfo(String name, String... extra) {
|
||||
features.add(new FeatureInfo(name));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
features.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class VanillaTweak extends Tweak {
|
|||
MethodInsnNode invoke = (MethodInsnNode) insn;
|
||||
minecraft = source.getClass(invoke.owner);
|
||||
run = NodeHelper.getMethod(minecraft, invoke.name, invoke.desc);
|
||||
tweakInfo(minecraft.name + "." + invoke.name + invoke.desc + " is Minecraft.run()");
|
||||
tweakInfo("Minecraft.run()", minecraft.name + "." + invoke.name + invoke.desc);
|
||||
break;
|
||||
}
|
||||
insn = previousInsn(insn);
|
||||
|
@ -100,7 +100,7 @@ public class VanillaTweak extends Tweak {
|
|||
LdcInsnNode ldc = (LdcInsnNode) insn;
|
||||
if(ldc.cst instanceof String) {
|
||||
if(launch.title.get() != null) {
|
||||
tweakInfo("Replaced title");
|
||||
tweakInfo("Replaced title", launch.title.get());
|
||||
ldc.cst = launch.title.get();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public class InsnHelper {
|
|||
return insn;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static boolean compareInsn(AbstractInsnNode insn, int opcode, Object... compare) {
|
||||
if(insn == null) {
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ClassicTest extends TweakTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new File(".").getAbsolutePath());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.mcphackers.launchwrapper.test;
|
||||
|
||||
public abstract class TweakTest {
|
||||
|
||||
public void testFramePatch() {
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue