2020-03-22 03:44:18 +03:00
|
|
|
|
package pro.gravit.launcher.client;
|
|
|
|
|
|
2021-06-05 02:30:56 +03:00
|
|
|
|
import pro.gravit.launcher.*;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import pro.gravit.launcher.api.AuthService;
|
|
|
|
|
import pro.gravit.launcher.api.ClientService;
|
2022-07-24 12:24:25 +03:00
|
|
|
|
import pro.gravit.launcher.api.KeyService;
|
2020-04-03 11:12:31 +03:00
|
|
|
|
import pro.gravit.launcher.client.events.client.*;
|
2021-11-16 19:00:41 +03:00
|
|
|
|
import pro.gravit.launcher.events.request.ProfileByUUIDRequestEvent;
|
|
|
|
|
import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import pro.gravit.launcher.hasher.FileNameMatcher;
|
|
|
|
|
import pro.gravit.launcher.hasher.HashedDir;
|
2021-01-28 20:13:21 +03:00
|
|
|
|
import pro.gravit.launcher.hasher.HashedEntry;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import pro.gravit.launcher.managers.ClientGsonManager;
|
2021-04-29 19:56:48 +03:00
|
|
|
|
import pro.gravit.launcher.managers.ConsoleManager;
|
2021-11-16 19:00:41 +03:00
|
|
|
|
import pro.gravit.launcher.modules.LauncherModulesManager;
|
|
|
|
|
import pro.gravit.launcher.modules.events.OfflineModeEvent;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
|
|
|
|
import pro.gravit.launcher.profiles.ClientProfile;
|
2020-09-12 09:41:58 +03:00
|
|
|
|
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
|
|
|
|
|
import pro.gravit.launcher.profiles.optional.actions.OptionalActionClassPath;
|
2020-09-26 20:52:43 +03:00
|
|
|
|
import pro.gravit.launcher.profiles.optional.actions.OptionalActionClientArgs;
|
2021-06-18 07:34:32 +03:00
|
|
|
|
import pro.gravit.launcher.profiles.optional.triggers.OptionalTrigger;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import pro.gravit.launcher.request.Request;
|
|
|
|
|
import pro.gravit.launcher.request.RequestException;
|
2021-11-16 19:00:41 +03:00
|
|
|
|
import pro.gravit.launcher.request.RequestService;
|
2020-09-12 09:41:58 +03:00
|
|
|
|
import pro.gravit.launcher.request.auth.AuthRequest;
|
2021-04-13 15:30:06 +03:00
|
|
|
|
import pro.gravit.launcher.request.auth.GetAvailabilityAuthRequest;
|
2021-11-16 19:00:41 +03:00
|
|
|
|
import pro.gravit.launcher.request.uuid.ProfileByUUIDRequest;
|
|
|
|
|
import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest;
|
|
|
|
|
import pro.gravit.launcher.request.websockets.OfflineRequestService;
|
2021-11-16 14:32:52 +03:00
|
|
|
|
import pro.gravit.launcher.request.websockets.StdWebSocketService;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import pro.gravit.launcher.serialize.HInput;
|
|
|
|
|
import pro.gravit.launcher.utils.DirWatcher;
|
|
|
|
|
import pro.gravit.utils.helper.*;
|
|
|
|
|
|
|
|
|
|
import javax.swing.*;
|
2021-01-28 20:13:21 +03:00
|
|
|
|
import java.io.File;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.lang.invoke.MethodHandle;
|
|
|
|
|
import java.lang.invoke.MethodHandles;
|
|
|
|
|
import java.lang.invoke.MethodType;
|
2021-01-28 20:13:21 +03:00
|
|
|
|
import java.net.*;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
import java.nio.file.FileVisitResult;
|
|
|
|
|
import java.nio.file.Path;
|
|
|
|
|
import java.nio.file.Paths;
|
|
|
|
|
import java.nio.file.SimpleFileVisitor;
|
|
|
|
|
import java.nio.file.attribute.BasicFileAttributes;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
public class ClientLauncherEntryPoint {
|
2021-01-28 20:13:21 +03:00
|
|
|
|
private static ClassLoader classLoader;
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
2020-03-22 04:30:29 +03:00
|
|
|
|
private static ClientLauncherProcess.ClientParams readParams(SocketAddress address) throws IOException {
|
2020-04-05 10:27:04 +03:00
|
|
|
|
try (Socket socket = IOHelper.newSocket()) {
|
2020-03-22 03:44:18 +03:00
|
|
|
|
socket.connect(address);
|
2020-04-05 10:27:04 +03:00
|
|
|
|
try (HInput input = new HInput(socket.getInputStream())) {
|
2020-03-22 03:44:18 +03:00
|
|
|
|
byte[] serialized = input.readByteArray(0);
|
2021-07-21 19:43:47 +03:00
|
|
|
|
ClientLauncherProcess.ClientParams params = Launcher.gsonManager.gson.fromJson(IOHelper.decode(serialized), ClientLauncherProcess.ClientParams.class);
|
2020-03-22 03:44:18 +03:00
|
|
|
|
params.clientHDir = new HashedDir(input);
|
|
|
|
|
params.assetHDir = new HashedDir(input);
|
2020-08-02 01:16:18 +03:00
|
|
|
|
boolean isNeedReadJavaDir = input.readBoolean();
|
2020-09-25 18:48:33 +03:00
|
|
|
|
if (isNeedReadJavaDir)
|
2020-08-02 01:16:18 +03:00
|
|
|
|
params.javaHDir = new HashedDir(input);
|
2020-03-22 03:44:18 +03:00
|
|
|
|
return params;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
2020-03-22 04:30:29 +03:00
|
|
|
|
public static void main(String[] args) throws Throwable {
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LauncherEngine engine = LauncherEngine.clientInstance();
|
2020-04-03 11:12:31 +03:00
|
|
|
|
JVMHelper.verifySystemProperties(ClientLauncherEntryPoint.class, true);
|
|
|
|
|
EnvHelper.checkDangerousParams();
|
|
|
|
|
JVMHelper.checkStackTrace(ClientLauncherEntryPoint.class);
|
|
|
|
|
LogHelper.printVersion("Client Launcher");
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LauncherEngine.checkClass(LauncherEngine.class);
|
|
|
|
|
LauncherEngine.checkClass(LauncherAgent.class);
|
2020-03-22 04:40:14 +03:00
|
|
|
|
LauncherEngine.checkClass(ClientLauncherEntryPoint.class);
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LauncherEngine.modulesManager = new ClientModuleManager();
|
2020-05-01 19:56:08 +03:00
|
|
|
|
LauncherEngine.modulesManager.loadModule(new ClientLauncherCoreModule());
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LauncherConfig.initModules(LauncherEngine.modulesManager); //INIT
|
|
|
|
|
LauncherEngine.modulesManager.initModules(null);
|
|
|
|
|
initGson(LauncherEngine.modulesManager);
|
2021-04-29 19:56:48 +03:00
|
|
|
|
ConsoleManager.initConsole();
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
|
|
|
|
|
engine.readKeys();
|
|
|
|
|
LogHelper.debug("Reading ClientLauncher params");
|
|
|
|
|
ClientLauncherProcess.ClientParams params = readParams(new InetSocketAddress("127.0.0.1", Launcher.getConfig().clientPort));
|
2021-05-07 15:25:04 +03:00
|
|
|
|
if (params.profile.getClassLoaderConfig() != ClientProfile.ClassLoaderConfig.AGENT) {
|
2021-01-28 20:13:21 +03:00
|
|
|
|
LauncherEngine.verifyNoAgent();
|
|
|
|
|
}
|
2020-03-22 03:44:18 +03:00
|
|
|
|
ClientProfile profile = params.profile;
|
|
|
|
|
Launcher.profile = profile;
|
|
|
|
|
AuthService.profile = profile;
|
|
|
|
|
LauncherEngine.clientParams = params;
|
2021-05-25 12:17:29 +03:00
|
|
|
|
if (params.oauth != null) {
|
2021-05-23 17:11:27 +03:00
|
|
|
|
LogHelper.info("Using OAuth");
|
2021-05-25 12:17:29 +03:00
|
|
|
|
if (params.oauthExpiredTime != 0) {
|
2021-05-23 14:13:30 +03:00
|
|
|
|
Request.setOAuth(params.authId, params.oauth, params.oauthExpiredTime);
|
|
|
|
|
} else {
|
|
|
|
|
Request.setOAuth(params.authId, params.oauth);
|
|
|
|
|
}
|
2021-05-25 12:17:29 +03:00
|
|
|
|
if (params.extendedTokens != null) {
|
2021-05-23 14:13:30 +03:00
|
|
|
|
Request.addAllExtendedToken(params.extendedTokens);
|
|
|
|
|
}
|
2021-05-25 12:17:29 +03:00
|
|
|
|
} else if (params.session != null) {
|
2022-03-18 15:22:03 +03:00
|
|
|
|
throw new UnsupportedOperationException("Legacy session not supported");
|
2021-05-23 14:13:30 +03:00
|
|
|
|
}
|
2021-01-28 20:13:21 +03:00
|
|
|
|
checkJVMBitsAndVersion(params.profile.getMinJavaVersion(), params.profile.getRecommendJavaVersion(), params.profile.getMaxJavaVersion(), params.profile.isWarnMissJavaVersion());
|
2020-04-03 11:12:31 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessInitPhase(engine, params));
|
2020-03-22 03:44:18 +03:00
|
|
|
|
|
|
|
|
|
Path clientDir = Paths.get(params.clientDir);
|
|
|
|
|
Path assetDir = Paths.get(params.assetDir);
|
|
|
|
|
|
|
|
|
|
// Verify ClientLauncher sign and classpath
|
|
|
|
|
LogHelper.debug("Verifying ClientLauncher sign and classpath");
|
2022-07-30 12:15:35 +03:00
|
|
|
|
List<Path> classpath = resolveClassPath(clientDir, params.actions, params.profile)
|
|
|
|
|
.filter(x -> !profile.getModulePath().contains(clientDir.relativize(x).toString()))
|
|
|
|
|
.collect(Collectors.toList());
|
2021-12-12 20:58:38 +03:00
|
|
|
|
List<URL> classpathURLs = classpath.stream().map(IOHelper::toURL).collect(Collectors.toList());
|
2020-03-22 03:44:18 +03:00
|
|
|
|
// Start client with WatchService monitoring
|
2021-11-16 19:00:41 +03:00
|
|
|
|
RequestService service;
|
|
|
|
|
if(params.offlineMode) {
|
|
|
|
|
service = initOffline(LauncherEngine.modulesManager, params);
|
2021-11-16 21:00:31 +03:00
|
|
|
|
Request.setRequestService(service);
|
2021-11-16 19:00:41 +03:00
|
|
|
|
} else {
|
|
|
|
|
service = StdWebSocketService.initWebSockets(Launcher.getConfig().address).get();
|
2021-11-16 21:00:31 +03:00
|
|
|
|
Request.setRequestService(service);
|
2021-11-16 19:00:41 +03:00
|
|
|
|
LogHelper.debug("Restore sessions");
|
|
|
|
|
Request.restore();
|
|
|
|
|
service.registerEventHandler(new BasicLauncherEventHandler());
|
|
|
|
|
((StdWebSocketService) service).reconnectCallback = () ->
|
|
|
|
|
{
|
|
|
|
|
LogHelper.debug("WebSocket connect closed. Try reconnect");
|
|
|
|
|
try {
|
|
|
|
|
Request.reconnect();
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
throw new RequestException("Connection failed", e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-07-24 12:24:25 +03:00
|
|
|
|
LogHelper.debug("Natives dir %s", params.nativesDir);
|
2021-07-11 09:44:57 +03:00
|
|
|
|
ClientProfile.ClassLoaderConfig classLoaderConfig = profile.getClassLoaderConfig();
|
|
|
|
|
if (classLoaderConfig == ClientProfile.ClassLoaderConfig.LAUNCHER) {
|
2021-12-12 20:58:38 +03:00
|
|
|
|
ClientClassLoader classLoader = new ClientClassLoader(classpathURLs.toArray(new URL[0]), ClassLoader.getSystemClassLoader());
|
|
|
|
|
System.setProperty("java.class.path", classpath.stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator)));
|
2021-01-28 20:13:21 +03:00
|
|
|
|
ClientLauncherEntryPoint.classLoader = classLoader;
|
|
|
|
|
Thread.currentThread().setContextClassLoader(classLoader);
|
2022-07-24 12:24:25 +03:00
|
|
|
|
classLoader.nativePath = params.nativesDir;
|
2021-01-28 20:13:21 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile));
|
|
|
|
|
ClientService.classLoader = classLoader;
|
|
|
|
|
ClientService.nativePath = classLoader.nativePath;
|
|
|
|
|
classLoader.addURL(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL());
|
|
|
|
|
ClientService.baseURLs = classLoader.getURLs();
|
2021-07-11 09:44:57 +03:00
|
|
|
|
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.AGENT) {
|
2021-01-28 20:13:21 +03:00
|
|
|
|
ClientLauncherEntryPoint.classLoader = ClassLoader.getSystemClassLoader();
|
2021-12-12 20:58:38 +03:00
|
|
|
|
classpathURLs.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toUri().toURL());
|
|
|
|
|
for (URL url : classpathURLs) {
|
2021-01-28 20:13:21 +03:00
|
|
|
|
LauncherAgent.addJVMClassPath(Paths.get(url.toURI()));
|
|
|
|
|
}
|
|
|
|
|
ClientService.instrumentation = LauncherAgent.inst;
|
2022-07-24 12:24:25 +03:00
|
|
|
|
ClientService.nativePath = params.nativesDir;
|
2021-01-28 20:13:21 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessClassLoaderEvent(engine, classLoader, profile));
|
|
|
|
|
ClientService.classLoader = classLoader;
|
2021-12-12 20:58:38 +03:00
|
|
|
|
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
2021-07-11 09:44:57 +03:00
|
|
|
|
} else if (classLoaderConfig == ClientProfile.ClassLoaderConfig.SYSTEM_ARGS) {
|
|
|
|
|
ClientLauncherEntryPoint.classLoader = ClassLoader.getSystemClassLoader();
|
|
|
|
|
ClientService.classLoader = ClassLoader.getSystemClassLoader();
|
2021-12-12 20:58:38 +03:00
|
|
|
|
ClientService.baseURLs = classpathURLs.toArray(new URL[0]);
|
2022-07-24 12:24:25 +03:00
|
|
|
|
ClientService.nativePath = params.nativesDir;
|
2021-01-28 20:13:21 +03:00
|
|
|
|
}
|
2021-07-11 09:44:57 +03:00
|
|
|
|
AuthService.username = params.playerProfile.username;
|
|
|
|
|
AuthService.uuid = params.playerProfile.uuid;
|
2022-07-24 12:24:25 +03:00
|
|
|
|
KeyService.serverRsaPublicKey = Launcher.getConfig().rsaPublicKey;
|
2021-05-25 12:17:29 +03:00
|
|
|
|
if (params.profile.getRuntimeInClientConfig() != ClientProfile.RuntimeInClientConfig.NONE) {
|
2021-04-29 19:56:48 +03:00
|
|
|
|
CommonHelper.newThread("Client Launcher Thread", true, () -> {
|
|
|
|
|
try {
|
|
|
|
|
engine.start(args);
|
|
|
|
|
} catch (Throwable throwable) {
|
|
|
|
|
LogHelper.error(throwable);
|
|
|
|
|
}
|
|
|
|
|
}).start();
|
|
|
|
|
}
|
2020-04-03 11:12:31 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessReadyEvent(engine, params));
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LogHelper.debug("Starting JVM and client WatchService");
|
|
|
|
|
FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher();
|
|
|
|
|
FileNameMatcher clientMatcher = profile.getClientUpdateMatcher();
|
2020-08-02 01:16:18 +03:00
|
|
|
|
Path javaDir = Paths.get(System.getProperty("java.home"));
|
2022-07-26 13:22:34 +03:00
|
|
|
|
try (DirWatcher assetWatcher = new DirWatcher(assetDir, params.assetHDir, assetMatcher, true);
|
|
|
|
|
DirWatcher clientWatcher = new DirWatcher(clientDir, params.clientHDir, clientMatcher, true);
|
|
|
|
|
DirWatcher javaWatcher = params.javaHDir == null ? null : new DirWatcher(javaDir, params.javaHDir, null, true)) {
|
2020-03-22 03:44:18 +03:00
|
|
|
|
// Verify current state of all dirs
|
|
|
|
|
//verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null, digest);
|
|
|
|
|
//for (OptionalFile s : Launcher.profile.getOptional()) {
|
|
|
|
|
// if (params.updateOptional.contains(s)) s.mark = true;
|
|
|
|
|
// else hdir.removeR(s.file);
|
|
|
|
|
//}
|
|
|
|
|
// Start WatchService, and only then client
|
|
|
|
|
CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
|
|
|
|
|
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
|
2020-09-25 18:48:33 +03:00
|
|
|
|
if (javaWatcher != null)
|
2022-06-29 13:36:45 +03:00
|
|
|
|
CommonHelper.newThread("Java Directory Watcher", true, javaWatcher).start();
|
2022-08-30 10:26:08 +03:00
|
|
|
|
verifyHDir(assetDir, params.assetHDir, assetMatcher, false, false);
|
|
|
|
|
verifyHDir(clientDir, params.clientHDir, clientMatcher, false, true);
|
2020-09-25 18:48:33 +03:00
|
|
|
|
if (javaWatcher != null)
|
2022-08-30 10:26:08 +03:00
|
|
|
|
verifyHDir(javaDir, params.javaHDir, null, false, true);
|
2020-10-27 21:55:08 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessLaunchEvent(engine, params));
|
2020-03-22 03:44:18 +03:00
|
|
|
|
launch(profile, params);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
2020-03-22 03:44:18 +03:00
|
|
|
|
private static void initGson(ClientModuleManager moduleManager) {
|
2020-09-12 09:41:58 +03:00
|
|
|
|
AuthRequest.registerProviders();
|
2021-04-13 15:30:06 +03:00
|
|
|
|
GetAvailabilityAuthRequest.registerProviders();
|
2020-09-12 09:41:58 +03:00
|
|
|
|
OptionalAction.registerProviders();
|
2021-06-18 07:34:32 +03:00
|
|
|
|
OptionalTrigger.registerProviders();
|
2020-03-22 03:44:18 +03:00
|
|
|
|
Launcher.gsonManager = new ClientGsonManager(moduleManager);
|
|
|
|
|
Launcher.gsonManager.initGson();
|
|
|
|
|
}
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
2021-11-16 19:00:41 +03:00
|
|
|
|
public static RequestService initOffline(LauncherModulesManager modulesManager, ClientLauncherProcess.ClientParams params) {
|
|
|
|
|
OfflineRequestService service = new OfflineRequestService();
|
|
|
|
|
LauncherEngine.applyBasicOfflineProcessors(service);
|
|
|
|
|
applyClientOfflineProcessors(service, params);
|
|
|
|
|
OfflineModeEvent event = new OfflineModeEvent(service);
|
|
|
|
|
modulesManager.invokeEvent(event);
|
|
|
|
|
return event.service;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void applyClientOfflineProcessors(OfflineRequestService service, ClientLauncherProcess.ClientParams params) {
|
|
|
|
|
service.registerRequestProcessor(ProfileByUsernameRequest.class, (r) -> {
|
|
|
|
|
if(params.playerProfile.username.equals(r.username)) {
|
|
|
|
|
return new ProfileByUsernameRequestEvent(params.playerProfile);
|
|
|
|
|
}
|
|
|
|
|
throw new RequestException("User not found");
|
|
|
|
|
});
|
|
|
|
|
service.registerRequestProcessor(ProfileByUUIDRequest.class, (r) -> {
|
|
|
|
|
if(params.playerProfile.uuid.equals(r.uuid)) {
|
|
|
|
|
return new ProfileByUUIDRequestEvent(params.playerProfile);
|
|
|
|
|
}
|
|
|
|
|
throw new RequestException("User not found");
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-30 10:26:08 +03:00
|
|
|
|
public static void verifyHDir(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest, boolean checkExtra) throws IOException {
|
2020-03-22 03:44:18 +03:00
|
|
|
|
//if (matcher != null)
|
|
|
|
|
// matcher = matcher.verifyOnly();
|
|
|
|
|
|
|
|
|
|
// Hash directory and compare (ignore update-only matcher entries, it will break offline-mode)
|
|
|
|
|
HashedDir currentHDir = new HashedDir(dir, matcher, true, digest);
|
|
|
|
|
HashedDir.Diff diff = hdir.diff(currentHDir, matcher);
|
2022-08-30 10:26:08 +03:00
|
|
|
|
if (!diff.mismatch.isEmpty() || (checkExtra && !diff.extra.isEmpty())) {
|
2022-07-24 12:24:25 +03:00
|
|
|
|
diff.extra.walk(File.separator, (e, k, v) -> {
|
|
|
|
|
if (v.getType().equals(HashedEntry.Type.FILE)) {
|
|
|
|
|
LogHelper.error("Extra file %s", e);
|
|
|
|
|
} else LogHelper.error("Extra %s", e);
|
|
|
|
|
return HashedDir.WalkAction.CONTINUE;
|
|
|
|
|
});
|
|
|
|
|
diff.mismatch.walk(File.separator, (e, k, v) -> {
|
|
|
|
|
if (v.getType().equals(HashedEntry.Type.FILE)) {
|
|
|
|
|
LogHelper.error("Mismatch file %s", e);
|
|
|
|
|
} else LogHelper.error("Mismatch %s", e);
|
|
|
|
|
return HashedDir.WalkAction.CONTINUE;
|
|
|
|
|
});
|
2020-03-22 03:44:18 +03:00
|
|
|
|
throw new SecurityException(String.format("Forbidden modification: '%s'", IOHelper.getFileName(dir)));
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
2021-01-28 20:13:21 +03:00
|
|
|
|
public static boolean checkJVMBitsAndVersion(int minVersion, int recommendVersion, int maxVersion, boolean showMessage) {
|
|
|
|
|
boolean ok = true;
|
2022-07-24 12:24:25 +03:00
|
|
|
|
if (JVMHelper.JVM_BITS == 64 && JVMHelper.ARCH_TYPE == JVMHelper.ARCH.X86) {
|
|
|
|
|
String error = "У Вас установлена Java x64, но Ваша система определена как x32. Установите Java правильной разрядности";
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LogHelper.error(error);
|
2021-01-28 20:13:21 +03:00
|
|
|
|
if (showMessage)
|
2020-03-22 03:44:18 +03:00
|
|
|
|
JOptionPane.showMessageDialog(null, error);
|
2021-01-28 20:13:21 +03:00
|
|
|
|
ok = false;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
}
|
|
|
|
|
String jvmVersion = JVMHelper.RUNTIME_MXBEAN.getVmVersion();
|
|
|
|
|
LogHelper.info(jvmVersion);
|
2021-01-28 20:13:21 +03:00
|
|
|
|
int version = JVMHelper.getVersion();
|
|
|
|
|
if (version < minVersion || version > maxVersion) {
|
2022-07-24 12:24:25 +03:00
|
|
|
|
String error = String.format("У Вас установлена Java %d, но этот клиент требует Java %d", JVMHelper.getVersion(), recommendVersion);
|
2020-03-22 03:44:18 +03:00
|
|
|
|
LogHelper.error(error);
|
2021-01-28 20:13:21 +03:00
|
|
|
|
if (showMessage)
|
2020-03-22 03:44:18 +03:00
|
|
|
|
JOptionPane.showMessageDialog(null, error);
|
2021-01-28 20:13:21 +03:00
|
|
|
|
ok = false;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
}
|
2021-01-28 20:13:21 +03:00
|
|
|
|
return ok;
|
2020-03-22 03:44:18 +03:00
|
|
|
|
}
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
2020-03-22 03:44:18 +03:00
|
|
|
|
private static LinkedList<Path> resolveClassPathList(Path clientDir, String... classPath) throws IOException {
|
|
|
|
|
return resolveClassPathStream(clientDir, classPath).collect(Collectors.toCollection(LinkedList::new));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Stream<Path> resolveClassPathStream(Path clientDir, String... classPath) throws IOException {
|
|
|
|
|
Stream.Builder<Path> builder = Stream.builder();
|
|
|
|
|
for (String classPathEntry : classPath) {
|
|
|
|
|
Path path = clientDir.resolve(IOHelper.toPath(classPathEntry.replace(IOHelper.CROSS_SEPARATOR, IOHelper.PLATFORM_SEPARATOR)));
|
|
|
|
|
if (IOHelper.isDir(path)) { // Recursive walking and adding
|
|
|
|
|
IOHelper.walk(path, new ClassPathFileVisitor(builder), false);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
builder.accept(path);
|
|
|
|
|
}
|
|
|
|
|
return builder.build();
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-11 09:44:57 +03:00
|
|
|
|
public static Stream<Path> resolveClassPath(Path clientDir, Set<OptionalAction> actions, ClientProfile profile) throws IOException {
|
|
|
|
|
Stream<Path> result = resolveClassPathStream(clientDir, profile.getClassPath());
|
|
|
|
|
for (OptionalAction a : actions) {
|
|
|
|
|
if (a instanceof OptionalActionClassPath)
|
|
|
|
|
result = Stream.concat(result, resolveClassPathStream(clientDir, ((OptionalActionClassPath) a).args));
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 03:44:18 +03:00
|
|
|
|
private static void launch(ClientProfile profile, ClientLauncherProcess.ClientParams params) throws Throwable {
|
|
|
|
|
// Add client args
|
|
|
|
|
Collection<String> args = new LinkedList<>();
|
|
|
|
|
if (profile.getVersion().compareTo(ClientProfile.Version.MC164) >= 0)
|
|
|
|
|
params.addClientArgs(args);
|
|
|
|
|
else {
|
|
|
|
|
params.addClientLegacyArgs(args);
|
|
|
|
|
System.setProperty("minecraft.applet.TargetDirectory", params.clientDir);
|
|
|
|
|
}
|
|
|
|
|
Collections.addAll(args, profile.getClientArgs());
|
2021-03-20 11:53:22 +03:00
|
|
|
|
for (OptionalAction action : params.actions) {
|
|
|
|
|
if (action instanceof OptionalActionClientArgs) {
|
2020-09-26 20:52:43 +03:00
|
|
|
|
args.addAll(((OptionalActionClientArgs) action).args);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-22 03:44:18 +03:00
|
|
|
|
List<String> copy = new ArrayList<>(args);
|
|
|
|
|
for (int i = 0, l = copy.size(); i < l; i++) {
|
|
|
|
|
String s = copy.get(i);
|
|
|
|
|
if (i + 1 < l && ("--accessToken".equals(s) || "--session".equals(s))) {
|
|
|
|
|
copy.set(i + 1, "censored");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LogHelper.debug("Args: " + copy);
|
|
|
|
|
// Resolve main class and method
|
|
|
|
|
Class<?> mainClass = classLoader.loadClass(profile.getMainClass());
|
2021-03-20 11:53:22 +03:00
|
|
|
|
if (LogHelper.isDevEnabled() && classLoader instanceof URLClassLoader) {
|
|
|
|
|
for (URL u : ((URLClassLoader) classLoader).getURLs()) {
|
2021-01-28 20:13:21 +03:00
|
|
|
|
LogHelper.dev("ClassLoader URL: %s", u.toString());
|
|
|
|
|
}
|
2020-03-22 03:44:18 +03:00
|
|
|
|
}
|
2020-04-03 11:12:31 +03:00
|
|
|
|
LauncherEngine.modulesManager.invokeEvent(new ClientProcessPreInvokeMainClassEvent(params, profile, args));
|
2020-03-22 03:44:18 +03:00
|
|
|
|
// Invoke main method
|
|
|
|
|
try {
|
2022-04-07 18:09:20 +03:00
|
|
|
|
{
|
|
|
|
|
List<String> compatClasses = profile.getCompatClasses();
|
|
|
|
|
for (String e : compatClasses) {
|
|
|
|
|
Class<?> clazz = classLoader.loadClass(e);
|
|
|
|
|
MethodHandle runMethod = MethodHandles.publicLookup().findStatic(clazz, "run", MethodType.methodType(void.class));
|
|
|
|
|
runMethod.invoke();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
MethodHandle mainMethod = MethodHandles.lookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
|
|
|
|
Launcher.LAUNCHED.set(true);
|
|
|
|
|
JVMHelper.fullGC();
|
2020-03-22 03:44:18 +03:00
|
|
|
|
mainMethod.invokeWithArguments((Object) args.toArray(new String[0]));
|
|
|
|
|
LogHelper.debug("Main exit successful");
|
|
|
|
|
} catch (Throwable e) {
|
|
|
|
|
LogHelper.error(e);
|
|
|
|
|
throw e;
|
|
|
|
|
} finally {
|
|
|
|
|
LauncherEngine.exitLauncher(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2020-04-05 10:27:04 +03:00
|
|
|
|
|
|
|
|
|
private static final class ClassPathFileVisitor extends SimpleFileVisitor<Path> {
|
|
|
|
|
private final Stream.Builder<Path> result;
|
|
|
|
|
|
|
|
|
|
private ClassPathFileVisitor(Stream.Builder<Path> result) {
|
|
|
|
|
this.result = result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
|
|
|
if (IOHelper.hasExtension(file, "jar") || IOHelper.hasExtension(file, "zip"))
|
|
|
|
|
result.accept(file);
|
|
|
|
|
return super.visitFile(file, attrs);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-22 03:44:18 +03:00
|
|
|
|
}
|