-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathForgeHack.java
210 lines (181 loc) · 6.33 KB
/
ForgeHack.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Minecraft Forge Installer Hack
// Bypasses the GUI and installs the Forge client to the specified location
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import java.io.OutputStream;
import java.util.function.Predicate;
public class ForgeHack
{
private static ClassLoader getClassLoader(String jarfile)
{
try
{
URL url = new File(jarfile).toURI().toURL();
return new URLClassLoader(new URL[] {url}, ForgeHack.class.getClassLoader());
}
catch (MalformedURLException e)
{
return null;
}
}
private static class MInvocationHandler implements InvocationHandler
{
public Object invoke(Object proxy, Method method, Object[] args)
{
return true; // So stupid, but necessary
}
}
/*
Interfaces for each major release version:
1.0 / 1.1 / 1.2 / 1.3:
cpw.mods.fml.installer.ClientInstall().run(File path);
1.5+:
net.minecraftforge.installer.ClientInstall().run(
File path,
com.google.common.base.Predicate<String> optionals
);
2.0:
net.minecraftforge.installer.actions.ClientInstall(
net.minecraftforge.installer.json.InstallV1 profile
= net.minecraftforge.installer.json.Util.loadInstallProfile(),
net.minecraftforge.installer.actions.ProgressCallback callback
).run(
File path,
java.util.function.Predicate<String> optionals,
File installer = installer jar path
)
*/
private static boolean run_v1(File target, ClassLoader loader)
throws ReflectiveOperationException
{
Class<?> clientInstall = null;
try
{
clientInstall = Class.forName("cpw.mods.fml.installer.ClientInstall", true, loader);
}
catch (ClassNotFoundException e)
{
// must be v1.5+ or v2
return false;
}
Object installer = clientInstall.getConstructor().newInstance();
clientInstall.getDeclaredMethod("run", File.class).invoke(installer, target);
return true;
}
private static boolean run_v15(File target, ClassLoader loader)
throws ReflectiveOperationException
{
// "Import" the required classes
Class<?> predicate = null;
Class<?> clientInstall = null;
try
{
predicate = Class.forName("com.google.common.base.Predicate", true, loader);
clientInstall = Class.forName("net.minecraftforge.installer.ClientInstall", true, loader);
}
catch (ClassNotFoundException e)
{
return false;
}
// Make a Predicate that returns true, installing all optionals
// This will install Mercurius unconditionally, but we might change that. TODO
InvocationHandler handler = new ForgeHack.MInvocationHandler();
Object pred = Proxy.newProxyInstance(loader, new Class[] {predicate}, handler);
// Run the client install function. This will pop up a dialog and install Forge to the
// specified Minecraft directory.
Object install = clientInstall.getConstructor().newInstance();
clientInstall.getDeclaredMethod("run", File.class, predicate).invoke(install, target, pred);
return true;
}
private static boolean run_v2(File target, File jarfile, ClassLoader loader)
throws ReflectiveOperationException
{
// classes needed
Class<?> c_ClientInstall = null;
Class<?> c_Util = null;
Class<?> c_InstallV1 = null;
Class<?> c_ProgressCallback = null;
try
{
c_ClientInstall = Class.forName("net.minecraftforge.installer.actions.ClientInstall", true, loader);
c_Util = Class.forName("net.minecraftforge.installer.json.Util", true, loader);
try
{
c_InstallV1 = Class.forName("net.minecraftforge.installer.json.InstallV1", true, loader);
}
catch (ClassNotFoundException ex)
{
System.out.println("using v0 Install class");
c_InstallV1 = Class.forName("net.minecraftforge.installer.json.Install", true, loader);
}
c_ProgressCallback = Class.forName("net.minecraftforge.installer.actions.ProgressCallback", true, loader);
}
catch (ClassNotFoundException e)
{
System.out.println(e.getMessage());
return false;
}
// load the profile
Object profile = c_Util.getDeclaredMethod("loadInstallProfile").invoke(null); // returns InstallV1 object
// load the progress monitor (stdout only)
Object monitor = c_ProgressCallback.getDeclaredMethod("withOutputs",
OutputStream[].class).invoke(null, new Object[] { new OutputStream[] {System.out} });
// create the ClientInstall
Object installer = c_ClientInstall.getConstructor(c_InstallV1, c_ProgressCallback)
.newInstance(profile, monitor);
// create the predicate
Predicate<String> p = (param) -> true;
// run the installer
try
{
c_ClientInstall.getDeclaredMethod("run", File.class, Predicate.class, File.class)
.invoke(installer, target, p, jarfile);
}
catch (NoSuchMethodException e)
{
c_ClientInstall.getDeclaredMethod("run", File.class, Predicate.class)
.invoke(installer, target, p);
}
return true;
}
public static void main(String[] args) throws Exception
{
if (args.length < 2)
{
System.out.println("Usage: ForgeHack <jarfile> <target dir>");
System.exit(1);
}
// NOTE: While this now has compatibility for all known versions of the
// installer, older installers seem to be broken due to missing mirror servers.
// As a result, support for any installer versions older than v2 may be
// dropped in the near future.
ClassLoader loader = getClassLoader(args[0]);
File target = new File(args[1]);
File jarfile = new File(args[0]);
System.out.println("Attempting to launch v1.5+ installer");
if (run_v15(target, loader))
{
System.out.println("Success!");
return;
}
System.out.println("Attempting to launch v2 installer");
if (run_v2(target, jarfile, loader))
{
System.out.println("Success!");
return;
}
System.out.println("Attempting to launch v1 installer");
if (run_v1(target, loader))
{
System.out.println("Success!");
return;
}
System.out.println("Failed to launch installer.");
System.exit(1);
}
}