Format source and add README
This commit is contained in:
parent
d18a02a90c
commit
ee061a6204
33 changed files with 3266 additions and 3439 deletions
51
README.md
Normal file
51
README.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
# LaunchWrapper
|
||||
|
||||
**LaunchWrapper** is a wrapper for legacy Minecraft which provides fixes for certain game features and also improves compatibility with launchers.
|
||||
|
||||
LaunchWrapper is bundled in [BetterJSONs](https://github.com/MCPHackers/BetterJSONs) which are meant for official Minecraft Launcher.
|
||||
|
||||
# Features
|
||||
- Strips game window from Java **AWT** (**Abstract Window Toolkit**) and lets the game use internal **LWJGL** frame
|
||||
- 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+
|
||||
- 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
|
||||
- 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
|
||||
- A launcher for isometric level viewer (IsomPreviewApplet)
|
||||
- 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
|
||||
|
||||
# How to use
|
||||
*This is a more in-depth guide for people experienced in Java*
|
||||
|
||||
Make sure all minecraft and wrapper libraries are on classpath<br>
|
||||
Use `java -cp <classpath> org.mcphackers.launchwrapper.Launch <arguments>` to launch the game
|
||||
|
||||
Arguments are formatted the same way as in Mojang launch wrapper. <br>
|
||||
For example: `--username DemoUser --width 1280 --height 720 --title "Minecraft Demo" --demo`
|
||||
|
||||
Arguments may be as follows:
|
||||
- `awtFrame` - disable AWT patches (Does not work at that moment)
|
||||
- `isom` - Launch IsomPreviewApplet
|
||||
- `forceVsync` - Launch the game with VSync enabled
|
||||
- `forceResizable` - Early Indev and Classic are 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
|
||||
- **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
|
||||
- **default** - do nothing with requested skin
|
||||
- `resourcesProxyPort` - Betacraft proxy port for sound resources
|
||||
- `serverSHA1` - Compare minecraft_server.jar in .minecraft/server against this hash
|
||||
- `serverURL` - URL to download the server from if the hash is mismatched or the jar is missing
|
||||
- `icon` - List of path of icon graphics separated by `;`
|
||||
- `title` - The display title
|
||||
- \+ any Minecraft launch argument or applet parameter
|
|
@ -21,7 +21,7 @@ dependencies {
|
|||
implementation 'org.lwjgl.lwjgl:lwjgl_util:2.9.4'
|
||||
implementation 'org.ow2.asm:asm:9.3'
|
||||
implementation 'org.ow2.asm:asm-tree:9.3'
|
||||
implementation 'org.json:json:20220924'
|
||||
implementation 'org.json:json:20230311'
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
|
|
|
@ -18,16 +18,16 @@ public class AppletLaunchTarget extends LaunchTarget {
|
|||
targetClass = classTarget;
|
||||
title = classTarget;
|
||||
}
|
||||
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
|
||||
public void setResolution(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
|
||||
public void setIcon(Image img) {
|
||||
icon = img;
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ public class Launch {
|
|||
|
||||
private static final LaunchClassLoader CLASS_LOADER = LaunchClassLoader.instantiate();
|
||||
public static Launch INSTANCE;
|
||||
|
||||
|
||||
public final LaunchConfig config;
|
||||
|
||||
|
||||
private Launch(LaunchConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
@ -34,11 +34,11 @@ public class Launch {
|
|||
mainTweak.getLaunchTarget(CLASS_LOADER).launch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setClassPath(URL[] urls) {
|
||||
CLASS_LOADER.setClassPath(urls);
|
||||
}
|
||||
|
||||
|
||||
public static Launch create(LaunchConfig config) {
|
||||
return INSTANCE = new Launch(config);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Map;
|
|||
|
||||
public class LaunchConfig {
|
||||
private Map<String, LaunchParameter<?>> parameters = new HashMap<String, LaunchParameter<?>>();
|
||||
|
||||
public LaunchParameterSwitch demo = new LaunchParameterSwitch("demo", false);
|
||||
public LaunchParameterSwitch fullscreen = new LaunchParameterSwitch("fullscreen", false);
|
||||
public LaunchParameterSwitch checkGlErrors = new LaunchParameterSwitch("checkGlErrors", false);
|
||||
|
@ -41,7 +42,7 @@ public class LaunchConfig {
|
|||
public LaunchParameterString loadmap_user = new LaunchParameterString("loadmap_user");
|
||||
public LaunchParameterNumber loadmap_id = new LaunchParameterNumber("loadmap_id");
|
||||
public LaunchParameterString mppass = new LaunchParameterString("mppass", "");
|
||||
public LaunchParameterSwitch lwjglFrame = new LaunchParameterSwitch("lwjglFrame", true, true);
|
||||
public LaunchParameterSwitch lwjglFrame = new LaunchParameterSwitch("awtFrame", true, true);
|
||||
public LaunchParameterSwitch isom = new LaunchParameterSwitch("isom", false, true);
|
||||
public LaunchParameterSwitch forceVsync = new LaunchParameterSwitch("forceVsync", false, true);
|
||||
public LaunchParameterSwitch forceResizable = new LaunchParameterSwitch("forceResizable", false, true);
|
||||
|
@ -53,40 +54,36 @@ public class LaunchConfig {
|
|||
public LaunchParameterString title = new LaunchParameterString("title", null, true);
|
||||
|
||||
public LaunchConfig(String[] args) {
|
||||
int i = 0;
|
||||
while(i < args.length) {
|
||||
for(int i = 0; i < args.length; i++) {
|
||||
if(args[i].startsWith("--")) {
|
||||
String paramName = args[i].substring(2);
|
||||
LaunchParameter<?> param = parameters.get(paramName.toLowerCase(Locale.ENGLISH));
|
||||
if(paramName.equalsIgnoreCase("awtFrame")) {
|
||||
lwjglFrame.set(false);
|
||||
if(param == null) {
|
||||
continue;
|
||||
}
|
||||
else if(param != null) {
|
||||
if(param.isSwitch()) {
|
||||
((LaunchParameterSwitch)param).set(true);
|
||||
}
|
||||
else if(i + 1 < args.length) {
|
||||
try {
|
||||
//TODO better handling for alternative parameter names
|
||||
if(param.equals(session)) {
|
||||
sessionid.set(args[i + 1]);
|
||||
}
|
||||
if(param.equals(sessionid)) {
|
||||
session.set(args[i + 1]);
|
||||
}
|
||||
if(param.equals(gameDir)) {
|
||||
workDir.set(new File(args[i + 1]));
|
||||
}
|
||||
if(param.equals(workDir)) {
|
||||
gameDir.set(new File(args[i + 1]));
|
||||
}
|
||||
param.setString(args[i + 1]);
|
||||
i++;
|
||||
} catch (IllegalArgumentException e) {}
|
||||
if(param.isSwitch()) {
|
||||
((LaunchParameterSwitch) param).setFlag();
|
||||
} else if(i + 1 < args.length) {
|
||||
try {
|
||||
// TODO better handling for alternative parameter names
|
||||
if(param.equals(session)) {
|
||||
sessionid.set(args[i + 1]);
|
||||
}
|
||||
if(param.equals(sessionid)) {
|
||||
session.set(args[i + 1]);
|
||||
}
|
||||
if(param.equals(gameDir)) {
|
||||
workDir.set(new File(args[i + 1]));
|
||||
}
|
||||
if(param.equals(workDir)) {
|
||||
gameDir.set(new File(args[i + 1]));
|
||||
}
|
||||
param.setString(args[i + 1]);
|
||||
i++;
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +106,7 @@ public class LaunchConfig {
|
|||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
public String[] getArgs() {
|
||||
List<String> list = new ArrayList<String>();
|
||||
for(LaunchParameter<?> param : parameters.values()) {
|
||||
|
@ -126,46 +123,46 @@ public class LaunchConfig {
|
|||
String[] arr = new String[list.size()];
|
||||
return list.toArray(arr);
|
||||
}
|
||||
|
||||
|
||||
public abstract class LaunchParameter<T> {
|
||||
public final String name;
|
||||
public final boolean wrapperOnly;
|
||||
|
||||
|
||||
protected LaunchParameter(String name) {
|
||||
this(name, false);
|
||||
}
|
||||
|
||||
|
||||
protected LaunchParameter(String name, boolean wrapper) {
|
||||
this.name = name;
|
||||
this.wrapperOnly = wrapper;
|
||||
parameters.put(name.toLowerCase(Locale.ENGLISH), this);
|
||||
}
|
||||
|
||||
|
||||
public boolean isSwitch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public abstract String getString();
|
||||
|
||||
|
||||
public abstract void setString(String argument);
|
||||
|
||||
|
||||
public abstract Object get();
|
||||
|
||||
|
||||
public abstract void set(T value);
|
||||
}
|
||||
|
||||
|
||||
public class LaunchParameterFile extends LaunchParameter<File> {
|
||||
private File value;
|
||||
|
||||
public LaunchParameterFile(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterFile(String name, File defaultValue) {
|
||||
super(name);
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterFile(String name, File defaultValue, boolean wrapper) {
|
||||
super(name, wrapper);
|
||||
value = defaultValue;
|
||||
|
@ -173,7 +170,8 @@ public class LaunchConfig {
|
|||
|
||||
@Override
|
||||
public String getString() {
|
||||
if(value == null) return null;
|
||||
if(value == null)
|
||||
return null;
|
||||
return this.value.getAbsolutePath();
|
||||
}
|
||||
|
||||
|
@ -186,25 +184,25 @@ public class LaunchConfig {
|
|||
public File get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(File value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LaunchParameterFileList extends LaunchParameter<File[]> {
|
||||
private File[] value;
|
||||
|
||||
public LaunchParameterFileList(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterFileList(String name, File[] defaultValue) {
|
||||
super(name);
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterFileList(String name, File[] defaultValue, boolean wrapper) {
|
||||
super(name, wrapper);
|
||||
value = defaultValue;
|
||||
|
@ -212,7 +210,8 @@ public class LaunchConfig {
|
|||
|
||||
@Override
|
||||
public String getString() {
|
||||
if(value == null) return null;
|
||||
if(value == null)
|
||||
return null;
|
||||
String s = "";
|
||||
for(int i = 0; i < value.length; i++) {
|
||||
if(i != 0) {
|
||||
|
@ -237,30 +236,33 @@ public class LaunchConfig {
|
|||
public File[] get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(File[] value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LaunchParameterSwitch extends LaunchParameter<Boolean> {
|
||||
private boolean value;
|
||||
private boolean defaultValue;
|
||||
|
||||
public LaunchParameterSwitch(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public LaunchParameterSwitch(String name, Boolean defaultValue) {
|
||||
|
||||
public LaunchParameterSwitch(String name, Boolean defaultVal) {
|
||||
super(name);
|
||||
value = defaultValue;
|
||||
defaultValue = defaultVal;
|
||||
value = defaultVal;
|
||||
}
|
||||
|
||||
public LaunchParameterSwitch(String name, Boolean defaultValue, boolean wrapper) {
|
||||
|
||||
public LaunchParameterSwitch(String name, Boolean defaultVal, boolean wrapper) {
|
||||
super(name, wrapper);
|
||||
value = defaultValue;
|
||||
defaultValue = defaultVal;
|
||||
value = defaultVal;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSwitch() {
|
||||
return true;
|
||||
}
|
||||
|
@ -279,25 +281,33 @@ public class LaunchConfig {
|
|||
public Boolean get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(Boolean value) {
|
||||
this.value = value == null ? false : value;
|
||||
}
|
||||
|
||||
public void setFlag() {
|
||||
this.value = !defaultValue;
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
this.value = !value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LaunchParameterString extends LaunchParameter<String> {
|
||||
private String value;
|
||||
|
||||
public LaunchParameterString(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterString(String name, String defaultValue) {
|
||||
super(name);
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterString(String name, String defaultValue, boolean wrapper) {
|
||||
super(name, wrapper);
|
||||
value = defaultValue;
|
||||
|
@ -317,25 +327,25 @@ public class LaunchConfig {
|
|||
public String get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LaunchParameterNumber extends LaunchParameter<Integer> {
|
||||
private Integer value;
|
||||
|
||||
public LaunchParameterNumber(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterNumber(String name, Integer defaultValue) {
|
||||
super(name);
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public LaunchParameterNumber(String name, Integer defaultValue, boolean wrapper) {
|
||||
super(name, wrapper);
|
||||
value = defaultValue;
|
||||
|
@ -355,7 +365,7 @@ public class LaunchConfig {
|
|||
public Integer get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void set(Integer value) {
|
||||
this.value = value;
|
||||
|
|
|
@ -3,9 +3,9 @@ package org.mcphackers.launchwrapper;
|
|||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
|
||||
public abstract class LaunchTarget {
|
||||
|
||||
|
||||
protected final LaunchClassLoader classLoader;
|
||||
|
||||
|
||||
public LaunchTarget(LaunchClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
|
|
@ -3,15 +3,15 @@ package org.mcphackers.launchwrapper;
|
|||
import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
||||
|
||||
public class MainLaunchTarget extends LaunchTarget {
|
||||
|
||||
|
||||
public String targetClass;
|
||||
public String[] args;
|
||||
|
||||
|
||||
public MainLaunchTarget(LaunchClassLoader classLoader, String classTarget) {
|
||||
super(classLoader);
|
||||
targetClass = classTarget;
|
||||
}
|
||||
|
||||
|
||||
public void launch() {
|
||||
classLoader.invokeMain(targetClass, args);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ import org.objectweb.asm.tree.FieldNode;
|
|||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
public interface ClassNodeSource {
|
||||
|
||||
|
||||
ClassNode getClass(String name);
|
||||
|
||||
|
||||
FieldNode getField(String owner, String name, String desc);
|
||||
|
||||
|
||||
MethodNode getMethod(String owner, String name, String desc);
|
||||
|
||||
|
||||
void overrideClass(ClassNode node);
|
||||
|
||||
}
|
||||
|
|
|
@ -18,26 +18,26 @@ import org.mcphackers.launchwrapper.tweak.AppletWrapper;
|
|||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public class Inject {
|
||||
|
||||
|
||||
private static final Launch LAUNCH = Launch.INSTANCE;
|
||||
private static final BufferedImage DEFAULT_ICON = getIcon();
|
||||
|
||||
public static AppletWrapper getApplet() {
|
||||
return new AppletWrapper(LAUNCH.config.getArgsAsMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indev load level injection
|
||||
*/
|
||||
public static File getLevelFile(int index) {
|
||||
return new File(LAUNCH.config.gameDir.get(), "levels/level" + index + ".dat");
|
||||
}
|
||||
public static AppletWrapper getApplet() {
|
||||
return new AppletWrapper(LAUNCH.config.getArgsAsMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Indev save level injection
|
||||
*/
|
||||
public static File saveLevel(int index, String levelName) {
|
||||
final int maxLevels = 5;
|
||||
/**
|
||||
* Indev load level injection
|
||||
*/
|
||||
public static File getLevelFile(int index) {
|
||||
return new File(LAUNCH.config.gameDir.get(), "levels/level" + index + ".dat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indev save level injection
|
||||
*/
|
||||
public static File saveLevel(int index, String levelName) {
|
||||
final int maxLevels = 5;
|
||||
File levels = new File(LAUNCH.config.gameDir.get(), "levels");
|
||||
File level = new File(levels, "level" + index + ".dat");
|
||||
File levelNames = new File(levels, "levels.txt");
|
||||
|
@ -77,33 +77,30 @@ public class Inject {
|
|||
return null;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuffer loadIcon(BufferedImage icon) {
|
||||
final int[] rgb = icon.getRGB(0, 0, icon.getWidth(), icon.getHeight(), null, 0, icon.getWidth());
|
||||
public static ByteBuffer loadIcon(BufferedImage icon) {
|
||||
final int[] rgb = icon.getRGB(0, 0, icon.getWidth(), icon.getHeight(), null, 0, icon.getWidth());
|
||||
|
||||
final ByteBuffer buffer = ByteBuffer.allocate(4 * rgb.length);
|
||||
for (int color : rgb) {
|
||||
buffer.putInt(color << 8 | ((color >> 24) & 0xFF));
|
||||
}
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
final ByteBuffer buffer = ByteBuffer.allocate(4 * rgb.length);
|
||||
for(int color : rgb) {
|
||||
buffer.putInt(color << 8 | ((color >> 24) & 0xFF));
|
||||
}
|
||||
buffer.flip();
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static ByteBuffer[] loadDefaultIcon(boolean grassBlock) {
|
||||
if(!grassBlock) {
|
||||
try {
|
||||
return new ByteBuffer[] { loadIcon("/icon_16x16.png"), loadIcon("/icon_32x32.png") };
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return new ByteBuffer[] { loadIcon(DEFAULT_ICON) };
|
||||
}
|
||||
|
||||
public static ByteBuffer[] loadDefaultIcon(boolean grassBlock) {
|
||||
if(!grassBlock) {
|
||||
try {
|
||||
return new ByteBuffer[] {
|
||||
loadIcon("/icon_16x16.png"),
|
||||
loadIcon("/icon_32x32.png")
|
||||
};
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return new ByteBuffer[] { loadIcon(DEFAULT_ICON) };
|
||||
}
|
||||
|
||||
public static ByteBuffer[] loadIcons() {
|
||||
List<ByteBuffer> processedIcons = new ArrayList<ByteBuffer>();
|
||||
for(File icon : LAUNCH.config.icon.get()) {
|
||||
|
@ -118,7 +115,7 @@ public class Inject {
|
|||
}
|
||||
return processedIcons.toArray(new ByteBuffer[0]);
|
||||
}
|
||||
|
||||
|
||||
public static ByteBuffer[] loadIcon(File icon) {
|
||||
try {
|
||||
return new ByteBuffer[] { loadIcon(ImageIO.read(icon)) };
|
||||
|
@ -126,11 +123,11 @@ public class Inject {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static ByteBuffer loadIcon(String icon) throws IOException {
|
||||
return loadIcon(ImageIO.read(Inject.class.getResourceAsStream(icon)));
|
||||
}
|
||||
|
||||
|
||||
public static BufferedImage getIcon() {
|
||||
if(DEFAULT_ICON != null) {
|
||||
return DEFAULT_ICON;
|
||||
|
|
|
@ -15,11 +15,11 @@ public class InjectUtils {
|
|||
PRIVATE, DEFAULT, PROTECTED, PUBLIC;
|
||||
|
||||
public static Access getFromBytecode(int acc) {
|
||||
if ((acc & ACC_PRIVATE) == ACC_PRIVATE)
|
||||
if((acc & ACC_PRIVATE) == ACC_PRIVATE)
|
||||
return PRIVATE;
|
||||
if ((acc & ACC_PROTECTED) == ACC_PROTECTED)
|
||||
if((acc & ACC_PROTECTED) == ACC_PROTECTED)
|
||||
return PROTECTED;
|
||||
if ((acc & ACC_PUBLIC) == ACC_PUBLIC)
|
||||
if((acc & ACC_PUBLIC) == ACC_PUBLIC)
|
||||
return PUBLIC;
|
||||
return DEFAULT;
|
||||
}
|
||||
|
@ -32,25 +32,25 @@ public class InjectUtils {
|
|||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static FieldNode getField(ClassNode node, String name, String desc) {
|
||||
for(FieldNode field : node.fields) {
|
||||
if(field.name.equals(name) && field.desc.equals(desc)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
for(FieldNode field : node.fields) {
|
||||
if(field.name.equals(name) && field.desc.equals(desc)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MethodNode getMethod(ClassNode node, String name, String desc) {
|
||||
for(MethodNode method : node.methods) {
|
||||
if(method.name.equals(name) && method.desc.equals(desc)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
for(MethodNode method : node.methods) {
|
||||
if(method.name.equals(name) && method.desc.equals(desc)) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static List<MethodNode> getConstructors(ClassNode node) {
|
||||
List<MethodNode> constructors = new ArrayList<MethodNode>();
|
||||
for(MethodNode method : node.methods) {
|
||||
|
@ -60,15 +60,15 @@ public class InjectUtils {
|
|||
}
|
||||
return constructors;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isAbstract(MethodNode method) {
|
||||
return (method.access & ACC_ABSTRACT) != 0;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isStatic(MethodNode method) {
|
||||
return (method.access & ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isStatic(FieldNode field) {
|
||||
return (field.access & ACC_STATIC) != 0;
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ public class InsnHelper {
|
|||
}
|
||||
|
||||
public static InsnList copyInsns(InsnList insnList) {
|
||||
MethodNode mv = new MethodNode();
|
||||
insnList.accept(mv);
|
||||
return mv.instructions;
|
||||
MethodNode mv = new MethodNode();
|
||||
insnList.accept(mv);
|
||||
return mv.instructions;
|
||||
}
|
||||
|
||||
public static void removeRange(InsnList insns, AbstractInsnNode first, AbstractInsnNode last) {
|
||||
|
@ -56,25 +56,25 @@ public class InsnHelper {
|
|||
|
||||
public static AbstractInsnNode intInsn(int value) {
|
||||
switch(value) {
|
||||
case -1:
|
||||
return new InsnNode(ICONST_M1);
|
||||
case 0:
|
||||
return new InsnNode(ICONST_0);
|
||||
case 1:
|
||||
return new InsnNode(ICONST_1);
|
||||
case 2:
|
||||
return new InsnNode(ICONST_2);
|
||||
case 3:
|
||||
return new InsnNode(ICONST_3);
|
||||
case 4:
|
||||
return new InsnNode(ICONST_4);
|
||||
case 5:
|
||||
return new InsnNode(ICONST_5);
|
||||
default:
|
||||
if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
return new IntInsnNode(SIPUSH, value);
|
||||
}
|
||||
return new LdcInsnNode(value);
|
||||
case -1:
|
||||
return new InsnNode(ICONST_M1);
|
||||
case 0:
|
||||
return new InsnNode(ICONST_0);
|
||||
case 1:
|
||||
return new InsnNode(ICONST_1);
|
||||
case 2:
|
||||
return new InsnNode(ICONST_2);
|
||||
case 3:
|
||||
return new InsnNode(ICONST_3);
|
||||
case 4:
|
||||
return new InsnNode(ICONST_4);
|
||||
case 5:
|
||||
return new InsnNode(ICONST_5);
|
||||
default:
|
||||
if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
return new IntInsnNode(SIPUSH, value);
|
||||
}
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,14 +85,11 @@ public class InsnHelper {
|
|||
public static AbstractInsnNode floatInsn(float value) {
|
||||
if(value == 0F) {
|
||||
return new InsnNode(FCONST_0);
|
||||
}
|
||||
else if(value == 1F) {
|
||||
} else if(value == 1F) {
|
||||
return new InsnNode(FCONST_1);
|
||||
}
|
||||
else if(value == 2F) {
|
||||
} else if(value == 2F) {
|
||||
return new InsnNode(FCONST_2);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
@ -100,11 +97,9 @@ public class InsnHelper {
|
|||
public static AbstractInsnNode doubleInsn(double value) {
|
||||
if(value == 0D) {
|
||||
return new InsnNode(DCONST_0);
|
||||
}
|
||||
else if(value == 1D) {
|
||||
} else if(value == 1D) {
|
||||
return new InsnNode(DCONST_1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +112,7 @@ public class InsnHelper {
|
|||
current = current.getPrevious();
|
||||
}
|
||||
if(current.getType() == LABEL) {
|
||||
return (LabelNode)current;
|
||||
return (LabelNode) current;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -136,8 +131,7 @@ public class InsnHelper {
|
|||
AbstractInsnNode insn = first;
|
||||
while(insn != null) {
|
||||
AbstractInsnNode prev = insn.getPrevious();
|
||||
if(prev != null && prev.getOpcode() == ALOAD && ((VarInsnNode)prev).var == 0
|
||||
&& insn.getOpcode() == INVOKESPECIAL && ((MethodInsnNode)insn).name.equals("<init>")) {
|
||||
if(prev != null && prev.getOpcode() == ALOAD && ((VarInsnNode) prev).var == 0 && insn.getOpcode() == INVOKESPECIAL && ((MethodInsnNode) insn).name.equals("<init>")) {
|
||||
break;
|
||||
}
|
||||
insn = insn.getNext();
|
||||
|
@ -157,19 +151,13 @@ public class InsnHelper {
|
|||
}
|
||||
|
||||
public static boolean isReturn(int opcode) {
|
||||
return
|
||||
opcode == RETURN ||
|
||||
opcode == IRETURN ||
|
||||
opcode == LRETURN ||
|
||||
opcode == FRETURN ||
|
||||
opcode == DRETURN ||
|
||||
opcode == ARETURN;
|
||||
return opcode == RETURN || opcode == IRETURN || opcode == LRETURN || opcode == FRETURN || opcode == DRETURN || opcode == ARETURN;
|
||||
}
|
||||
|
||||
public static boolean containsInvoke(InsnList insns, MethodInsnNode invoke) {
|
||||
for(AbstractInsnNode insn : insns) {
|
||||
if(insn.getType() == METHOD_INSN) {
|
||||
MethodInsnNode invoke2 = (MethodInsnNode)insn;
|
||||
MethodInsnNode invoke2 = (MethodInsnNode) insn;
|
||||
if(invoke2.getOpcode() == invoke.getOpcode() && invoke2.owner.equals(invoke.owner) && invoke2.name.equals(invoke.name) && invoke2.desc.equals(invoke.desc)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -212,7 +200,7 @@ public class InsnHelper {
|
|||
AbstractInsnNode insn = instructions.getFirst();
|
||||
while(insn != null) {
|
||||
if(insn.getType() == VAR_INSN) {
|
||||
VarInsnNode var = (VarInsnNode)insn;
|
||||
VarInsnNode var = (VarInsnNode) insn;
|
||||
lastFree = Math.max(lastFree, var.var + 1);
|
||||
}
|
||||
insn = insn.getNext();
|
||||
|
@ -220,42 +208,42 @@ public class InsnHelper {
|
|||
return lastFree;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static boolean compareInsn(AbstractInsnNode insn, int opcode, Object... compare) {
|
||||
if(insn == null) {
|
||||
return false;
|
||||
}
|
||||
boolean opcodeEqual = opcode == insn.getOpcode() || opcode == -1;
|
||||
if(!opcodeEqual) return false;
|
||||
if(!opcodeEqual)
|
||||
return false;
|
||||
if(compare.length == 0 && opcodeEqual) {
|
||||
return true;
|
||||
}
|
||||
boolean matches = true;
|
||||
switch(insn.getType()) {
|
||||
case INSN:
|
||||
InsnNode insn1 = (InsnNode)insn;
|
||||
InsnNode insn1 = (InsnNode) insn;
|
||||
// Nothing to compare
|
||||
return matches;
|
||||
case INT_INSN:
|
||||
IntInsnNode insn2 = (IntInsnNode)insn;
|
||||
IntInsnNode insn2 = (IntInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= insn2.operand == (Integer)compare[0];
|
||||
matches &= insn2.operand == (Integer) compare[0];
|
||||
}
|
||||
return matches;
|
||||
case VAR_INSN:
|
||||
VarInsnNode insn3 = (VarInsnNode)insn;
|
||||
VarInsnNode insn3 = (VarInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= insn3.var == (Integer)compare[0];
|
||||
matches &= insn3.var == (Integer) compare[0];
|
||||
}
|
||||
return matches;
|
||||
case TYPE_INSN:
|
||||
TypeInsnNode insn4 = (TypeInsnNode)insn;
|
||||
TypeInsnNode insn4 = (TypeInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= insn4.desc.equals(compare[0]);
|
||||
}
|
||||
return matches;
|
||||
case FIELD_INSN:
|
||||
FieldInsnNode insn5 = (FieldInsnNode)insn;
|
||||
FieldInsnNode insn5 = (FieldInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= compare[0] == null || insn5.owner.equals(compare[0]);
|
||||
}
|
||||
|
@ -267,7 +255,7 @@ public class InsnHelper {
|
|||
}
|
||||
return matches;
|
||||
case METHOD_INSN:
|
||||
MethodInsnNode insn6 = (MethodInsnNode)insn;
|
||||
MethodInsnNode insn6 = (MethodInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= compare[0] == null || insn6.owner.equals(compare[0]);
|
||||
}
|
||||
|
@ -279,9 +267,9 @@ public class InsnHelper {
|
|||
}
|
||||
return matches;
|
||||
case INVOKE_DYNAMIC_INSN:
|
||||
InvokeDynamicInsnNode insn7 = (InvokeDynamicInsnNode)insn;
|
||||
InvokeDynamicInsnNode insn7 = (InvokeDynamicInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= compare[0] == null || insn7.bsm.equals(compare[0]); //TODO ?
|
||||
matches &= compare[0] == null || insn7.bsm.equals(compare[0]); // TODO ?
|
||||
}
|
||||
if(compare.length > 1) {
|
||||
matches &= compare[1] == null || insn7.name.equals(compare[1]);
|
||||
|
@ -291,63 +279,63 @@ public class InsnHelper {
|
|||
}
|
||||
return matches;
|
||||
case JUMP_INSN:
|
||||
JumpInsnNode insn8 = (JumpInsnNode)insn;
|
||||
JumpInsnNode insn8 = (JumpInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
LabelNode label = (LabelNode)compare[0];
|
||||
LabelNode label = (LabelNode) compare[0];
|
||||
matches &= label == insn8.label;
|
||||
}
|
||||
return matches;
|
||||
case LABEL:
|
||||
LabelNode insn9 = (LabelNode)insn;
|
||||
//TODO
|
||||
LabelNode insn9 = (LabelNode) insn;
|
||||
// TODO
|
||||
return matches;
|
||||
case LDC_INSN:
|
||||
LdcInsnNode insn10 = (LdcInsnNode)insn;
|
||||
LdcInsnNode insn10 = (LdcInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
Object o = compare[0];
|
||||
matches &= o == null && insn10.cst == null || o != null && o.equals(insn10.cst);
|
||||
}
|
||||
return matches;
|
||||
case IINC_INSN:
|
||||
IincInsnNode insn11 = (IincInsnNode)insn;
|
||||
IincInsnNode insn11 = (IincInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
Integer i = (Integer)compare[0];
|
||||
Integer i = (Integer) compare[0];
|
||||
matches &= i == null || insn11.var == i;
|
||||
}
|
||||
if(compare.length > 1) {
|
||||
Integer i = (Integer)compare[1];
|
||||
Integer i = (Integer) compare[1];
|
||||
matches &= i == null || insn11.incr == i;
|
||||
}
|
||||
return matches;
|
||||
case TABLESWITCH_INSN:
|
||||
TableSwitchInsnNode insn12 = (TableSwitchInsnNode)insn;
|
||||
TableSwitchInsnNode insn12 = (TableSwitchInsnNode) insn;
|
||||
// TODO
|
||||
return matches;
|
||||
case LOOKUPSWITCH_INSN:
|
||||
LookupSwitchInsnNode insn13 = (LookupSwitchInsnNode)insn;
|
||||
LookupSwitchInsnNode insn13 = (LookupSwitchInsnNode) insn;
|
||||
// TODO
|
||||
return matches;
|
||||
case MULTIANEWARRAY_INSN:
|
||||
MultiANewArrayInsnNode insn14 = (MultiANewArrayInsnNode)insn;
|
||||
MultiANewArrayInsnNode insn14 = (MultiANewArrayInsnNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= compare[0] == null || insn14.desc.equals(compare[0]);
|
||||
}
|
||||
if(compare.length > 1) {
|
||||
Integer i = (Integer)compare[0];
|
||||
Integer i = (Integer) compare[0];
|
||||
matches &= i == null || insn14.dims == i;
|
||||
}
|
||||
return matches;
|
||||
case FRAME:
|
||||
FrameNode insn15 = (FrameNode)insn;
|
||||
FrameNode insn15 = (FrameNode) insn;
|
||||
// TODO
|
||||
return matches;
|
||||
case LINE:
|
||||
LineNumberNode insn16 = (LineNumberNode)insn;
|
||||
LineNumberNode insn16 = (LineNumberNode) insn;
|
||||
if(compare.length > 0) {
|
||||
matches &= insn16.line == (Integer)compare[0];
|
||||
matches &= insn16.line == (Integer) compare[0];
|
||||
}
|
||||
return matches;
|
||||
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -65,13 +65,13 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
|||
name = className(name);
|
||||
Class<?> cls = exceptions.get(name);
|
||||
if(cls != null) {
|
||||
return cls;
|
||||
return cls;
|
||||
}
|
||||
cls = transformedClass(name);
|
||||
if(cls != null) {
|
||||
return cls;
|
||||
return cls;
|
||||
}
|
||||
throw new ClassNotFoundException(name);
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
|
||||
public void invokeMain(String launchTarget, String... args) {
|
||||
|
@ -89,36 +89,41 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
|||
|
||||
protected Class<?> redefineClass(String name) {
|
||||
byte[] classData = getClassAsBytes(name);
|
||||
if(classData == null) return null;
|
||||
if(classData == null)
|
||||
return null;
|
||||
System.out.println(name);
|
||||
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));
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
URLConnection urlConnection;
|
||||
final URL resource = parent.getResource(classResourceName(name));
|
||||
if(resource == null) {
|
||||
return null;
|
||||
}
|
||||
URLConnection urlConnection;
|
||||
try {
|
||||
urlConnection = resource.openConnection();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
CodeSource codeSource = urlConnection == null ? null : new CodeSource(urlConnection.getURL(), new Certificate[0]);
|
||||
CodeSource codeSource = urlConnection == null ? null : new CodeSource(urlConnection.getURL(), new Certificate[0]);
|
||||
return new ProtectionDomain(codeSource, null);
|
||||
}
|
||||
|
||||
public void overrideClass(ClassNode node) {
|
||||
if(node == null) return;
|
||||
if(node == null)
|
||||
return;
|
||||
overridenClasses.put(className(node.name), node);
|
||||
classNodeCache.put(node.name, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name can be specified either as net.minecraft.client.Minecraft or as net/minecraft/client/Minecraft
|
||||
* @param name
|
||||
* can be specified either as net.minecraft.client.Minecraft or as
|
||||
* net/minecraft/client/Minecraft
|
||||
* @return parsed ClassNode
|
||||
*/
|
||||
public ClassNode getClass(String name) {
|
||||
|
@ -127,20 +132,21 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
|||
return node;
|
||||
}
|
||||
byte[] classData = getClassAsBytes(name);
|
||||
if(classData == null) return null;
|
||||
if(classData == null)
|
||||
return null;
|
||||
ClassNode classNode = new ClassNode();
|
||||
ClassReader classReader = new ClassReader(classData);
|
||||
classReader.accept(classNode, 0);
|
||||
classNodeCache.put(classNode.name, classNode);
|
||||
return classNode;
|
||||
ClassReader classReader = new ClassReader(classData);
|
||||
classReader.accept(classNode, 0);
|
||||
classNodeCache.put(classNode.name, classNode);
|
||||
return classNode;
|
||||
}
|
||||
|
||||
public FieldNode getField(String owner, String name, String desc) {
|
||||
return InjectUtils.getField(getClass(owner), name, desc);
|
||||
return InjectUtils.getField(getClass(owner), name, desc);
|
||||
}
|
||||
|
||||
public MethodNode getMethod(String owner, String name, String desc) {
|
||||
return InjectUtils.getMethod(getClass(owner), name, desc);
|
||||
return InjectUtils.getMethod(getClass(owner), name, desc);
|
||||
}
|
||||
|
||||
private Class<?> redefineClass(ClassNode node) {
|
||||
|
@ -168,17 +174,18 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
|||
}
|
||||
|
||||
private byte[] getClassAsBytes(String name) {
|
||||
InputStream is = parent.getResourceAsStream(classResourceName(name));
|
||||
if(is == null) return null;
|
||||
byte[] classData;
|
||||
InputStream is = parent.getResourceAsStream(classResourceName(name));
|
||||
if(is == null)
|
||||
return null;
|
||||
byte[] classData;
|
||||
try {
|
||||
classData = Util.readStream(is);
|
||||
} catch (IOException e) {
|
||||
Util.closeSilently(is);
|
||||
Util.closeSilently(is);
|
||||
return null;
|
||||
}
|
||||
Util.closeSilently(is);
|
||||
return classData;
|
||||
Util.closeSilently(is);
|
||||
return classData;
|
||||
}
|
||||
|
||||
private Class<?> transformedClass(String name) {
|
||||
|
@ -188,11 +195,11 @@ public class LaunchClassLoader extends ClassLoader implements ClassNodeSource {
|
|||
}
|
||||
ClassNode transformed = overridenClasses.get(name);
|
||||
if(transformed != null) {
|
||||
return redefineClass(transformed);
|
||||
return redefineClass(transformed);
|
||||
}
|
||||
return redefineClass(name);
|
||||
return redefineClass(name);
|
||||
}
|
||||
|
||||
|
||||
public void addException(Class<?> cls) {
|
||||
exceptions.put(cls.getName(), cls);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ import org.objectweb.asm.ClassWriter;
|
|||
|
||||
public class SafeClassWriter extends ClassWriter {
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
|
||||
public SafeClassWriter(final int flags) {
|
||||
this(null, flags);
|
||||
}
|
||||
|
||||
|
||||
public SafeClassWriter(ClassLoader parent, int flags) {
|
||||
this(parent, null, flags);
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ public class SafeClassWriter extends ClassWriter {
|
|||
super(classReader, flags);
|
||||
classLoader = parent == null ? ClassLoader.getSystemClassLoader() : parent;
|
||||
}
|
||||
|
||||
protected ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@ public class BasicResponseURLConnection extends HttpURLConnection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {}
|
||||
public void connect() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {}
|
||||
public void disconnect() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usingProxy() {
|
||||
|
@ -35,8 +37,8 @@ public class BasicResponseURLConnection extends HttpURLConnection {
|
|||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(responseMessage.getBytes());
|
||||
}
|
||||
|
||||
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ import java.net.URL;
|
|||
import java.net.URLConnection;
|
||||
|
||||
public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
|
||||
|
||||
|
||||
private SkinType skins;
|
||||
private int port;
|
||||
|
||||
|
||||
public LegacyURLStreamHandler(SkinType skins, int port) {
|
||||
this.skins = skins;
|
||||
this.port = port;
|
||||
|
@ -19,47 +19,46 @@ public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
|
|||
String host = url.getHost();
|
||||
String path = url.getPath();
|
||||
if(host.endsWith(".minecraft.net") || host.equals("s3.amazonaws.com")) {
|
||||
if (path.equals("/game/joinserver.jsp"))
|
||||
if(path.equals("/game/joinserver.jsp"))
|
||||
return new BasicResponseURLConnection(url, "ok");
|
||||
else if (path.equals("/login/session.jsp"))
|
||||
else if(path.equals("/login/session.jsp"))
|
||||
return new BasicResponseURLConnection(url, "ok");
|
||||
else if (host.equals("login.minecraft.net") && path.equals("/session"))
|
||||
else if(host.equals("login.minecraft.net") && path.equals("/session"))
|
||||
return new BasicResponseURLConnection(url, "ok");
|
||||
else if (path.equals("/game/"))
|
||||
else if(path.equals("/game/"))
|
||||
return new BasicResponseURLConnection(url, "42069");
|
||||
else if (path.equals("/haspaid.jsp"))
|
||||
else if(path.equals("/haspaid.jsp"))
|
||||
return new BasicResponseURLConnection(url, "true");
|
||||
else if (path.contains("/level/save.html"))
|
||||
else if(path.contains("/level/save.html"))
|
||||
return new SaveLevelURLConnection(url);
|
||||
else if (path.contains("/level/load.html"))
|
||||
else if(path.contains("/level/load.html"))
|
||||
return new LoadLevelURLConnection(url);
|
||||
else if (path.equals("/listmaps.jsp"))
|
||||
else if(path.equals("/listmaps.jsp"))
|
||||
return new ListLevelsURLConnection(url);
|
||||
else if (path.startsWith("/MinecraftResources/") || path.startsWith("/resources/"))
|
||||
else if(path.startsWith("/MinecraftResources/") || path.startsWith("/resources/"))
|
||||
return new ResourceIndexURLConnection(url, port);
|
||||
else if (path.startsWith("/MinecraftSkins/") || path.startsWith("/skin/")
|
||||
|| path.startsWith("/MinecraftCloaks/") || path.startsWith("/cloak/"))
|
||||
else if(path.startsWith("/MinecraftSkins/") || path.startsWith("/skin/") || path.startsWith("/MinecraftCloaks/") || path.startsWith("/cloak/"))
|
||||
return new SkinURLConnection(url, skins);
|
||||
else if(host.equals("assets.minecraft.net") && path.equals("/1_6_has_been_released.flag")) {
|
||||
return new BasicResponseURLConnection(url, "");
|
||||
//return new BasicResponseURLConnection(url, "https://web.archive.org/web/20130702232237if_/https://mojang.com/2013/07/minecraft-the-horse-update/");
|
||||
// return new BasicResponseURLConnection(url, "https://web.archive.org/web/20130702232237if_/https://mojang.com/2013/07/minecraft-the-horse-update/");
|
||||
}
|
||||
}
|
||||
return super.openConnection(url);
|
||||
}
|
||||
|
||||
|
||||
public enum SkinType {
|
||||
CLASSIC("classic"),
|
||||
PRE_B1_9("pre-b1.9-pre4"),
|
||||
PRE_1_8("pre-1.8"),
|
||||
DEFAULT("default");
|
||||
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
private SkinType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public static SkinType get(String name) {
|
||||
for(SkinType skinType : values()) {
|
||||
if(skinType.name.equals(name)) {
|
||||
|
@ -69,7 +68,7 @@ public class LegacyURLStreamHandler extends URLStreamHandlerProxy {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum ResourceIndex {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,15 +13,16 @@ import org.mcphackers.launchwrapper.Launch;
|
|||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public class ListLevelsURLConnection extends URLConnection {
|
||||
|
||||
|
||||
public static final String EMPTY_LEVEL = "-";
|
||||
|
||||
|
||||
public ListLevelsURLConnection(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {}
|
||||
public void connect() throws IOException {
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
File levels = new File(Launch.INSTANCE.config.gameDir.get(), "levels");
|
||||
|
|
|
@ -26,7 +26,8 @@ public class LoadLevelURLConnection extends HttpURLConnection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {}
|
||||
public void connect() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
|
|
|
@ -9,18 +9,19 @@ import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.ResourceInde
|
|||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public class ResourceIndexURLConnection extends URLConnection {
|
||||
private static final String[] RESOURCES = new String[] {"/resources/", "/MinecraftResources/"};
|
||||
private static final String[] RESOURCES = new String[] { "/resources/", "/MinecraftResources/" };
|
||||
|
||||
ResourceIndex index = null;
|
||||
int port = -1;
|
||||
|
||||
|
||||
public ResourceIndexURLConnection(URL url, int port) {
|
||||
super(url);
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {}
|
||||
public void connect() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
|
@ -32,7 +33,7 @@ public class ResourceIndexURLConnection extends URLConnection {
|
|||
}
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
|
||||
protected int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public class SaveLevelURLConnection extends HttpURLConnection {
|
|||
|
||||
ByteArrayOutputStream levelOutput = new ByteArrayOutputStream();
|
||||
Exception exception;
|
||||
|
||||
|
||||
public SaveLevelURLConnection(URL url) {
|
||||
super(url);
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ public class SaveLevelURLConnection extends HttpURLConnection {
|
|||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
try {
|
||||
|
@ -70,12 +69,11 @@ public class SaveLevelURLConnection extends HttpURLConnection {
|
|||
if(levelName.equals("---")) {
|
||||
level.delete();
|
||||
lvlNames[levelId] = EMPTY_LEVEL;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if(!levels.exists()) {
|
||||
levels.mkdirs();
|
||||
}
|
||||
OutputStream fileOutput = new FileOutputStream(level);
|
||||
OutputStream fileOutput = new FileOutputStream(level);
|
||||
fileOutput.write(levelData);
|
||||
fileOutput.close();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.mcphackers.launchwrapper.protocol;
|
|||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
@ -19,11 +18,11 @@ public class SkinRequests {
|
|||
public static String getUUIDfromName(String username) {
|
||||
String cachedUUID = nameToUUID.get(username);
|
||||
|
||||
if (cachedUUID != null) {
|
||||
if(cachedUUID != null) {
|
||||
return cachedUUID;
|
||||
} else {
|
||||
JSONObject obj = requestUUIDfromName(username);
|
||||
if (obj != null) {
|
||||
if(obj != null) {
|
||||
String uuid = obj.optString("id");
|
||||
|
||||
nameToUUID.put(username, uuid);
|
||||
|
@ -38,7 +37,7 @@ public class SkinRequests {
|
|||
try {
|
||||
URL profileURL = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
|
||||
InputStream connStream = profileURL.openConnection().getInputStream();
|
||||
JSONObject uuidJson = new JSONObject(new String(Util.readStream(connStream), "UTF-8"));
|
||||
JSONObject uuidJson = new JSONObject(new String(Util.readStream(connStream), "UTF-8"));
|
||||
|
||||
return uuidJson;
|
||||
} catch (Throwable t) {
|
||||
|
@ -49,24 +48,24 @@ public class SkinRequests {
|
|||
|
||||
public static SkinData fetchSkin(String uuid) {
|
||||
try {
|
||||
URL uuidtoprofileURL = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid);
|
||||
URL uuidtoprofileURL = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid);
|
||||
|
||||
JSONObject profilejson = new JSONObject(new String(Util.readStream(uuidtoprofileURL.openStream()), "UTF-8"));
|
||||
String base64tex = profilejson.getJSONArray("properties").getJSONObject(0).optString("value");
|
||||
String texjsonstr = new String(Base64.decode(base64tex), "UTF-8");
|
||||
JSONObject profilejson = new JSONObject(new String(Util.readStream(uuidtoprofileURL.openStream()), "UTF-8"));
|
||||
String base64tex = profilejson.getJSONArray("properties").getJSONObject(0).optString("value");
|
||||
String texjsonstr = new String(Base64.decode(base64tex), "UTF-8");
|
||||
|
||||
JSONObject texjson = new JSONObject(texjsonstr);
|
||||
JSONObject txts = texjson.optJSONObject("textures");
|
||||
JSONObject skinjson = txts.optJSONObject("SKIN");
|
||||
String skinURLstr = skinjson.optString("url");
|
||||
JSONObject texjson = new JSONObject(texjsonstr);
|
||||
JSONObject txts = texjson.optJSONObject("textures");
|
||||
JSONObject skinjson = txts.optJSONObject("SKIN");
|
||||
String skinURLstr = skinjson.optString("url");
|
||||
|
||||
byte[] officialCape = null;
|
||||
byte[] officialSkin = null;
|
||||
|
||||
JSONObject capejson = txts.optJSONObject("CAPE");
|
||||
if (capejson != null) {
|
||||
String capeURLstr = capejson.optString("url");
|
||||
URL capeURL = new URL(capeURLstr);
|
||||
if(capejson != null) {
|
||||
String capeURLstr = capejson.optString("url");
|
||||
URL capeURL = new URL(capeURLstr);
|
||||
|
||||
officialCape = Util.readStream(capeURL.openStream());
|
||||
}
|
||||
|
@ -108,20 +107,20 @@ public class SkinRequests {
|
|||
|
||||
byte[] cape = null;
|
||||
try {
|
||||
if (skindata.cape != null) {
|
||||
if(skindata.cape != null) {
|
||||
switch(skinType) {
|
||||
case CLASSIC:
|
||||
case PRE_B1_9:
|
||||
case PRE_1_8:
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(skindata.cape);
|
||||
|
||||
ImageUtils imgu = new ImageUtils(bis);
|
||||
imgu = imgu.crop(0, 0, 64, 32);
|
||||
|
||||
cape = imgu.getInByteForm();
|
||||
break;
|
||||
case DEFAULT:
|
||||
return skindata.cape;
|
||||
case CLASSIC:
|
||||
case PRE_B1_9:
|
||||
case PRE_1_8:
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(skindata.cape);
|
||||
|
||||
ImageUtils imgu = new ImageUtils(bis);
|
||||
imgu = imgu.crop(0, 0, 64, 32);
|
||||
|
||||
cape = imgu.getInByteForm();
|
||||
break;
|
||||
case DEFAULT:
|
||||
return skindata.cape;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
|
@ -139,23 +138,23 @@ public class SkinRequests {
|
|||
|
||||
byte[] skin = null;
|
||||
try {
|
||||
if (skindata.skin != null) {
|
||||
if(skindata.skin != null) {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(skindata.skin);
|
||||
ImageUtils imgu = new ImageUtils(bis);
|
||||
|
||||
switch(skinType) {
|
||||
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);
|
||||
imgu = imgu.crop(0, 0, 64, 32);
|
||||
case DEFAULT:
|
||||
break;
|
||||
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);
|
||||
imgu = imgu.crop(0, 0, 64, 32);
|
||||
case DEFAULT:
|
||||
break;
|
||||
}
|
||||
skin = imgu.getInByteForm();
|
||||
}
|
||||
|
|
|
@ -11,13 +11,13 @@ import org.mcphackers.launchwrapper.protocol.LegacyURLStreamHandler.SkinType;
|
|||
import org.mcphackers.launchwrapper.util.Util;
|
||||
|
||||
public class SkinURLConnection extends HttpURLConnection {
|
||||
|
||||
private static final String[] CLOAKS = {"/cloak/", "/MinecraftCloaks/"};
|
||||
private static final String[] SKINS = {"/skin/", "/MinecraftSkins/"};
|
||||
|
||||
|
||||
private static final String[] CLOAKS = { "/cloak/", "/MinecraftCloaks/" };
|
||||
private static final String[] SKINS = { "/skin/", "/MinecraftSkins/" };
|
||||
|
||||
protected SkinType skinType;
|
||||
protected InputStream inputStream;
|
||||
|
||||
|
||||
public SkinURLConnection(URL url, SkinType skin) {
|
||||
super(url);
|
||||
responseCode = 200;
|
||||
|
@ -25,7 +25,8 @@ public class SkinURLConnection extends HttpURLConnection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {}
|
||||
public void disconnect() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usingProxy() {
|
||||
|
@ -38,8 +39,8 @@ public class SkinURLConnection extends HttpURLConnection {
|
|||
String username = queryMap.get("user");
|
||||
String path = url.getPath();
|
||||
|
||||
for (String template : CLOAKS) {
|
||||
if (path.startsWith(template)) {
|
||||
for(String template : CLOAKS) {
|
||||
if(path.startsWith(template)) {
|
||||
if(username == null)
|
||||
username = path.substring(template.length()).replace(".png", "");
|
||||
byte[] skinData = SkinRequests.getCape(username, skinType);
|
||||
|
@ -50,8 +51,8 @@ public class SkinURLConnection extends HttpURLConnection {
|
|||
}
|
||||
}
|
||||
|
||||
for (String template : SKINS) {
|
||||
if (path.startsWith(template)) {
|
||||
for(String template : SKINS) {
|
||||
if(path.startsWith(template)) {
|
||||
if(username == null)
|
||||
username = path.substring(template.length()).replace(".png", "");
|
||||
byte[] skinData = SkinRequests.getSkin(username, skinType);
|
||||
|
@ -68,4 +69,4 @@ public class SkinURLConnection extends HttpURLConnection {
|
|||
public InputStream getInputStream() throws IOException {
|
||||
return inputStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ import org.mcphackers.launchwrapper.util.Util;
|
|||
|
||||
public abstract class URLStreamHandlerProxy extends URLStreamHandler {
|
||||
private static final Map<String, URLStreamHandler> DEFAULT_HANDLERS = new HashMap<String, URLStreamHandler>();
|
||||
|
||||
|
||||
protected URLStreamHandler parent;
|
||||
|
||||
|
||||
@Override
|
||||
protected final URLConnection openConnection(URL url, Proxy p) throws IOException {
|
||||
return openConnection(url);
|
||||
}
|
||||
|
||||
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
if(parent == null) {
|
||||
return null;
|
||||
|
@ -34,27 +34,27 @@ public abstract class URLStreamHandlerProxy extends URLStreamHandler {
|
|||
handler.parent = getURLStreamHandler(protocol);
|
||||
try {
|
||||
Field handlersField = URL.class.getDeclaredField("handlers");
|
||||
Hashtable handlers = (Hashtable)Util.getStaticObjectUnsafe(handlersField);
|
||||
Hashtable handlers = (Hashtable) Util.getStaticObjectUnsafe(handlersField);
|
||||
handlers.put(protocol, handler);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static URLStreamHandler getURLStreamHandler(String protocol) {
|
||||
URLStreamHandler handler = DEFAULT_HANDLERS.get(protocol);
|
||||
if(handler != null) {
|
||||
return handler;
|
||||
}
|
||||
try {
|
||||
URL url = new URL(protocol + ":");
|
||||
Field handlerField = URL.class.getDeclaredField("handler");
|
||||
handler = (URLStreamHandler)Util.getObjectUnsafe(url, handlerField);
|
||||
DEFAULT_HANDLERS.put(protocol, handler);
|
||||
return handler;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
URL url = new URL(protocol + ":");
|
||||
Field handlerField = URL.class.getDeclaredField("handler");
|
||||
handler = (URLStreamHandler) Util.getObjectUnsafe(url, handlerField);
|
||||
DEFAULT_HANDLERS.put(protocol, handler);
|
||||
return handler;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,53 +15,53 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
|
||||
public class AppletWrapper extends Applet implements AppletStub {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Map<String, String> args;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AppletWrapper(Map<String, String> argsAsMap) {
|
||||
args = argsAsMap;
|
||||
private Map<String, String> args;
|
||||
|
||||
public AppletWrapper(Map<String, String> argsAsMap) {
|
||||
args = argsAsMap;
|
||||
}
|
||||
|
||||
public void appletResize(int width, int height) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getDocumentBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public URL getDocumentBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getCodeBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public URL getCodeBase() {
|
||||
try {
|
||||
return new URL("http://www.minecraft.net/game/");
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameter(String paramName) {
|
||||
return args.get(paramName);
|
||||
}
|
||||
|
||||
public static void startApplet(Class<? extends Applet> appletClass, int width, int height, String title) {
|
||||
startApplet(appletClass, width, height, title, null);
|
||||
}
|
||||
|
||||
public static void startApplet(Class<? extends Applet> appletClass, int width, int height, String title, Image icon) {
|
||||
try {
|
||||
@Override
|
||||
public String getParameter(String paramName) {
|
||||
return args.get(paramName);
|
||||
}
|
||||
|
||||
public static void startApplet(Class<? extends Applet> appletClass, int width, int height, String title) {
|
||||
startApplet(appletClass, width, height, title, null);
|
||||
}
|
||||
|
||||
public static void startApplet(Class<? extends Applet> appletClass, int width, int height, String title, Image icon) {
|
||||
try {
|
||||
final Applet applet = appletClass.newInstance();
|
||||
if(applet != null) {
|
||||
applet.setStub(new AppletWrapper(Collections.<String, String>emptyMap()));
|
||||
|
@ -82,8 +82,8 @@ public class AppletWrapper extends Applet implements AppletStub {
|
|||
}
|
||||
});
|
||||
applet.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
};
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} ;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public class IsomTweak extends LegacyTweak {
|
|||
public IsomTweak(ClassNodeSource source, LaunchConfig launch) {
|
||||
super(source, launch);
|
||||
}
|
||||
|
||||
|
||||
protected void init() {
|
||||
super.init();
|
||||
isomApplet = source.getClass(MAIN_ISOM);
|
||||
|
@ -70,7 +70,7 @@ public class IsomTweak extends LegacyTweak {
|
|||
source.overrideClass(isomCanvas);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public LaunchTarget getLaunchTarget(LaunchClassLoader loader) {
|
||||
if(isomApplet != null) {
|
||||
AppletLaunchTarget launchTarget = new AppletLaunchTarget(loader, isomApplet.name);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -8,15 +8,15 @@ import org.mcphackers.launchwrapper.loader.LaunchClassLoader;
|
|||
public abstract class Tweak {
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
|
||||
protected ClassNodeSource source;
|
||||
|
||||
|
||||
public Tweak(ClassNodeSource source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public abstract boolean transform();
|
||||
|
||||
|
||||
public abstract LaunchTarget getLaunchTarget(LaunchClassLoader loader);
|
||||
|
||||
public static Tweak get(LaunchClassLoader classLoader, LaunchConfig launch) {
|
||||
|
@ -38,7 +38,7 @@ public abstract class Tweak {
|
|||
}
|
||||
return null; // Tweak not found
|
||||
}
|
||||
|
||||
|
||||
protected void debugInfo(String msg) {
|
||||
if(DEBUG)
|
||||
System.out.println("TWEAK: " + msg);
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.objectweb.asm.tree.*;
|
|||
|
||||
public class VanillaTweak extends Tweak {
|
||||
public static final String MAIN_CLASS = "net/minecraft/client/main/Main";
|
||||
|
||||
|
||||
protected LaunchConfig launch;
|
||||
protected ClassNode minecraftMain;
|
||||
protected ClassNode minecraft;
|
||||
|
@ -37,12 +37,13 @@ public class VanillaTweak extends Tweak {
|
|||
public boolean transform() {
|
||||
minecraftMain = source.getClass(MAIN_CLASS);
|
||||
MethodNode main = InjectUtils.getMethod(minecraftMain, "main", "([Ljava/lang/String;)V");
|
||||
if(main == null) return false;
|
||||
if(main == null)
|
||||
return false;
|
||||
AbstractInsnNode insn = main.instructions.getLast();
|
||||
while(insn != null) {
|
||||
// Last call inside of main is minecraft.run();
|
||||
if(insn.getOpcode() == INVOKEVIRTUAL) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)insn;
|
||||
MethodInsnNode invoke = (MethodInsnNode) insn;
|
||||
minecraft = source.getClass(invoke.owner);
|
||||
run = InjectUtils.getMethod(minecraft, invoke.name, invoke.desc);
|
||||
debugInfo(minecraft.name + "." + invoke.name + invoke.desc + " is Minecraft.run()");
|
||||
|
@ -53,9 +54,9 @@ public class VanillaTweak extends Tweak {
|
|||
for(AbstractInsnNode insn2 = main.instructions.getFirst(); insn2 != null; insn2 = nextInsn(insn2)) {
|
||||
if(compareInsn(insn2, INVOKEVIRTUAL, "joptsimple/OptionParser", "accepts", "(Ljava/lang/String;)Ljoptsimple/OptionSpecBuilder;")) {
|
||||
if(insn2.getPrevious() != null && insn2.getPrevious().getType() == AbstractInsnNode.LDC_INSN) {
|
||||
LdcInsnNode ldc = (LdcInsnNode)insn2.getPrevious();
|
||||
LdcInsnNode ldc = (LdcInsnNode) insn2.getPrevious();
|
||||
if(ldc.cst instanceof String) {
|
||||
availableParameters.add((String)ldc.cst);
|
||||
availableParameters.add((String) ldc.cst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,60 +76,58 @@ public class VanillaTweak extends Tweak {
|
|||
MethodNode init = getInit(run);
|
||||
boolean fixedTitle = replaceTitle(init);
|
||||
boolean fixedIcon = replaceIcon(init);
|
||||
for(MethodNode m : minecraft.methods) {
|
||||
if(!fixedTitle) {
|
||||
fixedTitle = replaceTitle(m);
|
||||
}
|
||||
if(!fixedIcon) {
|
||||
fixedIcon = replaceIcon(m);
|
||||
}
|
||||
if(fixedTitle && fixedIcon) {
|
||||
break;
|
||||
}
|
||||
for(MethodNode m : minecraft.methods) {
|
||||
if(!fixedTitle) {
|
||||
fixedTitle = replaceTitle(m);
|
||||
}
|
||||
if(!fixedIcon) {
|
||||
fixedIcon = replaceIcon(m);
|
||||
}
|
||||
if(fixedTitle && fixedIcon) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
source.overrideClass(minecraft);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private boolean replaceTitle(MethodNode m) {
|
||||
AbstractInsnNode insn = m.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fill(insn, 2);
|
||||
if(compareInsn(insns[0], LDC)
|
||||
&& compareInsn(insns[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "setTitle", "(Ljava/lang/String;)V")) {
|
||||
LdcInsnNode ldc = (LdcInsnNode)insn;
|
||||
if(ldc.cst instanceof String) {
|
||||
if(launch.title.get() != null) {
|
||||
debugInfo("Replaced title");
|
||||
ldc.cst = launch.title.get();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(compareInsn(insns[0], LDC) && compareInsn(insns[1], INVOKESTATIC, "org/lwjgl/opengl/Display", "setTitle", "(Ljava/lang/String;)V")) {
|
||||
LdcInsnNode ldc = (LdcInsnNode) insn;
|
||||
if(ldc.cst instanceof String) {
|
||||
if(launch.title.get() != null) {
|
||||
debugInfo("Replaced title");
|
||||
ldc.cst = launch.title.get();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean replaceIcon(MethodNode m) {
|
||||
AbstractInsnNode insn = m.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
if(launch.icon.get() != null && hasIcon(launch.icon.get())
|
||||
&& compareInsn(insn, INVOKESTATIC, "org/lwjgl/opengl/Display", "setIcon", "([Ljava/nio/ByteBuffer;)I")) {
|
||||
IdentifyCall call = new IdentifyCall((MethodInsnNode)insn);
|
||||
for(AbstractInsnNode[] arg : call.getArguments()) {
|
||||
remove(m.instructions, arg);
|
||||
}
|
||||
MethodInsnNode insert = new MethodInsnNode(INVOKESTATIC, "org/mcphackers/launchwrapper/inject/Inject", "loadIcons", "()[Ljava/nio/ByteBuffer;");
|
||||
m.instructions.insertBefore(insn, insert);
|
||||
debugInfo("Replaced icon");
|
||||
if(launch.icon.get() != null && hasIcon(launch.icon.get()) && compareInsn(insn, INVOKESTATIC, "org/lwjgl/opengl/Display", "setIcon", "([Ljava/nio/ByteBuffer;)I")) {
|
||||
IdentifyCall call = new IdentifyCall((MethodInsnNode) insn);
|
||||
for(AbstractInsnNode[] arg : call.getArguments()) {
|
||||
remove(m.instructions, arg);
|
||||
}
|
||||
MethodInsnNode insert = new MethodInsnNode(INVOKESTATIC, "org/mcphackers/launchwrapper/inject/Inject", "loadIcons", "()[Ljava/nio/ByteBuffer;");
|
||||
m.instructions.insertBefore(insn, insert);
|
||||
debugInfo("Replaced icon");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
insn = nextInsn(insn);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private boolean hasIcon(File[] icons) {
|
||||
for(File f : icons) {
|
||||
if(f.exists()) {
|
||||
|
@ -141,7 +140,7 @@ public class VanillaTweak extends Tweak {
|
|||
private MethodNode getInit(MethodNode run) {
|
||||
for(AbstractInsnNode insn : run.instructions) {
|
||||
if(insn.getType() == AbstractInsnNode.METHOD_INSN) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)insn;
|
||||
MethodInsnNode invoke = (MethodInsnNode) insn;
|
||||
if(invoke.owner.equals(minecraft.name)) {
|
||||
return InjectUtils.getMethod(minecraft, invoke.name, invoke.desc);
|
||||
}
|
||||
|
@ -155,14 +154,9 @@ public class VanillaTweak extends Tweak {
|
|||
AbstractInsnNode insn = m.instructions.getFirst();
|
||||
while(insn != null) {
|
||||
AbstractInsnNode[] insns = fill(insn, 6);
|
||||
if(compareInsn(insns[0], NEW, "java/io/File")
|
||||
&& compareInsn(insns[1], DUP)
|
||||
&& compareInsn(insns[2], ALOAD, 0)
|
||||
&& compareInsn(insns[3], GETFIELD, minecraft.name, null, "Ljava/io/File;")
|
||||
&& compareInsn(insns[4], LDC)
|
||||
&& compareInsn(insns[5], INVOKESPECIAL, "java/io/File", "<init>", "(Ljava/io/File;Ljava/lang/String;)V")) {
|
||||
LdcInsnNode ldc = (LdcInsnNode)insns[4];
|
||||
String s = (String)ldc.cst;
|
||||
if(compareInsn(insns[0], NEW, "java/io/File") && compareInsn(insns[1], DUP) && compareInsn(insns[2], ALOAD, 0) && compareInsn(insns[3], GETFIELD, minecraft.name, null, "Ljava/io/File;") && compareInsn(insns[4], LDC) && compareInsn(insns[5], INVOKESPECIAL, "java/io/File", "<init>", "(Ljava/io/File;Ljava/lang/String;)V")) {
|
||||
LdcInsnNode ldc = (LdcInsnNode) insns[4];
|
||||
String s = (String) ldc.cst;
|
||||
if(s.startsWith("assets/")) {
|
||||
ldc.cst = s.substring(6);
|
||||
InsnList insert = new InsnList();
|
||||
|
@ -173,7 +167,7 @@ public class VanillaTweak extends Tweak {
|
|||
m.instructions.remove(insns[2]);
|
||||
m.instructions.remove(insns[3]);
|
||||
m.instructions.insert(insns[1], insert);
|
||||
} else if (s.equals("assets")) {
|
||||
} else if(s.equals("assets")) {
|
||||
ldc.cst = assets;
|
||||
m.instructions.remove(insns[2]);
|
||||
m.instructions.remove(insns[3]);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@ import javax.imageio.ImageIO;
|
|||
|
||||
/**
|
||||
* use this for whatever you want
|
||||
*
|
||||
* @author Moresteck
|
||||
*/
|
||||
public class ImageUtils {
|
||||
|
@ -28,10 +29,10 @@ public class ImageUtils {
|
|||
int bufHeight = this.bufImg.getHeight();
|
||||
|
||||
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
for (int i = 0; i < bufWidth; i++) {
|
||||
for (int j = 0; j < bufHeight; j++) {
|
||||
if (j >= y && j < y+height && i >= x && i < x+width) {
|
||||
img.setRGB(i-x, j-y, pixels[i][j]);
|
||||
for(int i = 0; i < bufWidth; i++) {
|
||||
for(int j = 0; j < bufHeight; j++) {
|
||||
if(j >= y && j < y + height && i >= x && i < x + width) {
|
||||
img.setRGB(i - x, j - y, pixels[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,13 +48,13 @@ public class ImageUtils {
|
|||
int height = this.bufImg.getHeight();
|
||||
int[][] pixels = new int[width][height];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int j = 0; j < height; j++) {
|
||||
int pixel = this.bufImg.getRGB(i, j);
|
||||
if (j >= y && j < y+img.getHeight() && i >= x && i < x+img.getWidth()) {
|
||||
int toset = img.getRGB(i-x, j-y);
|
||||
if (!forceTransparent) {
|
||||
if ((toset>>24) != 0x00) {
|
||||
if(j >= y && j < y + img.getHeight() && i >= x && i < x + img.getWidth()) {
|
||||
int toset = img.getRGB(i - x, j - y);
|
||||
if(!forceTransparent) {
|
||||
if((toset >> 24) != 0x00) {
|
||||
pixel = toset;
|
||||
}
|
||||
} else {
|
||||
|
@ -64,8 +65,8 @@ public class ImageUtils {
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int j = 0; j < height; j++) {
|
||||
|
||||
this.bufImg.setRGB(i, j, pixels[i][j]);
|
||||
}
|
||||
|
@ -78,9 +79,9 @@ public class ImageUtils {
|
|||
int width = this.bufImg.getWidth();
|
||||
int height = this.bufImg.getHeight();
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
this.bufImg.setRGB(flipX ? width-1-i : i, flipY ? height-1-j : j, pixels[i][j]);
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int j = 0; j < height; j++) {
|
||||
this.bufImg.setRGB(flipX ? width - 1 - i : i, flipY ? height - 1 - j : j, pixels[i][j]);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
|
@ -91,8 +92,8 @@ public class ImageUtils {
|
|||
int height = this.bufImg.getHeight();
|
||||
int[][] pixels = new int[width][height];
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int j = 0; j < height; j++) {
|
||||
pixels[i][j] = this.bufImg.getRGB(i, j);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,16 +12,15 @@ import java.util.Map;
|
|||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public final class Util {
|
||||
|
||||
|
||||
private static final Unsafe theUnsafe = getUnsafe();
|
||||
|
||||
|
||||
private static Unsafe getUnsafe() {
|
||||
try {
|
||||
final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
final Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
unsafeField.setAccessible(true);
|
||||
final Unsafe unsafe = (Unsafe) unsafeField.get(null);
|
||||
return unsafe;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -30,49 +29,49 @@ public final class Util {
|
|||
}
|
||||
|
||||
public static void setStaticBooleanUnsafe(final Field field, boolean value) {
|
||||
final Object staticFieldBase = theUnsafe.staticFieldBase(field);
|
||||
final long staticFieldOffset = theUnsafe.staticFieldOffset(field);
|
||||
theUnsafe.putBoolean(staticFieldBase, staticFieldOffset, value);
|
||||
final Object staticFieldBase = theUnsafe.staticFieldBase(field);
|
||||
final long staticFieldOffset = theUnsafe.staticFieldOffset(field);
|
||||
theUnsafe.putBoolean(staticFieldBase, staticFieldOffset, value);
|
||||
}
|
||||
|
||||
public static void setStaticObjectUnsafe(final Field field, Object value) {
|
||||
final Object staticFieldBase = theUnsafe.staticFieldBase(field);
|
||||
final long staticFieldOffset = theUnsafe.staticFieldOffset(field);
|
||||
theUnsafe.putObject(staticFieldBase, staticFieldOffset, value);
|
||||
final Object staticFieldBase = theUnsafe.staticFieldBase(field);
|
||||
final long staticFieldOffset = theUnsafe.staticFieldOffset(field);
|
||||
theUnsafe.putObject(staticFieldBase, staticFieldOffset, value);
|
||||
}
|
||||
|
||||
public static Object getStaticObjectUnsafe(final Field field) {
|
||||
final Object staticFieldBase = theUnsafe.staticFieldBase(field);
|
||||
final long staticFieldOffset = theUnsafe.staticFieldOffset(field);
|
||||
return theUnsafe.getObject(staticFieldBase, staticFieldOffset);
|
||||
final Object staticFieldBase = theUnsafe.staticFieldBase(field);
|
||||
final long staticFieldOffset = theUnsafe.staticFieldOffset(field);
|
||||
return theUnsafe.getObject(staticFieldBase, staticFieldOffset);
|
||||
}
|
||||
|
||||
public static Object getObjectUnsafe(final Object base, final Field field) {
|
||||
final long fieldOffset = theUnsafe.objectFieldOffset(field);
|
||||
return theUnsafe.getObject(base, fieldOffset);
|
||||
final long fieldOffset = theUnsafe.objectFieldOffset(field);
|
||||
return theUnsafe.getObject(base, fieldOffset);
|
||||
}
|
||||
|
||||
public static void closeSilently(Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void closeSilently(Closeable closeable) {
|
||||
if(closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] readStream(InputStream stream) throws IOException {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
public static byte[] readStream(InputStream stream) throws IOException {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
|
||||
while ((nRead = stream.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
while((nRead = stream.read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
}
|
||||
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
public static URL replaceHost(URL url, String hostName, int port) {
|
||||
try {
|
||||
|
@ -94,13 +93,13 @@ public final class Util {
|
|||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
|
||||
while ((bytesRead = bs.read(buffer, 0, buffer.length)) != -1) {
|
||||
while((bytesRead = bs.read(buffer, 0, buffer.length)) != -1) {
|
||||
md.update(buffer, 0, bytesRead);
|
||||
}
|
||||
byte[] digest = md.digest();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte bite : digest) {
|
||||
for(byte bite : digest) {
|
||||
sb.append(Integer.toString((bite & 255) + 256, 16).substring(1).toLowerCase());
|
||||
}
|
||||
bs.close();
|
||||
|
@ -112,7 +111,7 @@ public final class Util {
|
|||
String query = url.getQuery();
|
||||
if(query != null) {
|
||||
String[] pairs = query.split("&");
|
||||
for (String pair : pairs) {
|
||||
for(String pair : pairs) {
|
||||
final int idx = pair.indexOf("=");
|
||||
final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair;
|
||||
final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null;
|
||||
|
|
|
@ -16,12 +16,12 @@ import org.objectweb.asm.tree.MethodInsnNode;
|
|||
public class IdentifyCall {
|
||||
protected MethodInsnNode invokeInsn;
|
||||
protected List<AbstractInsnNode[]> arguments;
|
||||
|
||||
|
||||
public IdentifyCall(MethodInsnNode invoke) {
|
||||
invokeInsn = invoke;
|
||||
arguments = initArguments();
|
||||
}
|
||||
|
||||
|
||||
private List<AbstractInsnNode[]> initArguments() {
|
||||
boolean isStatic = invokeInsn.getOpcode() == Opcodes.INVOKESTATIC;
|
||||
Type[] argTypes = Type.getArgumentTypes(invokeInsn.desc);
|
||||
|
@ -63,10 +63,11 @@ public class IdentifyCall {
|
|||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a collection of insn node arrays with each argument
|
||||
* Non-static methods include the owner of a call at index 0
|
||||
* Returns a collection of insn node arrays with each argument Non-static
|
||||
* methods include the owner of a call at index 0
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<AbstractInsnNode[]> getArguments() {
|
||||
|
@ -76,6 +77,7 @@ public class IdentifyCall {
|
|||
/**
|
||||
* Returns an array of insn nodes belonging to the argument at that index
|
||||
* Non-static methods include the owner of a call at index 0
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public AbstractInsnNode[] getArgument(int index) {
|
||||
|
@ -88,4 +90,4 @@ public class IdentifyCall {
|
|||
}
|
||||
insns.remove(invoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,17 +67,17 @@ public class InsnHelper {
|
|||
|
||||
public static InsnList clone(Iterable<AbstractInsnNode> insnList) {
|
||||
Map<LabelNode, LabelNode> labels = new HashMap<LabelNode, LabelNode>();
|
||||
for (AbstractInsnNode insn : insnList) {
|
||||
if (insn.getType() == LABEL) {
|
||||
LabelNode label = (LabelNode) insn;
|
||||
labels.put(label, new LabelNode());
|
||||
}
|
||||
for(AbstractInsnNode insn : insnList) {
|
||||
if(insn.getType() == LABEL) {
|
||||
LabelNode label = (LabelNode) insn;
|
||||
labels.put(label, new LabelNode());
|
||||
}
|
||||
}
|
||||
|
||||
InsnList destList = new InsnList();
|
||||
for (AbstractInsnNode insn : insnList) {
|
||||
AbstractInsnNode insnCopy = insn.clone(labels);
|
||||
destList.add(insnCopy);
|
||||
for(AbstractInsnNode insn : insnList) {
|
||||
AbstractInsnNode insnCopy = insn.clone(labels);
|
||||
destList.add(insnCopy);
|
||||
}
|
||||
return destList;
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ public class InsnHelper {
|
|||
current = current.getPrevious();
|
||||
}
|
||||
if(current.getType() == LABEL) {
|
||||
return (LabelNode)current;
|
||||
return (LabelNode) current;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class InsnHelper {
|
|||
public static boolean containsInvoke(InsnList insns, MethodInsnNode invoke) {
|
||||
for(AbstractInsnNode insn : insns) {
|
||||
if(insn.getType() == METHOD_INSN) {
|
||||
MethodInsnNode invoke2 = (MethodInsnNode)insn;
|
||||
MethodInsnNode invoke2 = (MethodInsnNode) insn;
|
||||
if(invoke2.getOpcode() == invoke.getOpcode() && invoke2.owner.equals(invoke.owner) && invoke2.name.equals(invoke.name) && invoke2.desc.equals(invoke.desc)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -153,8 +153,8 @@ public class InsnHelper {
|
|||
AbstractInsnNode insn = instructions.getFirst();
|
||||
while(insn != null) {
|
||||
if(insn.getType() == VAR_INSN) {
|
||||
VarInsnNode var = (VarInsnNode)insn;
|
||||
lastFree = Math.max(lastFree, var.var + 1); //FIXME 2 if it's a double or long?
|
||||
VarInsnNode var = (VarInsnNode) insn;
|
||||
lastFree = Math.max(lastFree, var.var + 1); // FIXME 2 if it's a double or long?
|
||||
}
|
||||
insn = insn.getNext();
|
||||
}
|
||||
|
@ -163,41 +163,37 @@ public class InsnHelper {
|
|||
|
||||
public static AbstractInsnNode intInsn(int value) {
|
||||
switch(value) {
|
||||
case -1:
|
||||
return new InsnNode(ICONST_M1);
|
||||
case 0:
|
||||
return new InsnNode(ICONST_0);
|
||||
case 1:
|
||||
return new InsnNode(ICONST_1);
|
||||
case 2:
|
||||
return new InsnNode(ICONST_2);
|
||||
case 3:
|
||||
return new InsnNode(ICONST_3);
|
||||
case 4:
|
||||
return new InsnNode(ICONST_4);
|
||||
case 5:
|
||||
return new InsnNode(ICONST_5);
|
||||
default:
|
||||
if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||
return new IntInsnNode(BIPUSH, value);
|
||||
}
|
||||
else if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
return new IntInsnNode(SIPUSH, value);
|
||||
}
|
||||
else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
case -1:
|
||||
return new InsnNode(ICONST_M1);
|
||||
case 0:
|
||||
return new InsnNode(ICONST_0);
|
||||
case 1:
|
||||
return new InsnNode(ICONST_1);
|
||||
case 2:
|
||||
return new InsnNode(ICONST_2);
|
||||
case 3:
|
||||
return new InsnNode(ICONST_3);
|
||||
case 4:
|
||||
return new InsnNode(ICONST_4);
|
||||
case 5:
|
||||
return new InsnNode(ICONST_5);
|
||||
default:
|
||||
if(value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||
return new IntInsnNode(BIPUSH, value);
|
||||
} else if(value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
return new IntInsnNode(SIPUSH, value);
|
||||
} else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static AbstractInsnNode longInsn(long value) {
|
||||
if(value == 0L) {
|
||||
return new InsnNode(LCONST_0);
|
||||
}
|
||||
else if(value == 1L) {
|
||||
} else if(value == 1L) {
|
||||
return new InsnNode(LCONST_1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
@ -209,14 +205,11 @@ public class InsnHelper {
|
|||
public static AbstractInsnNode floatInsn(float value) {
|
||||
if(value == 0F) {
|
||||
return new InsnNode(FCONST_0);
|
||||
}
|
||||
else if(value == 1F) {
|
||||
} else if(value == 1F) {
|
||||
return new InsnNode(FCONST_1);
|
||||
}
|
||||
else if(value == 2F) {
|
||||
} else if(value == 2F) {
|
||||
return new InsnNode(FCONST_2);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
@ -224,11 +217,9 @@ public class InsnHelper {
|
|||
public static AbstractInsnNode doubleInsn(double value) {
|
||||
if(value == 0D) {
|
||||
return new InsnNode(DCONST_0);
|
||||
}
|
||||
else if(value == 1D) {
|
||||
} else if(value == 1D) {
|
||||
return new InsnNode(DCONST_1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new LdcInsnNode(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import static org.objectweb.asm.Opcodes.*;
|
|||
import org.objectweb.asm.Type;
|
||||
|
||||
public final class OPHelper {
|
||||
|
||||
|
||||
private static final int[] STACK_SIZE_DELTA = new int[0xFF];
|
||||
|
||||
|
||||
static {
|
||||
STACK_SIZE_DELTA[NOP] = 0;
|
||||
STACK_SIZE_DELTA[ACONST_NULL] = 1;
|
||||
|
@ -179,14 +179,14 @@ public final class OPHelper {
|
|||
return 0;
|
||||
}
|
||||
if(insn.getType() == AbstractInsnNode.LDC_INSN) {
|
||||
LdcInsnNode ldc = (LdcInsnNode)insn;
|
||||
LdcInsnNode ldc = (LdcInsnNode) insn;
|
||||
if(ldc.cst instanceof Double || ldc.cst instanceof Long) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if(insn.getType() == AbstractInsnNode.METHOD_INSN) {
|
||||
MethodInsnNode invoke = (MethodInsnNode)insn;
|
||||
MethodInsnNode invoke = (MethodInsnNode) insn;
|
||||
int sizes = Type.getArgumentsAndReturnSizes(invoke.desc);
|
||||
int argumentSizes = sizes >> 2;
|
||||
if(opcode == INVOKESTATIC) {
|
||||
|
@ -196,189 +196,180 @@ public final class OPHelper {
|
|||
return returnSize - argumentSizes;
|
||||
}
|
||||
if(insn.getType() == AbstractInsnNode.FIELD_INSN) {
|
||||
FieldInsnNode field = (FieldInsnNode)insn;
|
||||
FieldInsnNode field = (FieldInsnNode) insn;
|
||||
int returnSize = Type.getType(field.desc).getSize();
|
||||
if(opcode == GETSTATIC) {
|
||||
return returnSize;
|
||||
}
|
||||
return returnSize - 1;
|
||||
}
|
||||
else if(opcode != ATHROW && opcode != MULTIANEWARRAY && opcode != INVOKEDYNAMIC) {
|
||||
} else if(opcode != ATHROW && opcode != MULTIANEWARRAY && opcode != INVOKEDYNAMIC) {
|
||||
return STACK_SIZE_DELTA[opcode];
|
||||
}
|
||||
throw new IllegalArgumentException("Could not get stack size delta for " + opcode);
|
||||
}
|
||||
|
||||
public static boolean isReturn(int opcode) {
|
||||
return
|
||||
opcode == RETURN ||
|
||||
opcode == IRETURN ||
|
||||
opcode == LRETURN ||
|
||||
opcode == FRETURN ||
|
||||
opcode == DRETURN ||
|
||||
opcode == ARETURN;
|
||||
return opcode == RETURN || opcode == IRETURN || opcode == LRETURN || opcode == FRETURN || opcode == DRETURN || opcode == ARETURN;
|
||||
}
|
||||
|
||||
public static final boolean isArrayLoad(int opcode) {
|
||||
switch (opcode) {
|
||||
case AALOAD:
|
||||
case BALOAD: // for booleans and bytes
|
||||
case CALOAD:
|
||||
case DALOAD:
|
||||
case FALOAD:
|
||||
case IALOAD:
|
||||
case LALOAD:
|
||||
case SALOAD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
switch(opcode) {
|
||||
case AALOAD:
|
||||
case BALOAD: // for booleans and bytes
|
||||
case CALOAD:
|
||||
case DALOAD:
|
||||
case FALOAD:
|
||||
case IALOAD:
|
||||
case LALOAD:
|
||||
case SALOAD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isVarLoad(int opcode) {
|
||||
switch (opcode) {
|
||||
case ALOAD:
|
||||
//case BLOAD: // bytes & booleans are also regular integers
|
||||
//case CLOAD: // characters are regular integers (?) under the hood
|
||||
case DLOAD:
|
||||
case FLOAD:
|
||||
case ILOAD:
|
||||
case LLOAD:
|
||||
//case SLOAD: // and so are shorts
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
switch(opcode) {
|
||||
case ALOAD:
|
||||
// case BLOAD: // bytes & booleans are also regular integers
|
||||
// case CLOAD: // characters are regular integers (?) under the hood
|
||||
case DLOAD:
|
||||
case FLOAD:
|
||||
case ILOAD:
|
||||
case LLOAD:
|
||||
// case SLOAD: // and so are shorts
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int reverseVarOpcode(int opcode) {
|
||||
switch (opcode) {
|
||||
case AALOAD:
|
||||
return AASTORE;
|
||||
case BALOAD:
|
||||
return BASTORE;
|
||||
case CALOAD:
|
||||
return CASTORE;
|
||||
case IALOAD:
|
||||
return IASTORE;
|
||||
case SALOAD:
|
||||
return IASTORE;
|
||||
case DALOAD:
|
||||
return IASTORE;
|
||||
case FALOAD:
|
||||
return IASTORE;
|
||||
case LALOAD:
|
||||
return IASTORE;
|
||||
case ALOAD:
|
||||
return IASTORE;
|
||||
case DLOAD:
|
||||
return IASTORE;
|
||||
case FLOAD:
|
||||
return IASTORE;
|
||||
case ILOAD:
|
||||
return IASTORE;
|
||||
case LLOAD:
|
||||
return IASTORE;
|
||||
case AASTORE:
|
||||
return AALOAD;
|
||||
case BASTORE:
|
||||
return BALOAD;
|
||||
case CASTORE:
|
||||
return CALOAD;
|
||||
case IASTORE:
|
||||
return IALOAD;
|
||||
case SASTORE:
|
||||
return SALOAD;
|
||||
case DASTORE:
|
||||
return DALOAD;
|
||||
case FASTORE:
|
||||
return FALOAD;
|
||||
case LASTORE:
|
||||
return LALOAD;
|
||||
case ASTORE:
|
||||
return ALOAD;
|
||||
case DSTORE:
|
||||
return DLOAD;
|
||||
case FSTORE:
|
||||
return FLOAD;
|
||||
case ISTORE:
|
||||
return ILOAD;
|
||||
case LSTORE:
|
||||
return LLOAD;
|
||||
default:
|
||||
throw new IllegalArgumentException("Opcode not valid.");
|
||||
switch(opcode) {
|
||||
case AALOAD:
|
||||
return AASTORE;
|
||||
case BALOAD:
|
||||
return BASTORE;
|
||||
case CALOAD:
|
||||
return CASTORE;
|
||||
case IALOAD:
|
||||
return IASTORE;
|
||||
case SALOAD:
|
||||
return IASTORE;
|
||||
case DALOAD:
|
||||
return IASTORE;
|
||||
case FALOAD:
|
||||
return IASTORE;
|
||||
case LALOAD:
|
||||
return IASTORE;
|
||||
case ALOAD:
|
||||
return IASTORE;
|
||||
case DLOAD:
|
||||
return IASTORE;
|
||||
case FLOAD:
|
||||
return IASTORE;
|
||||
case ILOAD:
|
||||
return IASTORE;
|
||||
case LLOAD:
|
||||
return IASTORE;
|
||||
case AASTORE:
|
||||
return AALOAD;
|
||||
case BASTORE:
|
||||
return BALOAD;
|
||||
case CASTORE:
|
||||
return CALOAD;
|
||||
case IASTORE:
|
||||
return IALOAD;
|
||||
case SASTORE:
|
||||
return SALOAD;
|
||||
case DASTORE:
|
||||
return DALOAD;
|
||||
case FASTORE:
|
||||
return FALOAD;
|
||||
case LASTORE:
|
||||
return LALOAD;
|
||||
case ASTORE:
|
||||
return ALOAD;
|
||||
case DSTORE:
|
||||
return DLOAD;
|
||||
case FSTORE:
|
||||
return FLOAD;
|
||||
case ISTORE:
|
||||
return ILOAD;
|
||||
case LSTORE:
|
||||
return LLOAD;
|
||||
default:
|
||||
throw new IllegalArgumentException("Opcode not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isVarSimilarType(int opcode1, int opcode2) {
|
||||
switch (opcode1) {
|
||||
case AALOAD:
|
||||
return opcode2 == ALOAD;
|
||||
case BALOAD:
|
||||
case CALOAD:
|
||||
case IALOAD:
|
||||
case SALOAD:
|
||||
return opcode2 == ILOAD;
|
||||
case DALOAD:
|
||||
return opcode2 == DLOAD;
|
||||
case FALOAD:
|
||||
return opcode2 == FLOAD;
|
||||
case LALOAD:
|
||||
return opcode2 == LLOAD;
|
||||
case ALOAD:
|
||||
return opcode2 == AALOAD;
|
||||
case DLOAD:
|
||||
return opcode2 == DALOAD;
|
||||
case FLOAD:
|
||||
return opcode2 == FALOAD;
|
||||
case ILOAD:
|
||||
return opcode2 == IALOAD || opcode2 == SALOAD
|
||||
|| opcode2 == BALOAD || opcode2 == CALOAD;
|
||||
case LLOAD:
|
||||
return opcode2 == LALOAD;
|
||||
// -- The same story for the store operation family --
|
||||
case AASTORE:
|
||||
return opcode2 == ASTORE;
|
||||
case BASTORE:
|
||||
case CASTORE:
|
||||
case IASTORE:
|
||||
case SASTORE:
|
||||
return opcode2 == ISTORE;
|
||||
case DASTORE:
|
||||
return opcode2 == DSTORE;
|
||||
case FASTORE:
|
||||
return opcode2 == FSTORE;
|
||||
case LASTORE:
|
||||
return opcode2 == LSTORE;
|
||||
case ASTORE:
|
||||
return opcode2 == ASTORE;
|
||||
case DSTORE:
|
||||
return opcode2 == DSTORE;
|
||||
case FSTORE:
|
||||
return opcode2 == FSTORE;
|
||||
case ISTORE:
|
||||
return opcode2 == IASTORE || opcode2 == SASTORE
|
||||
|| opcode2 == BASTORE || opcode2 == CASTORE;
|
||||
case LSTORE:
|
||||
return opcode2 == LSTORE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Opcode1 not valid.");
|
||||
switch(opcode1) {
|
||||
case AALOAD:
|
||||
return opcode2 == ALOAD;
|
||||
case BALOAD:
|
||||
case CALOAD:
|
||||
case IALOAD:
|
||||
case SALOAD:
|
||||
return opcode2 == ILOAD;
|
||||
case DALOAD:
|
||||
return opcode2 == DLOAD;
|
||||
case FALOAD:
|
||||
return opcode2 == FLOAD;
|
||||
case LALOAD:
|
||||
return opcode2 == LLOAD;
|
||||
case ALOAD:
|
||||
return opcode2 == AALOAD;
|
||||
case DLOAD:
|
||||
return opcode2 == DALOAD;
|
||||
case FLOAD:
|
||||
return opcode2 == FALOAD;
|
||||
case ILOAD:
|
||||
return opcode2 == IALOAD || opcode2 == SALOAD || opcode2 == BALOAD || opcode2 == CALOAD;
|
||||
case LLOAD:
|
||||
return opcode2 == LALOAD;
|
||||
// -- The same story for the store operation family --
|
||||
case AASTORE:
|
||||
return opcode2 == ASTORE;
|
||||
case BASTORE:
|
||||
case CASTORE:
|
||||
case IASTORE:
|
||||
case SASTORE:
|
||||
return opcode2 == ISTORE;
|
||||
case DASTORE:
|
||||
return opcode2 == DSTORE;
|
||||
case FASTORE:
|
||||
return opcode2 == FSTORE;
|
||||
case LASTORE:
|
||||
return opcode2 == LSTORE;
|
||||
case ASTORE:
|
||||
return opcode2 == ASTORE;
|
||||
case DSTORE:
|
||||
return opcode2 == DSTORE;
|
||||
case FSTORE:
|
||||
return opcode2 == FSTORE;
|
||||
case ISTORE:
|
||||
return opcode2 == IASTORE || opcode2 == SASTORE || opcode2 == BASTORE || opcode2 == CASTORE;
|
||||
case LSTORE:
|
||||
return opcode2 == LSTORE;
|
||||
default:
|
||||
throw new IllegalArgumentException("Opcode1 not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean isVarStore(int opcode) {
|
||||
switch (opcode) {
|
||||
case ASTORE:
|
||||
//case BSTORE: // bytes & booleans are also regular integers
|
||||
//case CSTORE: // characters are regular integers (?) under the hood
|
||||
case DSTORE:
|
||||
case FSTORE:
|
||||
case ISTORE:
|
||||
case LSTORE:
|
||||
//case SSTORE: // and so are shorts
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
switch(opcode) {
|
||||
case ASTORE:
|
||||
// case BSTORE: // bytes & booleans are also regular integers
|
||||
// case CSTORE: // characters are regular integers (?) under the hood
|
||||
case DSTORE:
|
||||
case FSTORE:
|
||||
case ISTORE:
|
||||
case LSTORE:
|
||||
// case SSTORE: // and so are shorts
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue