Unfinished URLClassLoader

This commit is contained in:
Lassebq 2023-03-19 22:30:39 +02:00
parent 1ec1b3daf1
commit b7ba767175
No known key found for this signature in database
GPG key ID: DE0866BB0C980B6E
15 changed files with 310 additions and 85 deletions

View file

@ -6,14 +6,16 @@ LaunchWrapper is bundled in [BetterJSONs](https://github.com/MCPHackers/BetterJS
# Features
- Strips game window from Java **AWT** (**Abstract Window Toolkit**) and lets the game use internal **LWJGL** frame
- BitDepthFix for versions before Beta 1.8
- Allows changing assets directory in 1.6 snapshots (the game didn't have a parameter to do that yet)
- Allows changing game directory in versions before 1.6
- Replaces mouse input code with **LWJGL** calls
- Fixes TimSort crash when using java 8+
- Fixes TimSort crash when using Java 8+
- Adds ability to customize built-in **LWJGL** frame
- Changing display title
- Setting icon
- Proxies all requests from old skin servers to the current skin API and converts skins to required format
- Skins don't work in Java versions before 8u181, due to the requrement of TLS 1.2 support
- Uses Betacraft proxy to download sounds for versions before 1.6
- Adds ability to launch classic and pre-classic at custom resolution and fullscreen
- Makes save slots in classic and indev functional and saves to `.minecraft/levels` directory
@ -21,11 +23,13 @@ LaunchWrapper is bundled in [BetterJSONs](https://github.com/MCPHackers/BetterJS
- A VSync toggle (Used to prevent extreme framerate in early versions which causes **coil whine**)
- Does not depend on any hard-coded obfuscated names and is mostly compatible with every Minecraft version
- This also includes modded versions
- A parameter to download `minecraft_server.jar` for snapshots which require it: `12w18a`, `12w19a`, `12w21a`
- The wrapper is fully compatible with java 5+ if the game is vanilla
- A parameter to automatically download `minecraft_server.jar` for snapshots: `12w18a`, `12w19a`, `12w21a`
- The wrapper is fully compatible with Java 5+ if the game is vanilla
- The wrapper also fixes Beta 1.3, Pre-classic and Classic compatibility with Java 5
- Built-in [Modloader Fix](https://github.com/coffeenotfound/ModloaderFix-b1.7.3)
# How to use
*This is a more in-depth guide for people experienced in Java*
*This is a more in-depth guide for those who will be using the wrapper*
Make sure all minecraft and wrapper libraries are on classpath<br>
Use `java -cp <classpath> org.mcphackers.launchwrapper.Launch <arguments>` to launch the game
@ -38,7 +42,8 @@ Arguments may be as follows:
- `isom` - Launch IsomPreviewApplet
- `forceVsync` - Launch the game with VSync enabled
- `forceResizable` - Early Indev and Classic don't properly update viewport, so the wrapper disables frame resizing. To enable it anyway use this argument
- `skinProxy` - **classic** / **pre-b1.9-pre4** / **pre-1.8** / **default** - convert the skin to one of these specified formats
- `skinProxy` - **pre-c0.0.19a** / **classic** / **pre-b1.9-pre4** / **pre-1.8** / **default** - convert the skin to one of these specified formats
- **pre-c0.0.19a** - flatten all skin layers, flip bottom textures, mirror entire skin and crop to 64x32
- **classic** - flatten all skin layers, flip bottom textures and crop to 64x32
- **pre-b1.9-pre4** - flip bottom textures and crop to 64x32
- **pre-1.8** - crop to 64x32

View file

@ -13,8 +13,7 @@ public class AppletLaunchTarget extends LaunchTarget {
private int width = 200, height = 200;
private Image icon;
public AppletLaunchTarget(LaunchClassLoader classLoader, String classTarget) {
super(classLoader);
public AppletLaunchTarget(String classTarget) {
targetClass = classTarget;
title = classTarget;
}
@ -32,7 +31,7 @@ public class AppletLaunchTarget extends LaunchTarget {
icon = img;
}
public void launch() {
public void launch(LaunchClassLoader classLoader) {
Class<? extends Applet> appletClass;
try {
appletClass = classLoader.findClass(targetClass).asSubclass(Applet.class);

View file

@ -34,7 +34,9 @@ public class Launch {
return;
}
if(mainTweak.transform()) {
mainTweak.getLaunchTarget(CLASS_LOADER).launch();
mainTweak.getLaunchTarget().launch(CLASS_LOADER);
} else {
System.err.println("Tweak could not be applied");
}
}

View file

@ -4,11 +4,5 @@ import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
public abstract class LaunchTarget {
protected final LaunchClassLoader classLoader;
public LaunchTarget(LaunchClassLoader classLoader) {
this.classLoader = classLoader;
}
public abstract void launch();
public abstract void launch(LaunchClassLoader classLoader);
}

View file

@ -7,12 +7,11 @@ public class MainLaunchTarget extends LaunchTarget {
public String targetClass;
public String[] args;
public MainLaunchTarget(LaunchClassLoader classLoader, String classTarget) {
super(classLoader);
public MainLaunchTarget(String classTarget) {
targetClass = classTarget;
}
public void launch() {
public void launch(LaunchClassLoader classLoader) {
classLoader.invokeMain(targetClass, args);
}

View file

@ -110,7 +110,10 @@ public class InsnHelper {
return matches;
case LABEL:
LabelNode insn9 = (LabelNode) insn;
// TODO
if(compare.length > 0) {
LabelNode label = (LabelNode) compare[0];
matches &= label == insn9;
}
return matches;
case LDC_INSN:
LdcInsnNode insn10 = (LdcInsnNode) insn;
@ -149,8 +152,6 @@ public class InsnHelper {
}
return matches;
case FRAME:
FrameNode insn15 = (FrameNode) insn;
// TODO
return matches;
case LINE:
LineNumberNode insn16 = (LineNumberNode) insn;

View file

@ -8,9 +8,9 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
@ -19,6 +19,7 @@ import java.util.HashMap;
import java.util.Map;
import org.mcphackers.launchwrapper.inject.ClassNodeSource;
import org.mcphackers.launchwrapper.tweak.ClassLoaderTweak;
import org.mcphackers.launchwrapper.util.Util;
import org.mcphackers.rdi.util.NodeHelper;
import org.objectweb.asm.ClassReader;
@ -27,11 +28,14 @@ import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodNode;
public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
// URLClassLoader is required to support ModLoader loading mods from mod folder
public class LaunchClassLoader extends URLClassLoader implements ClassNodeSource {
public static final int CLASS_VERSION = getSupportedClassVersion();
private static LaunchClassLoader INSTANCE;
private ClassLoader parent;
private ClassLoaderTweak tweak;
private Map<String, Class<?>> exceptions = new HashMap<String, Class<?>>();
/** Keys should contain dots */
private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
@ -42,23 +46,34 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
private File debugOutput;
public LaunchClassLoader(ClassLoader parent) {
super(null);
super(new URL[0], null);
this.parent = parent;
}
public void setClassPath(URL[] urls) {
this.parent = new URLClassLoader(urls, parent);
for(URL url : urls) {
super.addURL(url);
}
}
public void setDebugOutput(File directory) {
debugOutput = directory;
}
protected void addURL(URL url) {
super.addURL(url);
}
public URL getResource(String name) {
URL url = super.getResource(name);
if(url != null) {
return url;
}
return parent.getResource(name);
}
public Enumeration<URL> getResources(String name) throws IOException {
//TODO ?
return parent.getResources(name);
}
@ -67,7 +82,12 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
return parent.loadClass(name);
}
name = className(name);
Class<?> cls = exceptions.get(name);
Class<?> cls;
cls = exceptions.get(name);
if(cls != null) {
return cls;
}
cls = classes.get(name);
if(cls != null) {
return cls;
}
@ -92,28 +112,30 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
}
}
protected Class<?> redefineClass(String name) {
byte[] classData = getClassAsBytes(name);
if(classData == null)
return null;
Class<?> definedClass = defineClass(name, classData, 0, classData.length, getProtectionDomain(name));
classes.put(name, definedClass);
return definedClass;
}
private ProtectionDomain getProtectionDomain(String name) {
final URL resource = parent.getResource(classResourceName(name));
final URL resource = getResource(classResourceName(name));
if(resource == null) {
return null;
}
URLConnection urlConnection;
try {
urlConnection = resource.openConnection();
} catch (IOException e) {
e.printStackTrace();
return null;
CodeSource codeSource;
if(resource.getProtocol().equals("jar")) {
String path = resource.getPath();
if(path.startsWith("file:")) {
path = path.substring("file:".length());
int i = path.lastIndexOf('!');
if(i != -1) {
path.substring(0, i);
}
}
try {
URL newResource = new URL("file", "", path);
codeSource = new CodeSource(newResource, new Certificate[0]);
} catch (MalformedURLException e) {
codeSource = new CodeSource(resource, new Certificate[0]);
}
} else {
codeSource = new CodeSource(resource, new Certificate[0]);
}
CodeSource codeSource = urlConnection == null ? null : new CodeSource(urlConnection.getURL(), new Certificate[0]);
return new ProtectionDomain(codeSource, null);
}
@ -172,15 +194,30 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
return NodeHelper.getMethod(getClass(owner), name, desc);
}
protected Class<?> redefineClass(String name) {
ClassNode classNode = getClass(name);
if(classNode != null && tweak != null && tweak.tweakClass(classNode)) {
return redefineClass(classNode);
}
byte[] classData = getClassAsBytes(name);
if(classData == null) {
return null;
}
Class<?> definedClass = defineClass(name, classData, 0, classData.length, getProtectionDomain(name));
classes.put(name, definedClass);
return definedClass;
}
private Class<?> redefineClass(ClassNode node) {
if(node == null) {
return null;
}
ClassWriter writer = new SafeClassWriter(parent, COMPUTE_MAXS | COMPUTE_FRAMES);
ClassWriter writer = new SafeClassWriter(this, COMPUTE_MAXS | COMPUTE_FRAMES);
node.accept(writer);
byte[] classData = writer.toByteArray();
Class<?> definedClass = defineClass(className(node.name), classData, 0, classData.length);
classes.put(className(node.name), definedClass);
String name = className(node.name);
Class<?> definedClass = defineClass(name, classData, 0, classData.length, getProtectionDomain(name));
classes.put(name, definedClass);
return definedClass;
}
@ -196,8 +233,17 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
return name.replace('.', '/') + ".class";
}
private InputStream getClassAsStream(String name) {
String className = classResourceName(name);
InputStream is = super.getResourceAsStream(className);
if(is != null) {
return is;
}
return parent.getResourceAsStream(className);
}
private byte[] getClassAsBytes(String name) {
InputStream is = parent.getResourceAsStream(classResourceName(name));
InputStream is = getClassAsStream(name);
if(is == null)
return null;
byte[] classData;
@ -212,12 +258,11 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
}
private Class<?> transformedClass(String name) {
Class<?> cls = classes.get(name);
if(cls != null) {
return cls;
}
ClassNode transformed = overridenClasses.get(name);
if(transformed != null) {
if(tweak != null) {
tweak.tweakClass(transformed);
}
return redefineClass(transformed);
}
return redefineClass(name);
@ -227,6 +272,30 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
exceptions.put(cls.getName(), cls);
}
public void setLoaderTweak(ClassLoaderTweak classLoaderTweak) {
tweak = classLoaderTweak;
}
private static ClassNode getSystemClass(Class<?> cls) {
InputStream is = ClassLoader.getSystemResourceAsStream(classResourceName(cls.getName()));
if(is == null)
return null;
try {
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(is);
classReader.accept(classNode, 0);
return classNode;
} catch (IOException e) {
Util.closeSilently(is);
return null;
}
}
private static int getSupportedClassVersion() {
ClassNode objectClass = getSystemClass(Object.class);
return objectClass.version;
}
public static LaunchClassLoader instantiate() {
if(INSTANCE != null) {
throw new IllegalStateException("Can only have one instance of LaunchClassLoader!");

View file

@ -1,5 +1,6 @@
package org.mcphackers.launchwrapper.protocol;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URL;
@ -108,6 +109,7 @@ public class SkinRequests {
try {
if(skindata.cape != null) {
switch(skinType) {
case PRE_19A:
case CLASSIC:
case PRE_B1_9:
case PRE_1_8:
@ -142,15 +144,19 @@ public class SkinRequests {
ImageUtils imgu = new ImageUtils(bis);
switch(skinType) {
case PRE_19A:
case CLASSIC:
overlayHeadLayer(imgu);
case PRE_B1_9:
rotateBottomTX(imgu);
case PRE_1_8:
if(imgu.getImage().getHeight() == 64)
overlay64to32(imgu);
if(skindata.slim)
alexToSteve(imgu);
if(skinType == SkinType.PRE_B1_9 || skinType == SkinType.CLASSIC || skinType == SkinType.PRE_19A)
rotateBottomTX(imgu);
if(skinType == SkinType.PRE_19A)
flipSkin(imgu);
imgu = imgu.crop(0, 0, 64, 32);
case DEFAULT:
break;
@ -163,6 +169,43 @@ public class SkinRequests {
return skin;
}
private static void flipSkin(ImageUtils imgu) {
BufferedImage sideLeft;
BufferedImage sideRight;
// head
imgu.setArea(8, 0, imgu.crop(8, 0, 8, 16).flip(true, false).getImage());
imgu.setArea(16, 0, imgu.crop(16, 0, 8, 8).flip(true, false).getImage());
imgu.setArea(24, 8, imgu.crop(24, 8, 8, 8).flip(true, false).getImage());
sideLeft = imgu.crop(0, 8, 8, 8).flip(true, false).getImage();
sideRight = imgu.crop(16, 8, 8, 8).flip(true, false).getImage();
imgu.setArea(16, 8, sideLeft);
imgu.setArea(0, 8, sideRight);
// body
imgu.setArea(20, 16, imgu.crop(20, 16, 8, 16).flip(true, false).getImage());
imgu.setArea(28, 16, imgu.crop(28, 16, 8, 4).flip(true, false).getImage());
imgu.setArea(32, 20, imgu.crop(32, 20, 8, 12).flip(true, false).getImage());
sideLeft = imgu.crop(16, 20, 4, 12).flip(true, false).getImage();
sideRight = imgu.crop(28, 20, 4, 12).flip(true, false).getImage();
imgu.setArea(28, 20, sideLeft);
imgu.setArea(16, 20, sideRight);
// leg
imgu.setArea(4, 16, imgu.crop(4, 16, 4, 16).flip(true, false).getImage());
imgu.setArea(8, 16, imgu.crop(8, 16, 4, 4).flip(true, false).getImage());
imgu.setArea(12, 20, imgu.crop(12, 20, 4, 12).flip(true, false).getImage());
sideLeft = imgu.crop(0, 20, 4, 12).flip(true, false).getImage();
sideRight = imgu.crop(8, 20, 4, 12).flip(true, false).getImage();
imgu.setArea(8, 20, sideLeft);
imgu.setArea(0, 20, sideRight);
// arm
imgu.setArea(44, 16, imgu.crop(44, 16, 4, 16).flip(true, false).getImage());
imgu.setArea(48, 16, imgu.crop(48, 16, 4, 4).flip(true, false).getImage());
imgu.setArea(52, 20, imgu.crop(52, 20, 4, 12).flip(true, false).getImage());
sideLeft = imgu.crop(40, 20, 4, 12).flip(true, false).getImage();
sideRight = imgu.crop(48, 20, 4, 12).flip(true, false).getImage();
imgu.setArea(48, 20, sideLeft);
imgu.setArea(40, 20, sideRight);
}
public static void rotateBottomTX(ImageUtils imgu) {
// bottom head
imgu.setArea(16, 0, imgu.crop(16, 0, 8, 8).flip(false, true).getImage());
@ -201,18 +244,9 @@ public class SkinRequests {
}
public static void alexToSteve(ImageUtils imgu) {
// make space for the left arm 1px texture
imgu.setArea(48, 20, imgu.crop(47, 20, 7, 12).getImage());
// fill the 1px space in between
imgu.setArea(47, 20, imgu.crop(46, 20, 1, 12).getImage());
// fill the 1px space on the right
imgu.setArea(55, 20, imgu.crop(54, 20, 1, 12).getImage());
// bottom hand
imgu.setArea(48, 16, imgu.crop(47, 16, 3, 4).getImage());
// fill the 1px of the shoulder
imgu.setArea(47, 16, imgu.crop(46, 16, 1, 4).getImage());
// fill the 1px space on the right
imgu.setArea(51, 16, imgu.crop(50, 16, 1, 4).getImage());
imgu.setArea(48, 16, imgu.crop(47, 16, 7, 16).getImage());
imgu.setArea(47, 16, imgu.crop(45, 16, 1, 16).getImage());
imgu.setArea(55, 20, imgu.crop(53, 20, 1, 12).getImage());
imgu.setArea(51, 16, imgu.crop(49, 16, 1, 4).getImage());
}
}

View file

@ -1,6 +1,7 @@
package org.mcphackers.launchwrapper.protocol;
public enum SkinType {
PRE_19A("pre-c0.0.19a"),
CLASSIC("classic"),
PRE_B1_9("pre-b1.9-pre4"),
PRE_1_8("pre-1.8"),

View file

@ -0,0 +1,8 @@
package org.mcphackers.launchwrapper.tweak;
import org.objectweb.asm.tree.ClassNode;
public abstract class ClassLoaderTweak {
public abstract boolean tweakClass(ClassNode node);
}

View file

@ -1,6 +1,6 @@
package org.mcphackers.launchwrapper.tweak;
import static org.mcphackers.launchwrapper.inject.InsnHelper.*;
import static org.mcphackers.launchwrapper.inject.InsnHelper.getLastReturn;
import static org.objectweb.asm.Opcodes.*;
import org.mcphackers.launchwrapper.AppletLaunchTarget;
@ -8,7 +8,6 @@ import org.mcphackers.launchwrapper.LaunchConfig;
import org.mcphackers.launchwrapper.LaunchTarget;
import org.mcphackers.launchwrapper.inject.ClassNodeSource;
import org.mcphackers.launchwrapper.inject.Inject;
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.FieldNode;
@ -71,9 +70,9 @@ public class IsomTweak extends LegacyTweak {
return true;
}
public LaunchTarget getLaunchTarget(LaunchClassLoader loader) {
public LaunchTarget getLaunchTarget() {
if(isomApplet != null) {
AppletLaunchTarget launchTarget = new AppletLaunchTarget(loader, isomApplet.name);
AppletLaunchTarget launchTarget = new AppletLaunchTarget(isomApplet.name);
if(launch.title.get() != null) {
launchTarget.setTitle(launch.title.get());
} else {

View file

@ -0,0 +1,65 @@
package org.mcphackers.launchwrapper.tweak;
import static org.mcphackers.launchwrapper.inject.InsnHelper.compareInsn;
import static org.mcphackers.rdi.util.InsnHelper.*;
import static org.objectweb.asm.Opcodes.*;
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
public class LegacyClassLoaderTweak extends ClassLoaderTweak {
public boolean tweakClass(ClassNode node) {
boolean changed = false;
if(node.version > LaunchClassLoader.CLASS_VERSION) {
node.version = LaunchClassLoader.CLASS_VERSION;
changed = true;
}
for(MethodNode m : node.methods) {
AbstractInsnNode insn = m.instructions.getFirst();
while(insn != null) {
AbstractInsnNode[] insns = fill(insn, 3);
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);
InsnList insert = new InsnList();
LabelNode not = new LabelNode();
LabelNode end = new LabelNode();
insert.add(new JumpInsnNode(IFEQ, not));
insert.add(booleanInsn(false));
insert.add(new JumpInsnNode(GOTO, end));
insert.add(not);
insert.add(booleanInsn(true));
insert.add(end);
m.instructions.insert(invoke, insert);
insn = nextInsn(invoke);
changed = true;
continue;
}
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)) {
m.instructions.set(insns[2], new MethodInsnNode(INVOKEVIRTUAL, "java/lang/String", "getBytes", "(Ljava/lang/String;)[B"));
m.instructions.remove(insns[1]);
changed = true;
}
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)) {
m.instructions.set(insns[2], new MethodInsnNode(INVOKESPECIAL, "java/lang/String", "<init>", "([BLjava/lang/String;)V"));
m.instructions.remove(insns[1]);
changed = true;
}
insn = nextInsn(insn);
}
}
return changed;
}
}

View file

@ -15,7 +15,6 @@ import org.mcphackers.launchwrapper.LaunchConfig;
import org.mcphackers.launchwrapper.LaunchTarget;
import org.mcphackers.launchwrapper.MainLaunchTarget;
import org.mcphackers.launchwrapper.inject.ClassNodeSource;
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler;
import org.mcphackers.launchwrapper.protocol.SkinType;
import org.mcphackers.launchwrapper.protocol.URLStreamHandlerProxy;
@ -105,6 +104,7 @@ public class LegacyTweak extends Tweak {
replaceGameDirectory(init, mcDir);
optionsLoadFix(init);
displayPatch(init, supportsResizing);
bitDepthFix(init);
fixMouseHelper(mouseHelperName);
patchMinecraftInit();
@ -119,6 +119,10 @@ public class LegacyTweak extends Tweak {
return true;
}
public ClassLoaderTweak getLoaderTweak() {
return new LegacyClassLoaderTweak();
}
private void downloadServer() {
if(launch.serverURL.get() == null || launch.gameDir.get() == null) {
return;
@ -143,7 +147,7 @@ public class LegacyTweak extends Tweak {
}
}
public LaunchTarget getLaunchTarget(LaunchClassLoader loader) {
public LaunchTarget getLaunchTarget() {
if(main == null) {
return null;
}
@ -151,7 +155,7 @@ public class LegacyTweak extends Tweak {
enableLegacyMergeSort();
URLStreamHandlerProxy.setURLStreamHandler("http", new LegacyURLStreamHandler(skinType, port));
URLStreamHandlerProxy.setURLStreamHandler("https", new LegacyURLStreamHandler(skinType, port));
MainLaunchTarget target = new MainLaunchTarget(loader, minecraft.name);
MainLaunchTarget target = new MainLaunchTarget(minecraft.name);
target.args = new String[] { launch.username.get(), launch.sessionid.get() };
return target;
}
@ -374,6 +378,32 @@ public class LegacyTweak extends Tweak {
insn1 = nextInsn(insn1);
}
}
private void bitDepthFix(MethodNode init) {
for(TryCatchBlockNode tryCatch : init.tryCatchBlocks) {
if(!"org/lwjgl/LWJGLException".equals(tryCatch.type)) {
continue;
}
AbstractInsnNode insn = tryCatch.end;
while(insn != null && insn != tryCatch.start) {
if(compareInsn(insn, INVOKESTATIC, "org/lwjgl/opengl/Display", "create", "(Lorg/lwjgl/opengl/PixelFormat;)V")) {
return;
}
if(compareInsn(insn, INVOKESTATIC, "org/lwjgl/opengl/Display", "create", "()V")) {
InsnList insert = new InsnList();
insert.add(new TypeInsnNode(NEW, "org/lwjgl/opengl/PixelFormat"));
insert.add(new InsnNode(DUP));
insert.add(new MethodInsnNode(INVOKESPECIAL, "org/lwjgl/opengl/PixelFormat", "<init>", "()V"));
insert.add(intInsn(24));
insert.add(new MethodInsnNode(INVOKEVIRTUAL, "org/lwjgl/opengl/PixelFormat", "withDepthBits", "(I)Lorg/lwjgl/opengl/PixelFormat;"));
insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "create", "(Lorg/lwjgl/opengl/PixelFormat;)V"));
init.instructions.insert(insn, insert);
init.instructions.remove(insn);
}
insn = previousInsn(insn);
}
}
}
private void displayPatch(MethodNode init, boolean supportsResizing) {
boolean foundTitle = false; // TODO
@ -453,8 +483,7 @@ public class LegacyTweak extends Tweak {
else
if(compareInsn(insns[0], ICONST_1)
&& compareInsn(insns[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "setFullscreen", "(Z)V")
&& insns[2] != null && insns[2].getType() == AbstractInsnNode.LABEL //FIXME fill no longer stores labels
&& compareInsn(insns[4], INVOKESTATIC, "org/lwjgl/opengl/Display", "create", "()V")) {
&& compareInsn(insns[2], INVOKESTATIC, "org/lwjgl/opengl/Display", "create", "()V")) {
tweakInfo("Pre-classic resolution patch");
InsnList insert = getIcon(classic);
if(launch.forceVsync.get()) {
@ -603,6 +632,7 @@ public class LegacyTweak extends Tweak {
&& compareInsn(insns3[7], INVOKESTATIC, "org/lwjgl/opengl/Display", "setDisplayMode", "(Lorg/lwjgl/opengl/DisplayMode;)V")) {
m.instructions.set(insns3[3], new FieldInsnNode(GETFIELD, minecraft.name, defaultWidth.name, defaultWidth.desc));
m.instructions.set(insns3[5], new FieldInsnNode(GETFIELD, minecraft.name, defaultHeight.name, defaultHeight.desc));
break methodLoop;
} else {
JumpInsnNode jump = (JumpInsnNode) insns2[0];
LabelNode newLabel = new LabelNode();
@ -618,6 +648,7 @@ public class LegacyTweak extends Tweak {
insert.add(new MethodInsnNode(INVOKESPECIAL, "org/lwjgl/opengl/DisplayMode", "<init>", "(II)V"));
insert.add(new MethodInsnNode(INVOKESTATIC, "org/lwjgl/opengl/Display", "setDisplayMode", "(Lorg/lwjgl/opengl/DisplayMode;)V"));
m.instructions.insert(insns2[3], insert);
break methodLoop;
}
}
insn2 = nextInsn(insn2);
@ -1139,7 +1170,8 @@ public class LegacyTweak extends Tweak {
String mcField = null;
String mcDesc = "L" + minecraft.name + ";";
if(minecraftApplet != null) {
boolean invokeAppletInit = patchAppletInit();
if(invokeAppletInit) {
for(FieldNode field : minecraftApplet.fields) {
if(mcDesc.equals(field.desc)) {
mcField = field.name;
@ -1154,7 +1186,6 @@ public class LegacyTweak extends Tweak {
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/applet/Applet", "setStub", "(Ljava/applet/AppletStub;)V"));
insns.add(new VarInsnNode(ALOAD, appletIndex));
insns.add(new MethodInsnNode(INVOKEVIRTUAL, minecraftApplet.name, "init", "()V"));
patchAppletInit();
}
if(!launch.lwjglFrame.get()) {
insns.add(new TypeInsnNode(NEW, "java/awt/Frame"));
@ -1191,7 +1222,7 @@ public class LegacyTweak extends Tweak {
insns.add(new InsnNode(ACONST_NULL));
insns.add(new MethodInsnNode(INVOKEVIRTUAL, "java/awt/Frame", "setLocationRelativeTo", "(Ljava/awt/Component;)V"));
}
if(minecraftApplet != null) {
if(invokeAppletInit) {
insns.add(new VarInsnNode(ALOAD, appletIndex));
insns.add(new FieldInsnNode(GETFIELD, minecraftApplet.name, mcField, mcDesc));
} else {
@ -1250,13 +1281,16 @@ public class LegacyTweak extends Tweak {
return node;
}
private void patchAppletInit() {
private boolean patchAppletInit() {
if(minecraftApplet == null) {
return false;
}
String mcField = null;
String canvasField = null;
String mcDesc = "L" + minecraft.name + ";";
MethodNode init = NodeHelper.getMethod(minecraftApplet, "init", "()V");
if(init == null) {
throw new IllegalStateException("Missing applet init");
return false;
}
for(FieldNode field : minecraftApplet.fields) {
if(mcDesc.equals(field.desc)) {
@ -1339,6 +1373,7 @@ public class LegacyTweak extends Tweak {
insn = nextInsn(insn);
}
source.overrideClass(minecraftApplet);
return true;
}
private void createWindowListener(String listenerClass) {

View file

@ -17,9 +17,19 @@ public abstract class Tweak {
public abstract boolean transform();
public abstract LaunchTarget getLaunchTarget(LaunchClassLoader loader);
public abstract ClassLoaderTweak getLoaderTweak();
public abstract LaunchTarget getLaunchTarget();
public static Tweak get(LaunchClassLoader classLoader, LaunchConfig launch) {
Tweak tweak = getTweak(classLoader, launch);
if(tweak != null) {
classLoader.setLoaderTweak(tweak.getLoaderTweak());
}
return tweak;
}
private static Tweak getTweak(LaunchClassLoader classLoader, LaunchConfig launch) {
if(launch.isom.get()) {
return new IsomTweak(classLoader, launch);
}

View file

@ -1,6 +1,6 @@
package org.mcphackers.launchwrapper.tweak;
import static org.mcphackers.launchwrapper.inject.InsnHelper.*;
import static org.mcphackers.launchwrapper.inject.InsnHelper.compareInsn;
import static org.mcphackers.rdi.util.InsnHelper.*;
import static org.objectweb.asm.Opcodes.*;
@ -13,7 +13,6 @@ import org.mcphackers.launchwrapper.LaunchConfig.LaunchParameter;
import org.mcphackers.launchwrapper.LaunchTarget;
import org.mcphackers.launchwrapper.MainLaunchTarget;
import org.mcphackers.launchwrapper.inject.ClassNodeSource;
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler;
import org.mcphackers.launchwrapper.protocol.URLStreamHandlerProxy;
import org.mcphackers.rdi.util.IdentifyCall;
@ -190,12 +189,17 @@ public class VanillaTweak extends Tweak {
}
}
public LaunchTarget getLaunchTarget(LaunchClassLoader loader) {
public LaunchTarget getLaunchTarget() {
URLStreamHandlerProxy.setURLStreamHandler("http", new LegacyURLStreamHandler(launch.skinProxy.get(), 11707));
URLStreamHandlerProxy.setURLStreamHandler("https", new LegacyURLStreamHandler(launch.skinProxy.get(), 11707));
MainLaunchTarget target = new MainLaunchTarget(loader, MAIN_CLASS);
MainLaunchTarget target = new MainLaunchTarget(MAIN_CLASS);
target.args = launch.getArgs();
return target;
}
@Override
public ClassLoaderTweak getLoaderTweak() {
return null;
}
}