Merge branch 'dev' of github.com:GravitLauncher/Launcher into dev

This commit is contained in:
Zaxar163 2019-12-09 16:08:23 +01:00
commit 47e5902e94
No known key found for this signature in database
GPG key ID: 1FE4F2E1F053831B
61 changed files with 622 additions and 620 deletions

View file

@ -16,29 +16,17 @@
-keepattributes Signature -keepattributes Signature
-adaptresourcefilecontents META-INF/MANIFEST.MF -adaptresourcefilecontents META-INF/MANIFEST.MF
-keeppackagenames com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.** -keeppackagenames com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.**, pro.gravit.utils.**, pro.gravit.launcher.request.**, pro.gravit.launcher.events.**, pro.gravit.launcher.profiles.**
-keep class com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.** { -keep class com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.**, pro.gravit.utils.**, pro.gravit.launcher.request.**, pro.gravit.launcher.events.**, pro.gravit.launcher.profiles.** {
*; *;
} }
-keepclassmembers @pro.gravit.launcher.LauncherAPI class ** {
<fields>;
<methods>;
}
-keepclassmembers @pro.gravit.launcher.LauncherNetworkAPI class ** { -keepclassmembers @pro.gravit.launcher.LauncherNetworkAPI class ** {
<fields>; <fields>;
<methods>; <methods>;
} }
-keepclassmembers class ** {
@pro.gravit.launcher.LauncherAPI
<fields>;
@pro.gravit.launcher.LauncherAPI
<methods>;
}
-keepclassmembers class ** { -keepclassmembers class ** {
@pro.gravit.launcher.LauncherNetworkAPI @pro.gravit.launcher.LauncherNetworkAPI
<fields>; <fields>;

View file

@ -53,7 +53,7 @@ task javadocJar(type: Jar) {
} }
dependencies { dependencies {
pack project(':LauncherAuthlib') pack project(':LauncherAPI')
bundle 'com.github.oshi:oshi-core:3.13.0' bundle 'com.github.oshi:oshi-core:3.13.0'
pack 'io.netty:netty-codec-http:4.1.43.Final' pack 'io.netty:netty-codec-http:4.1.43.Final'
pack 'org.ow2.asm:asm-tree:7.1' pack 'org.ow2.asm:asm-tree:7.1'

View file

@ -7,7 +7,7 @@
public abstract class JSApplication extends Application { public abstract class JSApplication extends Application {
private static final AtomicReference<JSApplication> INSTANCE = new AtomicReference<>(); private static final AtomicReference<JSApplication> INSTANCE = new AtomicReference<>();
@LauncherAPI
public static JSApplication getInstance() { public static JSApplication getInstance() {
return INSTANCE.get(); return INSTANCE.get();
} }

View file

@ -10,7 +10,7 @@
import java.nio.file.Path; import java.nio.file.Path;
import java.util.jar.JarFile; import java.util.jar.JarFile;
@LauncherAPI
public final class LauncherAgent { public final class LauncherAgent {
private static boolean isAgentStarted = false; private static boolean isAgentStarted = false;
public static Instrumentation inst; public static Instrumentation inst;

View file

@ -126,7 +126,7 @@ private LauncherEngine() {
} }
@LauncherAPI
public void start(String... args) throws Throwable { public void start(String... args) throws Throwable {
//Launcher.modulesManager = new ClientModuleManager(this); //Launcher.modulesManager = new ClientModuleManager(this);
ClientPreGuiPhase event = new ClientPreGuiPhase(null); ClientPreGuiPhase event = new ClientPreGuiPhase(null);

View file

@ -8,21 +8,17 @@
import java.util.*; import java.util.*;
public class NewLauncherSettings { public class NewLauncherSettings {
@LauncherAPI @LauncherNetworkAPI
public Map<String, UserSettings> userSettings = new HashMap<>(); public Map<String, UserSettings> userSettings = new HashMap<>();
@LauncherAPI @LauncherNetworkAPI
public List<String> features = new ArrayList<>(); public List<String> features = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
public String consoleUnlockKey; public String consoleUnlockKey;
public static class HashedStoreEntry { public static class HashedStoreEntry {
@LauncherAPI
public final HashedDir hdir; public final HashedDir hdir;
@LauncherAPI
public final String name; public final String name;
@LauncherAPI
public final String fullPath; public final String fullPath;
@LauncherAPI
public transient boolean needSave = false; public transient boolean needSave = false;
public HashedStoreEntry(HashedDir hdir, String name, String fullPath) { public HashedStoreEntry(HashedDir hdir, String name, String fullPath) {
@ -32,10 +28,9 @@ public HashedStoreEntry(HashedDir hdir, String name, String fullPath) {
} }
} }
@LauncherAPI @LauncherNetworkAPI
public final transient List<HashedStoreEntry> lastHDirs = new ArrayList<>(16); public final transient List<HashedStoreEntry> lastHDirs = new ArrayList<>(16);
@LauncherAPI
public void putHDir(String name, Path path, HashedDir dir) { public void putHDir(String name, Path path, HashedDir dir) {
String fullPath = path.toAbsolutePath().toString(); String fullPath = path.toAbsolutePath().toString();
lastHDirs.removeIf((e) -> e.fullPath.equals(fullPath) && e.name.equals(name)); lastHDirs.removeIf((e) -> e.fullPath.equals(fullPath) && e.name.equals(name));

View file

@ -0,0 +1,89 @@
package pro.gravit.launcher.client;
import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper;
import java.net.URL;
import java.net.URLClassLoader;
public class ClientClassLoader extends URLClassLoader {
public String nativePath;
/**
* Constructs a new URLClassLoader for the specified URLs using the
* default delegation parent {@code ClassLoader}. The URLs will
* be searched in the order specified for classes and resources after
* first searching in the parent class loader. Any URL that ends with
* a '/' is assumed to refer to a directory. Otherwise, the URL is
* assumed to refer to a JAR file which will be downloaded and opened
* as needed.
*
* <p>If there is a security manager, this method first
* calls the security manager's {@code checkCreateClassLoader} method
* to ensure creation of a class loader is allowed.
*
* @param urls the URLs from which to load classes and resources
* @throws SecurityException if a security manager exists and its
* {@code checkCreateClassLoader} method doesn't allow
* creation of a class loader.
* @throws NullPointerException if {@code urls} is {@code null}.
* @see SecurityManager#checkCreateClassLoader
*/
public ClientClassLoader(URL[] urls) {
super(urls);
}
/**
* Constructs a new URLClassLoader for the given URLs. The URLs will be
* searched in the order specified for classes and resources after first
* searching in the specified parent class loader. Any {@code jar:}
* scheme URL is assumed to refer to a JAR file. Any {@code file:} scheme
* URL that ends with a '/' is assumed to refer to a directory. Otherwise,
* the URL is assumed to refer to a JAR file which will be downloaded and
* opened as needed.
*
* <p>If there is a security manager, this method first
* calls the security manager's {@code checkCreateClassLoader} method
* to ensure creation of a class loader is allowed.
*
* @param urls the URLs from which to load classes and resources
* @param parent the parent class loader for delegation
* @throws SecurityException if a security manager exists and its
* {@code checkCreateClassLoader} method doesn't allow
* creation of a class loader.
* @throws NullPointerException if {@code urls} is {@code null}.
* @see SecurityManager#checkCreateClassLoader
*/
public ClientClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
@Override
public String findLibrary(String name) {
return nativePath.concat(IOHelper.PLATFORM_SEPARATOR).concat(getNativePrefix()).concat(name).concat(getNativeEx());
}
public String getNativeEx()
{
if(JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE)
return ".dll";
else if(JVMHelper.OS_TYPE == JVMHelper.OS.LINUX)
return ".so";
else if(JVMHelper.OS_TYPE == JVMHelper.OS.MACOSX)
return ".dylib";
return "";
}
public String getNativePrefix()
{
if(JVMHelper.OS_TYPE == JVMHelper.OS.LINUX)
return "lib";
else if(JVMHelper.OS_TYPE == JVMHelper.OS.MACOSX)
return "lib";
return "";
}
@Override
public void addURL(URL url) {
super.addURL(url);
}
}

View file

@ -10,7 +10,6 @@
import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.FileNameMatcher;
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.hwid.HWIDProvider; import pro.gravit.launcher.hwid.HWIDProvider;
import pro.gravit.launcher.hwid.OshiHWIDProvider;
import pro.gravit.launcher.managers.ClientGsonManager; import pro.gravit.launcher.managers.ClientGsonManager;
import pro.gravit.launcher.managers.ClientHookManager; import pro.gravit.launcher.managers.ClientHookManager;
import pro.gravit.launcher.modules.events.PreConfigPhase; import pro.gravit.launcher.modules.events.PreConfigPhase;
@ -50,7 +49,7 @@
public final class ClientLauncher { public final class ClientLauncher {
@LauncherAPI
public static int getClientJVMBits() { public static int getClientJVMBits() {
return LauncherGuardManager.guard.getClientJVMBits(); return LauncherGuardManager.guard.getClientJVMBits();
} }
@ -72,30 +71,30 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
public static final class Params extends StreamObject { public static final class Params extends StreamObject {
// Client paths // Client paths
@LauncherAPI
public final Path assetDir; public final Path assetDir;
@LauncherAPI
public final Path clientDir; public final Path clientDir;
// Client params // Client params
@LauncherAPI
public final PlayerProfile pp; public final PlayerProfile pp;
@LauncherAPI
public final String accessToken; public final String accessToken;
@LauncherAPI
public final boolean autoEnter; public final boolean autoEnter;
@LauncherAPI
public final boolean fullScreen; public final boolean fullScreen;
@LauncherAPI
public final int ram; public final int ram;
@LauncherAPI
public final int width; public final int width;
@LauncherAPI
public final int height; public final int height;
@LauncherAPI
public final long session; public final long session;
@LauncherAPI
public Params(byte[] launcherDigest, Path assetDir, Path clientDir, PlayerProfile pp, String accessToken, public Params(byte[] launcherDigest, Path assetDir, Path clientDir, PlayerProfile pp, String accessToken,
boolean autoEnter, boolean fullScreen, int ram, int width, int height) { boolean autoEnter, boolean fullScreen, int ram, int width, int height) {
// Client paths // Client paths
@ -112,7 +111,7 @@ public Params(byte[] launcherDigest, Path assetDir, Path clientDir, PlayerProfil
this.session = Request.getSession(); this.session = Request.getSession();
} }
@LauncherAPI
public Params(HInput input) throws Exception { public Params(HInput input) throws Exception {
session = input.readLong(); session = input.readLong();
// Client paths // Client paths
@ -163,16 +162,16 @@ public void write(HOutput output) throws IOException {
// Constants // Constants
private static final Path NATIVES_DIR = IOHelper.toPath("natives"); private static final Path NATIVES_DIR = IOHelper.toPath("natives");
private static final Path RESOURCEPACKS_DIR = IOHelper.toPath("resourcepacks"); private static final Path RESOURCEPACKS_DIR = IOHelper.toPath("resourcepacks");
private static PublicURLClassLoader classLoader; private static ClientClassLoader classLoader;
public static class ClientUserProperties { public static class ClientUserProperties {
@LauncherAPI
String[] skinURL; String[] skinURL;
@LauncherAPI
String[] skinDigest; String[] skinDigest;
@LauncherAPI
String[] cloakURL; String[] cloakURL;
@LauncherAPI
String[] cloakDigest; String[] cloakDigest;
} }
@ -234,7 +233,7 @@ private static void addClientArgs(Collection<String> args, ClientProfile profile
} }
} }
@LauncherAPI
public static void setJavaBinPath(Path javaBinPath) { public static void setJavaBinPath(Path javaBinPath) {
JavaBinPath = javaBinPath; JavaBinPath = javaBinPath;
} }
@ -249,7 +248,7 @@ private static void addClientLegacyArgs(Collection<String> args, ClientProfile p
Collections.addAll(args, "--assetsDir", params.assetDir.toString()); Collections.addAll(args, "--assetsDir", params.assetDir.toString());
} }
@LauncherAPI
public static void checkJVMBitsAndVersion() { public static void checkJVMBitsAndVersion() {
if (JVMHelper.JVM_BITS != JVMHelper.OS_BITS) { if (JVMHelper.JVM_BITS != JVMHelper.OS_BITS) {
String error = String.format("У Вас установлена Java %d, но Ваша система определена как %d. Установите Java правильной разрядности", JVMHelper.JVM_BITS, JVMHelper.OS_BITS); String error = String.format("У Вас установлена Java %d, но Ваша система определена как %d. Установите Java правильной разрядности", JVMHelper.JVM_BITS, JVMHelper.OS_BITS);
@ -267,7 +266,7 @@ public static void checkJVMBitsAndVersion() {
} }
} }
@LauncherAPI
public static boolean isLaunched() { public static boolean isLaunched() {
return Launcher.LAUNCHED.get(); return Launcher.LAUNCHED.get();
} }
@ -292,6 +291,10 @@ private static void launch(ClientProfile profile, Params params) throws Throwabl
LogHelper.debug("Args: " + copy); LogHelper.debug("Args: " + copy);
// Resolve main class and method // Resolve main class and method
Class<?> mainClass = classLoader.loadClass(profile.getMainClass()); Class<?> mainClass = classLoader.loadClass(profile.getMainClass());
for(URL u : classLoader.getURLs())
{
LogHelper.info("ClassLoader URL: %s", u.toString());
}
MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity(); MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
Launcher.LAUNCHED.set(true); Launcher.LAUNCHED.set(true);
JVMHelper.fullGC(); JVMHelper.fullGC();
@ -318,7 +321,7 @@ public static void setClientStarted() {
public static PlayerProfile playerProfile; public static PlayerProfile playerProfile;
@LauncherAPI
public static Process launch( public static Process launch(
HashedDir assetHDir, HashedDir clientHDir, HashedDir assetHDir, HashedDir clientHDir,
ClientProfile profile, Params params, boolean pipeOutput) throws Throwable { ClientProfile profile, Params params, boolean pipeOutput) throws Throwable {
@ -429,7 +432,7 @@ public ClientLaunchContext(Params params, ClientProfile profile, HashedDir asset
} }
} }
@LauncherAPI
public static void main(String... args) throws Throwable { public static void main(String... args) throws Throwable {
LauncherEngine.IS_CLIENT.set(true); LauncherEngine.IS_CLIENT.set(true);
LauncherEngine engine = LauncherEngine.clientInstance(); LauncherEngine engine = LauncherEngine.clientInstance();
@ -468,19 +471,18 @@ public static void main(String... args) throws Throwable {
LogHelper.debug("Verifying ClientLauncher sign and classpath"); LogHelper.debug("Verifying ClientLauncher sign and classpath");
LinkedList<Path> classPath = resolveClassPathList(params.clientDir, profile.getClassPath()); LinkedList<Path> classPath = resolveClassPathList(params.clientDir, profile.getClassPath());
for (Path classpathURL : classPath) { for (Path classpathURL : classPath) {
LauncherAgent.addJVMClassPath(classpathURL.normalize().toAbsolutePath()); //LauncherAgent.addJVMClassPath(classpathURL.normalize().toAbsolutePath());
} }
profile.pushOptionalClassPath(cp -> { profile.pushOptionalClassPath(cp -> {
LinkedList<Path> optionalClassPath = resolveClassPathList(params.clientDir, cp); LinkedList<Path> optionalClassPath = resolveClassPathList(params.clientDir, cp);
for (Path classpathURL : optionalClassPath) { for (Path classpathURL : optionalClassPath) {
LauncherAgent.addJVMClassPath(classpathURL.normalize().toAbsolutePath()); //LauncherAgent.addJVMClassPath(classpathURL.normalize().toAbsolutePath());
} }
}); });
URL[] classpathurls = resolveClassPath(params.clientDir, profile.getClassPath()); URL[] classpathurls = resolveClassPath(params.clientDir, profile.getClassPath());
classLoader = new PublicURLClassLoader(classpathurls, ClassLoader.getSystemClassLoader()); classLoader = new ClientClassLoader(classpathurls, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(classLoader); Thread.currentThread().setContextClassLoader(classLoader);
classLoader.nativePath = params.clientDir.resolve(NATIVES_DIR).toString(); classLoader.nativePath = params.clientDir.resolve(NATIVES_DIR).toString();
PublicURLClassLoader.systemclassloader = classLoader;
// Start client with WatchService monitoring // Start client with WatchService monitoring
boolean digest = !profile.isUpdateFastCheck(); boolean digest = !profile.isUpdateFastCheck();
LogHelper.debug("Restore sessions"); LogHelper.debug("Restore sessions");
@ -507,6 +509,8 @@ public static void main(String... args) throws Throwable {
AuthService.uuid = params.pp.uuid; AuthService.uuid = params.pp.uuid;
ClientService.instrumentation = LauncherAgent.inst; ClientService.instrumentation = LauncherAgent.inst;
ClientService.classLoader = classLoader; ClientService.classLoader = classLoader;
classLoader.addURL(IOHelper.getCodeSource(ClientLauncher.class).toUri().toURL());
//classForName(classLoader, "com.google.common.collect.ForwardingMultimap");
ClientService.baseURLs = classpathurls; ClientService.baseURLs = classpathurls;
LogHelper.debug("Starting JVM and client WatchService"); LogHelper.debug("Starting JVM and client WatchService");
FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher(); FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher();
@ -532,6 +536,13 @@ public static void main(String... args) throws Throwable {
launch(profile, params); launch(profile, params);
} }
} }
public static void classForName(ClassLoader loader, String name)
{
try {
Class.forName(name, false, loader);
} catch (ClassNotFoundException ignored) {
}
}
private static URL[] resolveClassPath(Path clientDir, String... classPath) throws IOException { private static URL[] resolveClassPath(Path clientDir, String... classPath) throws IOException {
return resolveClassPathStream(clientDir, classPath).map(IOHelper::toURL).toArray(URL[]::new); return resolveClassPathStream(clientDir, classPath).map(IOHelper::toURL).toArray(URL[]::new);
@ -559,7 +570,7 @@ private static void initGson(ClientModuleManager moduleManager) {
Launcher.gsonManager.initGson(); Launcher.gsonManager.initGson();
} }
@LauncherAPI
public static void setProfile(ClientProfile profile) { public static void setProfile(ClientProfile profile) {
Launcher.profile = profile; Launcher.profile = profile;
LogHelper.debug("New Profile name: %s", profile.getTitle()); LogHelper.debug("New Profile name: %s", profile.getTitle());

View file

@ -1,7 +1,6 @@
package pro.gravit.launcher.client; package pro.gravit.launcher.client;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.JVMHelper; import pro.gravit.utils.helper.JVMHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
@ -17,26 +16,26 @@ public class DirBridge {
public static final String CUSTOMDIR_PROPERTY = "launcher.customdir"; public static final String CUSTOMDIR_PROPERTY = "launcher.customdir";
public static final String USE_OPTDIR_PROPERTY = "launcher.useoptdir"; public static final String USE_OPTDIR_PROPERTY = "launcher.useoptdir";
@LauncherAPI
public static Path dir; public static Path dir;
@LauncherAPI
public static Path dirStore; public static Path dirStore;
@LauncherAPI
public static Path dirProjectStore; public static Path dirProjectStore;
@LauncherAPI
public static Path dirUpdates; public static Path dirUpdates;
@LauncherAPI
public static Path defaultUpdatesDir; public static Path defaultUpdatesDir;
@LauncherAPI
public static boolean useLegacyDir; public static boolean useLegacyDir;
@LauncherAPI
public static void move(Path newDir) throws IOException { public static void move(Path newDir) throws IOException {
IOHelper.move(dirUpdates, newDir); IOHelper.move(dirUpdates, newDir);
dirUpdates = newDir; dirUpdates = newDir;
} }
@LauncherAPI
public static Path getAppDataDir() throws IOException { public static Path getAppDataDir() throws IOException {
boolean isCustomDir = Boolean.getBoolean(System.getProperty(USE_CUSTOMDIR_PROPERTY, "false")); boolean isCustomDir = Boolean.getBoolean(System.getProperty(USE_CUSTOMDIR_PROPERTY, "false"));
if (isCustomDir) { if (isCustomDir) {
@ -66,12 +65,12 @@ public static Path getAppDataDir() throws IOException {
} }
} }
@LauncherAPI
public static Path getLauncherDir(String projectname) throws IOException { public static Path getLauncherDir(String projectname) throws IOException {
return getAppDataDir().resolve(projectname); return getAppDataDir().resolve(projectname);
} }
@LauncherAPI
public static Path getStoreDir(String projectname) throws IOException { public static Path getStoreDir(String projectname) throws IOException {
if (JVMHelper.OS_TYPE == JVMHelper.OS.LINUX) if (JVMHelper.OS_TYPE == JVMHelper.OS.LINUX)
return getAppDataDir().resolve("store"); return getAppDataDir().resolve("store");
@ -81,22 +80,22 @@ else if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE)
return getAppDataDir().resolve("minecraftStore"); return getAppDataDir().resolve("minecraftStore");
} }
@LauncherAPI
public static Path getProjectStoreDir(String projectname) throws IOException { public static Path getProjectStoreDir(String projectname) throws IOException {
return getStoreDir(projectname).resolve(projectname); return getStoreDir(projectname).resolve(projectname);
} }
@LauncherAPI
public static Path getGuardDir() { public static Path getGuardDir() {
return dir.resolve("guard"); return dir.resolve("guard");
} }
@LauncherAPI
public static Path getLegacyLauncherDir(String projectname) { public static Path getLegacyLauncherDir(String projectname) {
return IOHelper.HOME_DIR.resolve(projectname); return IOHelper.HOME_DIR.resolve(projectname);
} }
@LauncherAPI
public static void setUseLegacyDir(boolean b) { public static void setUseLegacyDir(boolean b) {
useLegacyDir = b; useLegacyDir = b;
} }

View file

@ -2,7 +2,6 @@
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.profiles.ClientProfile; import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
@ -24,11 +23,11 @@ public final class ServerPinger {
private final JsonParser parser = new JsonParser(); private final JsonParser parser = new JsonParser();
public static final class Result { public static final class Result {
@LauncherAPI
public final int onlinePlayers; public final int onlinePlayers;
@LauncherAPI
public final int maxPlayers; public final int maxPlayers;
@LauncherAPI
public final String raw; public final String raw;
public Result(int onlinePlayers, int maxPlayers, String raw) { public Result(int onlinePlayers, int maxPlayers, String raw) {
@ -39,7 +38,7 @@ public Result(int onlinePlayers, int maxPlayers, String raw) {
this.raw = raw; this.raw = raw;
} }
@LauncherAPI
public boolean isOverfilled() { public boolean isOverfilled() {
return onlinePlayers >= maxPlayers; return onlinePlayers >= maxPlayers;
} }
@ -75,7 +74,7 @@ private static void writeUTF16String(HOutput output, String s) throws IOExceptio
private Instant cacheTime = null; private Instant cacheTime = null;
@LauncherAPI
public ServerPinger(ClientProfile profile) { public ServerPinger(ClientProfile profile) {
this.address = Objects.requireNonNull(profile.getServerSocketAddress(), "address"); this.address = Objects.requireNonNull(profile.getServerSocketAddress(), "address");
this.version = Objects.requireNonNull(profile.getVersion(), "version"); this.version = Objects.requireNonNull(profile.getVersion(), "version");
@ -194,7 +193,7 @@ private Result modernPing(HInput input, HOutput output) throws IOException {
return new Result(online, max, response); return new Result(online, max, response);
} }
@LauncherAPI
public Result ping() throws IOException { public Result ping() throws IOException {
Instant now = Instant.now(); Instant now = Instant.now();
synchronized (cacheLock) { synchronized (cacheLock) {

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.managers; package pro.gravit.launcher.managers;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.FileNameMatcher;
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.hasher.HashedEntry; import pro.gravit.launcher.hasher.HashedEntry;
@ -19,15 +18,15 @@ public class HasherStore {
public Map<String, HasherStoreEnity> store; public Map<String, HasherStoreEnity> store;
public static class HasherStoreEnity { public static class HasherStoreEnity {
@LauncherAPI
public HashedDir hdir; public HashedDir hdir;
@LauncherAPI
public Path dir; public Path dir;
@LauncherAPI
public Collection<String> shared; public Collection<String> shared;
} }
@LauncherAPI
public void addProfileUpdateDir(ClientProfile profile, Path dir, HashedDir hdir) { public void addProfileUpdateDir(ClientProfile profile, Path dir, HashedDir hdir) {
HasherStoreEnity e = new HasherStoreEnity(); HasherStoreEnity e = new HasherStoreEnity();
e.hdir = hdir; e.hdir = hdir;
@ -37,7 +36,7 @@ public void addProfileUpdateDir(ClientProfile profile, Path dir, HashedDir hdir)
store.put(profile.getTitle(), e); store.put(profile.getTitle(), e);
} }
@LauncherAPI
public void copyCompareFilesTo(String name, Path targetDir, HashedDir targetHDir, String[] shared) { public void copyCompareFilesTo(String name, Path targetDir, HashedDir targetHDir, String[] shared) {
store.forEach((key, e) -> { store.forEach((key, e) -> {
if (key.equals(name)) return; if (key.equals(name)) return;
@ -47,7 +46,7 @@ public void copyCompareFilesTo(String name, Path targetDir, HashedDir targetHDir
}); });
} }
@LauncherAPI
public void recurseCopy(String filename, HashedEntry entry, String name, Path targetDir, Path sourceDir) { public void recurseCopy(String filename, HashedEntry entry, String name, Path targetDir, Path sourceDir) {
if (!IOHelper.isDir(targetDir)) { if (!IOHelper.isDir(targetDir)) {
try { try {

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.managers; package pro.gravit.launcher.managers;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.NewLauncherSettings; import pro.gravit.launcher.NewLauncherSettings;
import pro.gravit.launcher.client.DirBridge; import pro.gravit.launcher.client.DirBridge;
import pro.gravit.launcher.config.JsonConfigurable; import pro.gravit.launcher.config.JsonConfigurable;
@ -32,26 +31,26 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
} }
@LauncherAPI
public static NewLauncherSettings settings; public static NewLauncherSettings settings;
public SettingsManager() { public SettingsManager() {
super(NewLauncherSettings.class, DirBridge.dir.resolve("settings.json")); super(NewLauncherSettings.class, DirBridge.dir.resolve("settings.json"));
} }
@LauncherAPI
@Override @Override
public NewLauncherSettings getConfig() { public NewLauncherSettings getConfig() {
return settings; return settings;
} }
@LauncherAPI
@Override @Override
public NewLauncherSettings getDefaultConfig() { public NewLauncherSettings getDefaultConfig() {
return new NewLauncherSettings(); return new NewLauncherSettings();
} }
@LauncherAPI
@Override @Override
public void setConfig(NewLauncherSettings config) { public void setConfig(NewLauncherSettings config) {
settings = config; settings = config;
@ -63,13 +62,13 @@ public void setConfig(NewLauncherSettings config) {
} }
} }
@LauncherAPI
public void loadHDirStore(Path storePath) throws IOException { public void loadHDirStore(Path storePath) throws IOException {
Files.createDirectories(storePath); Files.createDirectories(storePath);
IOHelper.walk(storePath, new StoreFileVisitor(), false); IOHelper.walk(storePath, new StoreFileVisitor(), false);
} }
@LauncherAPI
public void saveHDirStore(Path storeProjectPath) throws IOException { public void saveHDirStore(Path storeProjectPath) throws IOException {
Files.createDirectories(storeProjectPath); Files.createDirectories(storeProjectPath);
for (NewLauncherSettings.HashedStoreEntry e : settings.lastHDirs) { for (NewLauncherSettings.HashedStoreEntry e : settings.lastHDirs) {
@ -84,12 +83,12 @@ public void saveHDirStore(Path storeProjectPath) throws IOException {
} }
} }
@LauncherAPI
public void loadHDirStore() throws IOException { public void loadHDirStore() throws IOException {
loadHDirStore(DirBridge.dirStore); loadHDirStore(DirBridge.dirStore);
} }
@LauncherAPI
public void saveHDirStore() throws IOException { public void saveHDirStore() throws IOException {
saveHDirStore(DirBridge.dirProjectStore); saveHDirStore(DirBridge.dirProjectStore);
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.utils; package pro.gravit.launcher.utils;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.FileNameMatcher;
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.hasher.HashedEntry; import pro.gravit.launcher.hasher.HashedEntry;
@ -69,7 +68,7 @@ private static Deque<String> toPath(Iterable<Path> path) {
private final boolean digest; private final boolean digest;
@LauncherAPI
public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest) throws IOException { public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean digest) throws IOException {
this.dir = Objects.requireNonNull(dir, "dir"); this.dir = Objects.requireNonNull(dir, "dir");
this.hdir = Objects.requireNonNull(hdir, "hdir"); this.hdir = Objects.requireNonNull(hdir, "hdir");
@ -83,7 +82,7 @@ public DirWatcher(Path dir, HashedDir hdir, FileNameMatcher matcher, boolean dig
} }
@Override @Override
@LauncherAPI
public void close() throws IOException { public void close() throws IOException {
service.close(); service.close();
} }
@ -124,7 +123,7 @@ private void processLoop() throws IOException, InterruptedException {
} }
@Override @Override
@LauncherAPI
public void run() { public void run() {
try { try {
processLoop(); processLoop();

View file

@ -8,17 +8,17 @@
public class ClientPermissions { public class ClientPermissions {
public static final ClientPermissions DEFAULT = new ClientPermissions(); public static final ClientPermissions DEFAULT = new ClientPermissions();
@LauncherAPI @LauncherNetworkAPI
public boolean canAdmin; public boolean canAdmin;
@LauncherAPI @LauncherNetworkAPI
public boolean canServer; public boolean canServer;
@LauncherAPI @LauncherNetworkAPI
public final boolean canUSR1; public final boolean canUSR1;
@LauncherAPI @LauncherNetworkAPI
public final boolean canUSR2; public final boolean canUSR2;
@LauncherAPI @LauncherNetworkAPI
public final boolean canUSR3; public final boolean canUSR3;
@LauncherAPI @LauncherNetworkAPI
public boolean canBot; public boolean canBot;
public ClientPermissions(HInput input) throws IOException { public ClientPermissions(HInput input) throws IOException {
@ -43,7 +43,7 @@ public ClientPermissions(long data) {
canBot = (data & (1 << 5)) != 0; canBot = (data & (1 << 5)) != 0;
} }
@LauncherAPI
public long toLong() { public long toLong() {
long result = 0; long result = 0;
result |= !canAdmin ? 0 : 1; result |= !canAdmin ? 0 : 1;

View file

@ -20,42 +20,42 @@
public final class Launcher { public final class Launcher {
// Authlib constants // Authlib constants
@LauncherAPI
public static final String SKIN_URL_PROPERTY = "skinURL"; public static final String SKIN_URL_PROPERTY = "skinURL";
@LauncherAPI
public static final String SKIN_DIGEST_PROPERTY = "skinDigest"; public static final String SKIN_DIGEST_PROPERTY = "skinDigest";
@LauncherAPI
public static final String CLOAK_URL_PROPERTY = "cloakURL"; public static final String CLOAK_URL_PROPERTY = "cloakURL";
@LauncherAPI
public static final String CLOAK_DIGEST_PROPERTY = "cloakDigest"; public static final String CLOAK_DIGEST_PROPERTY = "cloakDigest";
// Used to determine from clientside is launched from launcher // Used to determine from clientside is launched from launcher
public static final AtomicBoolean LAUNCHED = new AtomicBoolean(false); public static final AtomicBoolean LAUNCHED = new AtomicBoolean(false);
private static final AtomicReference<LauncherConfig> CONFIG = new AtomicReference<>(); private static final AtomicReference<LauncherConfig> CONFIG = new AtomicReference<>();
@LauncherAPI
public static final int PROTOCOL_MAGIC_LEGACY = 0x724724_00 + 24; public static final int PROTOCOL_MAGIC_LEGACY = 0x724724_00 + 24;
@LauncherAPI
public static final int PROTOCOL_MAGIC = 0xA205B064; // e = 2.718281828 public static final int PROTOCOL_MAGIC = 0xA205B064; // e = 2.718281828
// Constants // Constants
@LauncherAPI
public static final String RUNTIME_DIR = "runtime"; public static final String RUNTIME_DIR = "runtime";
@LauncherAPI
public static final String GUARD_DIR = "guard"; public static final String GUARD_DIR = "guard";
@LauncherAPI
public static final String CONFIG_FILE = "config.bin"; public static final String CONFIG_FILE = "config.bin";
@LauncherAPI
public static ClientProfile profile; public static ClientProfile profile;
@LauncherAPI
public static final String INIT_SCRIPT_FILE = "init.js"; public static final String INIT_SCRIPT_FILE = "init.js";
@LauncherAPI
public static final String API_SCRIPT_FILE = "engine/api.js"; public static final String API_SCRIPT_FILE = "engine/api.js";
public static final String CONFIG_SCRIPT_FILE = "config.js"; public static final String CONFIG_SCRIPT_FILE = "config.js";
private static final Pattern UUID_PATTERN = Pattern.compile("-", Pattern.LITERAL); private static final Pattern UUID_PATTERN = Pattern.compile("-", Pattern.LITERAL);
public static GsonManager gsonManager; public static GsonManager gsonManager;
@LauncherAPI
public static LauncherConfig getConfig() { public static LauncherConfig getConfig() {
LauncherConfig config = CONFIG.get(); LauncherConfig config = CONFIG.get();
if (config == null) { if (config == null) {
@ -69,12 +69,12 @@ public static LauncherConfig getConfig() {
return config; return config;
} }
@LauncherAPI
public static void setConfig(LauncherConfig cfg) { public static void setConfig(LauncherConfig cfg) {
CONFIG.set(cfg); CONFIG.set(cfg);
} }
@LauncherAPI
public static URL getResourceURL(String name) throws IOException { public static URL getResourceURL(String name) throws IOException {
LauncherConfig config = getConfig(); LauncherConfig config = getConfig();
byte[] validDigest = config.runtime.get(name); byte[] validDigest = config.runtime.get(name);
@ -105,7 +105,7 @@ public static URL getResourceURL(String name, String prefix) throws IOException
return url; return url;
} }
@LauncherAPI
public static String toHash(UUID uuid) { public static String toHash(UUID uuid) {
return UUID_PATTERN.matcher(uuid.toString()).replaceAll(""); return UUID_PATTERN.matcher(uuid.toString()).replaceAll("");
} }

View file

@ -24,16 +24,16 @@ public static AutogenConfig getAutogenConfig() {
// Instance // Instance
public String address; public String address;
@LauncherAPI
public final String projectName; public final String projectName;
public final int clientPort; public final int clientPort;
public String secretKeyClient; public String secretKeyClient;
public String oemUnlockKey; public String oemUnlockKey;
public final LauncherTrustManager trustManager; public final LauncherTrustManager trustManager;
@LauncherAPI
public final ECPublicKey publicKey; public final ECPublicKey publicKey;
@LauncherAPI
public final Map<String, byte[]> runtime; public final Map<String, byte[]> runtime;
public final boolean isWarningMissArchJava; public final boolean isWarningMissArchJava;
public boolean isNettyEnabled; public boolean isNettyEnabled;
@ -45,7 +45,7 @@ public static AutogenConfig getAutogenConfig() {
public final String secureCheckSalt; public final String secureCheckSalt;
public final String passwordEncryptKey; public final String passwordEncryptKey;
@LauncherAPI
public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException { public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException {
publicKey = SecurityHelper.toPublicECKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH)); publicKey = SecurityHelper.toPublicECKey(input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH));
secureCheckHash = config.secureCheckHash; secureCheckHash = config.secureCheckHash;
@ -84,7 +84,7 @@ public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException
runtime = Collections.unmodifiableMap(localResources); runtime = Collections.unmodifiableMap(localResources);
} }
@LauncherAPI
public LauncherConfig(String address, ECPublicKey publicKey, Map<String, byte[]> runtime, String projectName) { public LauncherConfig(String address, ECPublicKey publicKey, Map<String, byte[]> runtime, String projectName) {
this.address = address; this.address = address;
this.publicKey = publicKey; this.publicKey = publicKey;

View file

@ -1,7 +1,5 @@
package pro.gravit.launcher.config; package pro.gravit.launcher.config;
import pro.gravit.launcher.LauncherAPI;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.file.Path; import java.nio.file.Path;
@ -9,7 +7,7 @@ public abstract class JsonConfigurable<T> implements JsonConfigurableInterface<T
private transient final Type type; private transient final Type type;
protected transient final Path configPath; protected transient final Path configPath;
@LauncherAPI
public JsonConfigurable(Type type, Path configPath) { public JsonConfigurable(Type type, Path configPath) {
this.type = type; this.type = type;
this.configPath = configPath; this.configPath = configPath;
@ -25,12 +23,12 @@ public Type getType() {
return type; return type;
} }
@LauncherAPI
public abstract T getConfig(); public abstract T getConfig();
@LauncherAPI
public abstract T getDefaultConfig(); public abstract T getDefaultConfig();
@LauncherAPI
public abstract void setConfig(T config); public abstract void setConfig(T config);
} }

View file

@ -2,7 +2,6 @@
import com.google.gson.Gson; import com.google.gson.Gson;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
@ -13,24 +12,24 @@
import java.nio.file.Path; import java.nio.file.Path;
public interface JsonConfigurableInterface<T> { public interface JsonConfigurableInterface<T> {
@LauncherAPI
default void saveConfig() throws IOException { default void saveConfig() throws IOException {
saveConfig(getPath()); saveConfig(getPath());
} }
@LauncherAPI
default void loadConfig() throws IOException { default void loadConfig() throws IOException {
loadConfig(getPath()); loadConfig(getPath());
} }
@LauncherAPI
default void saveConfig(Gson gson, Path configPath) throws IOException { default void saveConfig(Gson gson, Path configPath) throws IOException {
try (BufferedWriter writer = IOHelper.newWriter(configPath)) { try (BufferedWriter writer = IOHelper.newWriter(configPath)) {
gson.toJson(getConfig(), getType(), writer); gson.toJson(getConfig(), getType(), writer);
} }
} }
@LauncherAPI
default void loadConfig(Gson gson, Path configPath) throws IOException { default void loadConfig(Gson gson, Path configPath) throws IOException {
if (generateConfigIfNotExists(configPath)) return; if (generateConfigIfNotExists(configPath)) return;
try (BufferedReader reader = IOHelper.newReader(configPath)) { try (BufferedReader reader = IOHelper.newReader(configPath)) {
@ -41,29 +40,29 @@ default void loadConfig(Gson gson, Path configPath) throws IOException {
} }
} }
@LauncherAPI
default void saveConfig(Path configPath) throws IOException { default void saveConfig(Path configPath) throws IOException {
saveConfig(Launcher.gsonManager.configGson, configPath); saveConfig(Launcher.gsonManager.configGson, configPath);
} }
@LauncherAPI
default void loadConfig(Path configPath) throws IOException { default void loadConfig(Path configPath) throws IOException {
loadConfig(Launcher.gsonManager.configGson, configPath); loadConfig(Launcher.gsonManager.configGson, configPath);
} }
@LauncherAPI
default void resetConfig() throws IOException { default void resetConfig() throws IOException {
setConfig(getDefaultConfig()); setConfig(getDefaultConfig());
saveConfig(); saveConfig();
} }
@LauncherAPI
default void resetConfig(Path newPath) throws IOException { default void resetConfig(Path newPath) throws IOException {
setConfig(getDefaultConfig()); setConfig(getDefaultConfig());
saveConfig(newPath); saveConfig(newPath);
} }
@LauncherAPI
default boolean generateConfigIfNotExists(Path path) throws IOException { default boolean generateConfigIfNotExists(Path path) throws IOException {
if (IOHelper.isFile(path)) if (IOHelper.isFile(path))
return false; return false;
@ -71,7 +70,7 @@ default boolean generateConfigIfNotExists(Path path) throws IOException {
return true; return true;
} }
@LauncherAPI
default boolean generateConfigIfNotExists() throws IOException { default boolean generateConfigIfNotExists() throws IOException {
if (IOHelper.isFile(getPath())) if (IOHelper.isFile(getPath()))
return false; return false;
@ -79,16 +78,16 @@ default boolean generateConfigIfNotExists() throws IOException {
return true; return true;
} }
@LauncherAPI
T getConfig(); T getConfig();
@LauncherAPI
T getDefaultConfig(); T getDefaultConfig();
@LauncherAPI
void setConfig(T config); void setConfig(T config);
@LauncherAPI
Path getPath(); Path getPath();
Type getType(); Type getType();

View file

@ -1,10 +1,10 @@
package pro.gravit.launcher.events.request; package pro.gravit.launcher.events.request;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.RequestEvent; import pro.gravit.launcher.events.RequestEvent;
public class VerifySecureTokenRequestEvent extends RequestEvent { public class VerifySecureTokenRequestEvent extends RequestEvent {
@LauncherAPI @LauncherNetworkAPI
public final boolean success; public final boolean success;
@Override @Override

View file

@ -1,22 +1,22 @@
package pro.gravit.launcher.hwid; package pro.gravit.launcher.hwid;
import com.google.gson.Gson; import com.google.gson.Gson;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import java.util.Objects; import java.util.Objects;
import java.util.StringJoiner; import java.util.StringJoiner;
public class OshiHWID implements HWID { public class OshiHWID implements HWID {
public static Gson gson = new Gson(); public static Gson gson = new Gson();
@LauncherAPI @LauncherNetworkAPI
public long totalMemory = 0; public long totalMemory = 0;
@LauncherAPI @LauncherNetworkAPI
public String serialNumber; public String serialNumber;
@LauncherAPI @LauncherNetworkAPI
public String HWDiskSerial; public String HWDiskSerial;
@LauncherAPI @LauncherNetworkAPI
public String processorID; public String processorID;
@LauncherAPI @LauncherNetworkAPI
public String macAddr; public String macAddr;
@Override @Override

View file

@ -1,6 +1,6 @@
package pro.gravit.launcher.profiles; package pro.gravit.launcher.profiles;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.hasher.FileNameMatcher; import pro.gravit.launcher.hasher.FileNameMatcher;
import pro.gravit.launcher.hasher.HashedDir; import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.profiles.optional.OptionalDepend; import pro.gravit.launcher.profiles.optional.OptionalDepend;
@ -14,7 +14,7 @@
import java.util.*; import java.util.*;
public final class ClientProfile implements Comparable<ClientProfile> { public final class ClientProfile implements Comparable<ClientProfile> {
@LauncherAPI
public enum Version { public enum Version {
MC125("1.2.5", 29), MC125("1.2.5", 29),
MC147("1.4.7", 51), MC147("1.4.7", 51),
@ -73,54 +73,54 @@ public String toString() {
private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher( private static final FileNameMatcher ASSET_MATCHER = new FileNameMatcher(
new String[0], new String[]{"indexes", "objects"}, new String[0]); new String[0], new String[]{"indexes", "objects"}, new String[0]);
// Version // Version
@LauncherAPI @LauncherNetworkAPI
private String version; private String version;
@LauncherAPI @LauncherNetworkAPI
private String assetIndex; private String assetIndex;
@LauncherAPI @LauncherNetworkAPI
private String dir; private String dir;
@LauncherAPI @LauncherNetworkAPI
private String assetDir; private String assetDir;
// Client // Client
@LauncherAPI @LauncherNetworkAPI
private int sortIndex; private int sortIndex;
@LauncherAPI @LauncherNetworkAPI
private UUID uuid; private UUID uuid;
@LauncherAPI @LauncherNetworkAPI
private String title; private String title;
@LauncherAPI @LauncherNetworkAPI
private String info; private String info;
@LauncherAPI @LauncherNetworkAPI
private String serverAddress; private String serverAddress;
@LauncherAPI @LauncherNetworkAPI
private int serverPort; private int serverPort;
// Updater and client watch service // Updater and client watch service
@LauncherAPI @LauncherNetworkAPI
private final List<String> update = new ArrayList<>(); private final List<String> update = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final List<String> updateExclusions = new ArrayList<>(); private final List<String> updateExclusions = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final List<String> updateShared = new ArrayList<>(); private final List<String> updateShared = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final List<String> updateVerify = new ArrayList<>(); private final List<String> updateVerify = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final Set<OptionalFile> updateOptional = new HashSet<>(); private final Set<OptionalFile> updateOptional = new HashSet<>();
@LauncherAPI @LauncherNetworkAPI
private boolean updateFastCheck; private boolean updateFastCheck;
@LauncherAPI @LauncherNetworkAPI
private boolean useWhitelist; private boolean useWhitelist;
// Client launcher // Client launcher
@LauncherAPI @LauncherNetworkAPI
private String mainClass; private String mainClass;
@LauncherAPI @LauncherNetworkAPI
private final List<String> jvmArgs = new ArrayList<>(); private final List<String> jvmArgs = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final List<String> classPath = new ArrayList<>(); private final List<String> classPath = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final List<String> clientArgs = new ArrayList<>(); private final List<String> clientArgs = new ArrayList<>();
@LauncherAPI @LauncherNetworkAPI
private final List<String> whitelist = new ArrayList<>(); private final List<String> whitelist = new ArrayList<>();
@Override @Override
@ -128,27 +128,27 @@ public int compareTo(ClientProfile o) {
return Integer.compare(getSortIndex(), o.getSortIndex()); return Integer.compare(getSortIndex(), o.getSortIndex());
} }
@LauncherAPI
public String getAssetIndex() { public String getAssetIndex() {
return assetIndex; return assetIndex;
} }
@LauncherAPI
public FileNameMatcher getAssetUpdateMatcher() { public FileNameMatcher getAssetUpdateMatcher() {
return getVersion().compareTo(Version.MC1710) >= 0 ? ASSET_MATCHER : null; return getVersion().compareTo(Version.MC1710) >= 0 ? ASSET_MATCHER : null;
} }
@LauncherAPI
public String[] getClassPath() { public String[] getClassPath() {
return classPath.toArray(new String[0]); return classPath.toArray(new String[0]);
} }
@LauncherAPI
public String[] getClientArgs() { public String[] getClientArgs() {
return clientArgs.toArray(new String[0]); return clientArgs.toArray(new String[0]);
} }
@LauncherAPI
public String getDir() { public String getDir() {
return dir; return dir;
} }
@ -157,12 +157,12 @@ public void setDir(String dir) {
this.dir = dir; this.dir = dir;
} }
@LauncherAPI
public String getAssetDir() { public String getAssetDir() {
return assetDir; return assetDir;
} }
@LauncherAPI
public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) { public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) {
String[] updateArray = update.toArray(new String[0]); String[] updateArray = update.toArray(new String[0]);
String[] verifyArray = updateVerify.toArray(new String[0]); String[] verifyArray = updateVerify.toArray(new String[0]);
@ -179,27 +179,27 @@ public FileNameMatcher getClientUpdateMatcher(/*boolean excludeOptional*/) {
return new FileNameMatcher(updateArray, verifyArray, exclusionsArray); return new FileNameMatcher(updateArray, verifyArray, exclusionsArray);
} }
@LauncherAPI
public String[] getJvmArgs() { public String[] getJvmArgs() {
return jvmArgs.toArray(new String[0]); return jvmArgs.toArray(new String[0]);
} }
@LauncherAPI
public String getMainClass() { public String getMainClass() {
return mainClass; return mainClass;
} }
@LauncherAPI
public String getServerAddress() { public String getServerAddress() {
return serverAddress; return serverAddress;
} }
@LauncherAPI
public Set<OptionalFile> getOptional() { public Set<OptionalFile> getOptional() {
return updateOptional; return updateOptional;
} }
@LauncherAPI
public void updateOptionalGraph() { public void updateOptionalGraph() {
for (OptionalFile file : updateOptional) { for (OptionalFile file : updateOptional) {
if (file.dependenciesFile != null) { if (file.dependenciesFile != null) {
@ -217,19 +217,19 @@ public void updateOptionalGraph() {
} }
} }
@LauncherAPI
public OptionalFile getOptionalFile(String file, OptionalType type) { public OptionalFile getOptionalFile(String file, OptionalType type) {
for (OptionalFile f : updateOptional) for (OptionalFile f : updateOptional)
if (f.type.equals(type) && f.name.equals(file)) return f; if (f.type.equals(type) && f.name.equals(file)) return f;
return null; return null;
} }
@LauncherAPI
public Collection<String> getShared() { public Collection<String> getShared() {
return updateShared; return updateShared;
} }
@LauncherAPI
public void markOptional(String name, OptionalType type) { public void markOptional(String name, OptionalType type) {
OptionalFile file = getOptionalFile(name, type); OptionalFile file = getOptionalFile(name, type);
if (file == null) { if (file == null) {
@ -238,7 +238,7 @@ public void markOptional(String name, OptionalType type) {
markOptional(file); markOptional(file);
} }
@LauncherAPI
public void markOptional(OptionalFile file) { public void markOptional(OptionalFile file) {
if (file.mark) return; if (file.mark) return;
@ -257,7 +257,7 @@ public void markOptional(OptionalFile file) {
} }
} }
@LauncherAPI
public void unmarkOptional(String name, OptionalType type) { public void unmarkOptional(String name, OptionalType type) {
OptionalFile file = getOptionalFile(name, type); OptionalFile file = getOptionalFile(name, type);
if (file == null) { if (file == null) {
@ -266,7 +266,7 @@ public void unmarkOptional(String name, OptionalType type) {
unmarkOptional(file); unmarkOptional(file);
} }
@LauncherAPI
public void unmarkOptional(OptionalFile file) { public void unmarkOptional(OptionalFile file) {
if (!file.mark) return; if (!file.mark) return;
file.mark = false; file.mark = false;
@ -330,58 +330,58 @@ public interface pushOptionalClassPathCallback {
void run(String[] opt) throws IOException; void run(String[] opt) throws IOException;
} }
@LauncherAPI
public int getServerPort() { public int getServerPort() {
return serverPort; return serverPort;
} }
@LauncherAPI
public InetSocketAddress getServerSocketAddress() { public InetSocketAddress getServerSocketAddress() {
return InetSocketAddress.createUnresolved(getServerAddress(), getServerPort()); return InetSocketAddress.createUnresolved(getServerAddress(), getServerPort());
} }
@LauncherAPI
public int getSortIndex() { public int getSortIndex() {
return sortIndex; return sortIndex;
} }
@LauncherAPI
public String getTitle() { public String getTitle() {
return title; return title;
} }
@LauncherAPI
public String getInfo() { public String getInfo() {
return info; return info;
} }
@LauncherAPI
public Version getVersion() { public Version getVersion() {
return Version.byName(version); return Version.byName(version);
} }
@LauncherAPI
public boolean isUpdateFastCheck() { public boolean isUpdateFastCheck() {
return updateFastCheck; return updateFastCheck;
} }
@LauncherAPI
public boolean isWhitelistContains(String username) { public boolean isWhitelistContains(String username) {
if (!useWhitelist) return true; if (!useWhitelist) return true;
return whitelist.stream().anyMatch(profileCaseSensitive ? e -> e.equals(username) : e -> e.equalsIgnoreCase(username)); return whitelist.stream().anyMatch(profileCaseSensitive ? e -> e.equals(username) : e -> e.equalsIgnoreCase(username));
} }
@LauncherAPI
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
} }
@LauncherAPI
public void setInfo(String info) { public void setInfo(String info) {
this.info = info; this.info = info;
} }
@LauncherAPI
public void setVersion(Version version) { public void setVersion(Version version) {
this.version = version.name; this.version = version.name;
} }
@ -399,7 +399,7 @@ public UUID getUUID() {
return uuid; return uuid;
} }
@LauncherAPI
public void verify() { public void verify() {
// Version // Version
getVersion(); getVersion();

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.profiles; package pro.gravit.launcher.profiles;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.stream.StreamObject; import pro.gravit.launcher.serialize.stream.StreamObject;
@ -12,26 +11,26 @@
import java.util.UUID; import java.util.UUID;
public final class PlayerProfile extends StreamObject { public final class PlayerProfile extends StreamObject {
@LauncherAPI
public static PlayerProfile newOfflineProfile(String username) { public static PlayerProfile newOfflineProfile(String username) {
return new PlayerProfile(offlineUUID(username), username, null, null); return new PlayerProfile(offlineUUID(username), username, null, null);
} }
@LauncherAPI
public static UUID offlineUUID(String username) { public static UUID offlineUUID(String username) {
return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username)); return UUID.nameUUIDFromBytes(IOHelper.encodeASCII("OfflinePlayer:" + username));
} }
@LauncherAPI
public final UUID uuid; public final UUID uuid;
@LauncherAPI
public final String username; public final String username;
@LauncherAPI
public final Texture skin, cloak; public final Texture skin, cloak;
@LauncherAPI
public PlayerProfile(HInput input) throws IOException { public PlayerProfile(HInput input) throws IOException {
uuid = input.readUUID(); uuid = input.readUUID();
username = VerifyHelper.verifyUsername(input.readString(64)); username = VerifyHelper.verifyUsername(input.readString(64));
@ -39,7 +38,7 @@ public PlayerProfile(HInput input) throws IOException {
cloak = input.readBoolean() ? new Texture(input) : null; cloak = input.readBoolean() ? new Texture(input) : null;
} }
@LauncherAPI
public PlayerProfile(UUID uuid, String username, Texture skin, Texture cloak) { public PlayerProfile(UUID uuid, String username, Texture skin, Texture cloak) {
this.uuid = Objects.requireNonNull(uuid, "uuid"); this.uuid = Objects.requireNonNull(uuid, "uuid");
this.username = VerifyHelper.verifyUsername(username); this.username = VerifyHelper.verifyUsername(username);

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.profiles; package pro.gravit.launcher.profiles;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.stream.StreamObject; import pro.gravit.launcher.serialize.stream.StreamObject;
@ -17,18 +16,18 @@ public final class Texture extends StreamObject {
private static final SecurityHelper.DigestAlgorithm DIGEST_ALGO = SecurityHelper.DigestAlgorithm.SHA256; private static final SecurityHelper.DigestAlgorithm DIGEST_ALGO = SecurityHelper.DigestAlgorithm.SHA256;
// Instance // Instance
@LauncherAPI
public final String url; public final String url;
@LauncherAPI
public final byte[] digest; public final byte[] digest;
@LauncherAPI
public Texture(HInput input) throws IOException { public Texture(HInput input) throws IOException {
url = IOHelper.verifyURL(input.readASCII(2048)); url = IOHelper.verifyURL(input.readASCII(2048));
digest = input.readByteArray(-DIGEST_ALGO.bytes); digest = input.readByteArray(-DIGEST_ALGO.bytes);
} }
@LauncherAPI
public Texture(String url, boolean cloak) throws IOException { public Texture(String url, boolean cloak) throws IOException {
this.url = IOHelper.verifyURL(url); this.url = IOHelper.verifyURL(url);
@ -45,7 +44,7 @@ public Texture(String url, boolean cloak) throws IOException {
digest = SecurityHelper.digest(DIGEST_ALGO, new URL(url)); digest = SecurityHelper.digest(DIGEST_ALGO, new URL(url));
} }
@LauncherAPI
public Texture(String url, byte[] digest) { public Texture(String url, byte[] digest) {
this.url = IOHelper.verifyURL(url); this.url = IOHelper.verifyURL(url);
this.digest = Objects.requireNonNull(digest, "digest"); this.digest = Objects.requireNonNull(digest, "digest");

View file

@ -1,10 +1,10 @@
package pro.gravit.launcher.profiles.optional; package pro.gravit.launcher.profiles.optional;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
public class OptionalDepend { public class OptionalDepend {
@LauncherAPI @LauncherNetworkAPI
public String name; public String name;
@LauncherAPI @LauncherNetworkAPI
public OptionalType type; public OptionalType type;
} }

View file

@ -1,6 +1,6 @@
package pro.gravit.launcher.profiles.optional; package pro.gravit.launcher.profiles.optional;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
@ -10,33 +10,33 @@
import java.util.Set; import java.util.Set;
public class OptionalFile { public class OptionalFile {
@LauncherAPI @LauncherNetworkAPI
public String[] list; public String[] list;
@LauncherAPI @LauncherNetworkAPI
public OptionalType type; public OptionalType type;
@LauncherAPI @LauncherNetworkAPI
public boolean mark; public boolean mark;
@LauncherAPI @LauncherNetworkAPI
public final boolean visible = true; public final boolean visible = true;
@LauncherAPI @LauncherNetworkAPI
public String name; public String name;
@LauncherAPI @LauncherNetworkAPI
public String info; public String info;
@LauncherAPI @LauncherNetworkAPI
public OptionalDepend[] dependenciesFile; public OptionalDepend[] dependenciesFile;
@LauncherAPI @LauncherNetworkAPI
public OptionalDepend[] conflictFile; public OptionalDepend[] conflictFile;
@LauncherAPI @LauncherNetworkAPI
public transient OptionalFile[] dependencies; public transient OptionalFile[] dependencies;
@LauncherAPI @LauncherNetworkAPI
public transient OptionalFile[] conflict; public transient OptionalFile[] conflict;
@LauncherAPI @LauncherNetworkAPI
public int subTreeLevel = 1; public int subTreeLevel = 1;
@LauncherAPI @LauncherNetworkAPI
public boolean isPreset; public boolean isPreset;
@LauncherAPI @LauncherNetworkAPI
public final long permissions = 0L; public final long permissions = 0L;
@LauncherAPI
public transient Set<OptionalFile> dependenciesCount; public transient Set<OptionalFile> dependenciesCount;
@Override @Override
@ -51,32 +51,32 @@ public int hashCode() {
return Objects.hash(name); return Objects.hash(name);
} }
@LauncherAPI
public OptionalType getType() { public OptionalType getType() {
return OptionalType.FILE; return OptionalType.FILE;
} }
@LauncherAPI
public String getName() { public String getName() {
return name; return name;
} }
@LauncherAPI
public boolean isVisible() { public boolean isVisible() {
return visible; return visible;
} }
@LauncherAPI
public boolean isMark() { public boolean isMark() {
return mark; return mark;
} }
@LauncherAPI
public long getPermissions() { public long getPermissions() {
return permissions; return permissions;
} }
@LauncherAPI
public void writeType(HOutput output) throws IOException { public void writeType(HOutput output) throws IOException {
switch (type) { switch (type) {
@ -98,7 +98,7 @@ public void writeType(HOutput output) throws IOException {
} }
} }
@LauncherAPI
public static OptionalType readType(HInput input) throws IOException { public static OptionalType readType(HInput input) throws IOException {
int t = input.readInt(); int t = input.readInt();
OptionalType type; OptionalType type;

View file

@ -1,15 +1,14 @@
package pro.gravit.launcher.profiles.optional; package pro.gravit.launcher.profiles.optional;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
@LauncherAPI
public enum OptionalType { public enum OptionalType {
@LauncherAPI @LauncherNetworkAPI
FILE, FILE,
@LauncherAPI @LauncherNetworkAPI
CLASSPATH, CLASSPATH,
@LauncherAPI @LauncherNetworkAPI
JVMARGS, JVMARGS,
@LauncherAPI @LauncherNetworkAPI
CLIENTARGS CLIENTARGS
} }

View file

@ -1,7 +1,6 @@
package pro.gravit.launcher.request; package pro.gravit.launcher.request;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.request.websockets.StandartClientWebSocketService; import pro.gravit.launcher.request.websockets.StandartClientWebSocketService;
import pro.gravit.launcher.request.websockets.WebSocketRequest; import pro.gravit.launcher.request.websockets.WebSocketRequest;
@ -24,14 +23,14 @@ public static long getSession() {
return Request.session; return Request.session;
} }
@LauncherAPI
public static void requestError(String message) throws RequestException { public static void requestError(String message) throws RequestException {
throw new RequestException(message); throw new RequestException(message);
} }
private transient final AtomicBoolean started = new AtomicBoolean(false); private transient final AtomicBoolean started = new AtomicBoolean(false);
@LauncherAPI
public R request() throws Exception { public R request() throws Exception {
if (!started.compareAndSet(false, true)) if (!started.compareAndSet(false, true))
throw new IllegalStateException("Request already started"); throw new IllegalStateException("Request already started");
@ -40,7 +39,7 @@ public R request() throws Exception {
return requestDo(service); return requestDo(service);
} }
@LauncherAPI
public R request(StandartClientWebSocketService service) throws Exception { public R request(StandartClientWebSocketService service) throws Exception {
if (!started.compareAndSet(false, true)) if (!started.compareAndSet(false, true))
throw new IllegalStateException("Request already started"); throw new IllegalStateException("Request already started");

View file

@ -1,23 +1,21 @@
package pro.gravit.launcher.request; package pro.gravit.launcher.request;
import pro.gravit.launcher.LauncherAPI;
import java.io.IOException; import java.io.IOException;
public final class RequestException extends IOException { public final class RequestException extends IOException {
private static final long serialVersionUID = 7558237657082664821L; private static final long serialVersionUID = 7558237657082664821L;
@LauncherAPI
public RequestException(String message) { public RequestException(String message) {
super(message); super(message);
} }
@LauncherAPI
public RequestException(String message, Throwable exc) { public RequestException(String message, Throwable exc) {
super(message, exc); super(message, exc);
} }
@LauncherAPI
public RequestException(Throwable exc) { public RequestException(Throwable exc) {
super(exc); super(exc);
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request; package pro.gravit.launcher.request;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.stream.EnumSerializer; import pro.gravit.launcher.serialize.stream.EnumSerializer;
@ -15,7 +14,7 @@ public enum RequestType implements EnumSerializer.Itf {
CUSTOM(255); // Custom requests CUSTOM(255); // Custom requests
private static final EnumSerializer<RequestType> SERIALIZER = new EnumSerializer<>(RequestType.class); private static final EnumSerializer<RequestType> SERIALIZER = new EnumSerializer<>(RequestType.class);
@LauncherAPI
public static RequestType read(HInput input) throws IOException { public static RequestType read(HInput input) throws IOException {
return SERIALIZER.read(input); return SERIALIZER.read(input);
} }

View file

@ -1,12 +1,11 @@
package pro.gravit.launcher.request.admin; package pro.gravit.launcher.request.admin;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.events.request.ExecCommandRequestEvent; import pro.gravit.launcher.events.request.ExecCommandRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.websockets.WebSocketRequest; import pro.gravit.launcher.request.websockets.WebSocketRequest;
public class ExecCommandRequest extends Request<ExecCommandRequestEvent> implements WebSocketRequest { public class ExecCommandRequest extends Request<ExecCommandRequestEvent> implements WebSocketRequest {
@LauncherAPI
public final String cmd; public final String cmd;
public ExecCommandRequest(String cmd) { public ExecCommandRequest(String cmd) {

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request.auth; package pro.gravit.launcher.request.auth;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.AuthRequestEvent; import pro.gravit.launcher.events.request.AuthRequestEvent;
import pro.gravit.launcher.hwid.HWID; import pro.gravit.launcher.hwid.HWID;
@ -46,7 +45,7 @@ public enum ConnectTypes {
PROXY PROXY
} }
@LauncherAPI
public AuthRequest(String login, byte[] password, HWID hwid) { public AuthRequest(String login, byte[] password, HWID hwid) {
this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty");
this.password = new AuthECPassword(password.clone()); this.password = new AuthECPassword(password.clone());
@ -57,7 +56,7 @@ public AuthRequest(String login, byte[] password, HWID hwid) {
authType = ConnectTypes.CLIENT; authType = ConnectTypes.CLIENT;
} }
@LauncherAPI
public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) { public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) {
this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty");
this.password = new AuthECPassword(password.clone()); this.password = new AuthECPassword(password.clone());
@ -68,7 +67,7 @@ public AuthRequest(String login, byte[] password, HWID hwid, String auth_id) {
authType = ConnectTypes.CLIENT; authType = ConnectTypes.CLIENT;
} }
@LauncherAPI
public AuthRequest(String login, byte[] password, HWID hwid, String customText, String auth_id) { public AuthRequest(String login, byte[] password, HWID hwid, String customText, String auth_id) {
this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty"); this.login = VerifyHelper.verify(login, VerifyHelper.NOT_EMPTY, "Login can't be empty");
this.password = new AuthECPassword(password.clone()); this.password = new AuthECPassword(password.clone());

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request.auth; package pro.gravit.launcher.request.auth;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.CheckServerRequestEvent; import pro.gravit.launcher.events.request.CheckServerRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -13,7 +12,7 @@ public final class CheckServerRequest extends Request<CheckServerRequestEvent> i
@LauncherNetworkAPI @LauncherNetworkAPI
private final String serverID; private final String serverID;
@LauncherAPI
public CheckServerRequest(String username, String serverID) { public CheckServerRequest(String username, String serverID) {
this.username = VerifyHelper.verifyUsername(username); this.username = VerifyHelper.verifyUsername(username);
this.serverID = VerifyHelper.verifyServerID(serverID); this.serverID = VerifyHelper.verifyServerID(serverID);

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request.auth; package pro.gravit.launcher.request.auth;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.JoinServerRequestEvent; import pro.gravit.launcher.events.request.JoinServerRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -17,7 +16,7 @@ public final class JoinServerRequest extends Request<JoinServerRequestEvent> imp
@LauncherNetworkAPI @LauncherNetworkAPI
private final String serverID; private final String serverID;
@LauncherAPI
public JoinServerRequest(String username, String accessToken, String serverID) { public JoinServerRequest(String username, String accessToken, String serverID) {
this.username = VerifyHelper.verifyUsername(username); this.username = VerifyHelper.verifyUsername(username);
this.accessToken = accessToken; this.accessToken = accessToken;

View file

@ -1,7 +1,6 @@
package pro.gravit.launcher.request.update; package pro.gravit.launcher.request.update;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.LauncherRequestEvent; import pro.gravit.launcher.events.request.LauncherRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -30,16 +29,16 @@ public final class LauncherRequest extends Request<LauncherRequestEvent> impleme
public final String secureSalt; public final String secureSalt;
@LauncherNetworkAPI @LauncherNetworkAPI
public int launcher_type = EXE_BINARY ? 2 : 1; public int launcher_type = EXE_BINARY ? 2 : 1;
@LauncherAPI
public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class); public static final Path BINARY_PATH = IOHelper.getCodeSource(Launcher.class);
@LauncherAPI
public static final Path C_BINARY_PATH = BINARY_PATH.getParent().resolve(IOHelper.getFileName(BINARY_PATH) + ".tmp"); public static final Path C_BINARY_PATH = BINARY_PATH.getParent().resolve(IOHelper.getFileName(BINARY_PATH) + ".tmp");
@LauncherAPI
public static final boolean EXE_BINARY = IOHelper.hasExtension(BINARY_PATH, "exe"); public static final boolean EXE_BINARY = IOHelper.hasExtension(BINARY_PATH, "exe");
@LauncherAPI
public static void update(LauncherRequestEvent result) throws IOException { public static void update(LauncherRequestEvent result) throws IOException {
List<String> args = new ArrayList<>(8); List<String> args = new ArrayList<>(8);
args.add(IOHelper.resolveJavaBin(null).toString()); args.add(IOHelper.resolveJavaBin(null).toString());
@ -90,7 +89,6 @@ public LauncherRequestEvent requestDo(StandartClientWebSocketService service) th
return result; return result;
} }
@LauncherAPI
public LauncherRequest() { public LauncherRequest() {
Path launcherPath = IOHelper.getCodeSource(LauncherRequest.class); Path launcherPath = IOHelper.getCodeSource(LauncherRequest.class);
try { try {

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request.uuid; package pro.gravit.launcher.request.uuid;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.BatchProfileByUsernameRequestEvent; import pro.gravit.launcher.events.request.BatchProfileByUsernameRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -22,7 +21,7 @@ static class Entry {
@LauncherNetworkAPI @LauncherNetworkAPI
private final Entry[] list; private final Entry[] list;
@LauncherAPI
public BatchProfileByUsernameRequest(String... usernames) throws IOException { public BatchProfileByUsernameRequest(String... usernames) throws IOException {
this.list = new Entry[usernames.length]; this.list = new Entry[usernames.length];
for (int i = 0; i < usernames.length; ++i) { for (int i = 0; i < usernames.length; ++i) {

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request.uuid; package pro.gravit.launcher.request.uuid;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.ProfileByUUIDRequestEvent; import pro.gravit.launcher.events.request.ProfileByUUIDRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -13,7 +12,7 @@ public final class ProfileByUUIDRequest extends Request<ProfileByUUIDRequestEven
@LauncherNetworkAPI @LauncherNetworkAPI
private final UUID uuid; private final UUID uuid;
@LauncherAPI
public ProfileByUUIDRequest(UUID uuid) { public ProfileByUUIDRequest(UUID uuid) {
this.uuid = Objects.requireNonNull(uuid, "uuid"); this.uuid = Objects.requireNonNull(uuid, "uuid");
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.request.uuid; package pro.gravit.launcher.request.uuid;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent; import pro.gravit.launcher.events.request.ProfileByUsernameRequestEvent;
import pro.gravit.launcher.request.Request; import pro.gravit.launcher.request.Request;
@ -11,7 +10,7 @@ public final class ProfileByUsernameRequest extends Request<ProfileByUsernameReq
@LauncherNetworkAPI @LauncherNetworkAPI
private final String username; private final String username;
@LauncherAPI
public ProfileByUsernameRequest(String username) { public ProfileByUsernameRequest(String username) {
this.username = VerifyHelper.verifyUsername(username); this.username = VerifyHelper.verifyUsername(username);
} }

View file

@ -1,21 +1,19 @@
package com.mojang.authlib.yggdrasil; package com.mojang.authlib.yggdrasil;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.profiles.PlayerProfile; import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launcher.request.auth.CheckServerRequest; import pro.gravit.launcher.request.auth.CheckServerRequest;
import pro.gravit.launcher.request.auth.JoinServerRequest; import pro.gravit.launcher.request.auth.JoinServerRequest;
import pro.gravit.launcher.request.uuid.BatchProfileByUsernameRequest; import pro.gravit.launcher.request.uuid.BatchProfileByUsernameRequest;
import pro.gravit.launcher.request.uuid.ProfileByUUIDRequest; import pro.gravit.launcher.request.uuid.ProfileByUUIDRequest;
import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest; import pro.gravit.launcher.request.uuid.ProfileByUsernameRequest;
import pro.gravit.launcher.serialize.SerializeLimits;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import java.util.UUID; import java.util.UUID;
// Used to bypass Launcher's class name obfuscation and access API // Used to bypass Launcher's class name obfuscation and access API
@LauncherAPI
public class CompatBridge { public class CompatBridge {
public static final int PROFILES_MAX_BATCH_SIZE = SerializeLimits.MAX_BATCH_SIZE; public static final int PROFILES_MAX_BATCH_SIZE = 128;
public static CompatProfile checkServer(String username, String serverID) throws Exception { public static CompatProfile checkServer(String username, String serverID) throws Exception {
LogHelper.debug("CompatBridge.checkServer, Username: '%s', Server ID: %s", username, serverID); LogHelper.debug("CompatBridge.checkServer, Username: '%s', Server ID: %s", username, serverID);

View file

@ -1,13 +1,12 @@
package com.mojang.authlib.yggdrasil; package com.mojang.authlib.yggdrasil;
import pro.gravit.launcher.Launcher; import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.profiles.PlayerProfile; import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.utils.helper.SecurityHelper; import pro.gravit.utils.helper.SecurityHelper;
import java.util.UUID; import java.util.UUID;
@LauncherAPI
public class CompatProfile { public class CompatProfile {
public static final String SKIN_URL_PROPERTY = Launcher.SKIN_URL_PROPERTY; public static final String SKIN_URL_PROPERTY = Launcher.SKIN_URL_PROPERTY;
public static final String SKIN_DIGEST_PROPERTY = Launcher.SKIN_DIGEST_PROPERTY; public static final String SKIN_DIGEST_PROPERTY = Launcher.SKIN_DIGEST_PROPERTY;

View file

@ -1,6 +1,5 @@
package com.mojang.authlib.yggdrasil; package com.mojang.authlib.yggdrasil;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.request.auth.CheckServerRequest; import pro.gravit.launcher.request.auth.CheckServerRequest;
import pro.gravit.launcher.request.auth.JoinServerRequest; import pro.gravit.launcher.request.auth.JoinServerRequest;
import pro.gravit.utils.helper.CommonHelper; import pro.gravit.utils.helper.CommonHelper;
@ -8,7 +7,7 @@
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
// Used by 1.6.4 and below versions // Used by 1.6.4 and below versions
@LauncherAPI
public class LegacyBridge { public class LegacyBridge {
public static boolean checkServer(String username, String serverID) throws Exception { public static boolean checkServer(String username, String serverID) throws Exception {
LogHelper.debug("LegacyBridge.checkServer, Username: '%s', Server ID: %s", username, serverID); LogHelper.debug("LegacyBridge.checkServer, Username: '%s', Server ID: %s", username, serverID);

View file

@ -6,7 +6,6 @@
import com.mojang.authlib.ProfileLookupCallback; import com.mojang.authlib.ProfileLookupCallback;
import pro.gravit.launcher.profiles.PlayerProfile; import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launcher.request.uuid.BatchProfileByUsernameRequest; import pro.gravit.launcher.request.uuid.BatchProfileByUsernameRequest;
import pro.gravit.launcher.serialize.SerializeLimits;
import pro.gravit.utils.helper.LogHelper; import pro.gravit.utils.helper.LogHelper;
import pro.gravit.utils.helper.VerifyHelper; import pro.gravit.utils.helper.VerifyHelper;
@ -37,8 +36,8 @@ public YggdrasilGameProfileRepository() {
public void findProfilesByNames(String[] usernames, Agent agent, ProfileLookupCallback callback) { public void findProfilesByNames(String[] usernames, Agent agent, ProfileLookupCallback callback) {
int offset = 0; int offset = 0;
while (offset < usernames.length) { while (offset < usernames.length) {
String[] sliceUsernames = Arrays.copyOfRange(usernames, offset, Math.min(offset + SerializeLimits.MAX_BATCH_SIZE, usernames.length)); String[] sliceUsernames = Arrays.copyOfRange(usernames, offset, Math.min(offset + 128, usernames.length));
offset += SerializeLimits.MAX_BATCH_SIZE; offset += 128;
// Batch Username-To-UUID request // Batch Username-To-UUID request
PlayerProfile[] sliceProfiles; PlayerProfile[] sliceProfiles;

View file

@ -1,14 +0,0 @@
package pro.gravit.launcher;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation implies that method/field/class should not be renamed or obfuscated
*/
@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface LauncherAPI {
}

View file

@ -1,7 +1,5 @@
package pro.gravit.launcher.hasher; package pro.gravit.launcher.hasher;
import pro.gravit.launcher.LauncherAPI;
import java.util.Collection; import java.util.Collection;
public final class FileNameMatcher { public final class FileNameMatcher {
@ -36,7 +34,7 @@ private static boolean anyMatch(String[] entries, Collection<String> path) {
private final String[] exclusions; private final String[] exclusions;
@LauncherAPI
public FileNameMatcher(String[] update, String[] verify, String[] exclusions) { public FileNameMatcher(String[] update, String[] verify, String[] exclusions) {
this.update = update; this.update = update;
this.verify = verify; this.verify = verify;

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.hasher; package pro.gravit.launcher.hasher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
@ -19,9 +18,9 @@
public final class HashedDir extends HashedEntry { public final class HashedDir extends HashedEntry {
public static final class Diff { public static final class Diff {
@LauncherAPI
public final HashedDir mismatch; public final HashedDir mismatch;
@LauncherAPI
public final HashedDir extra; public final HashedDir extra;
private Diff(HashedDir mismatch, HashedDir extra) { private Diff(HashedDir mismatch, HashedDir extra) {
@ -29,7 +28,7 @@ private Diff(HashedDir mismatch, HashedDir extra) {
this.extra = extra; this.extra = extra;
} }
@LauncherAPI
public boolean isSame() { public boolean isSame() {
return mismatch.isEmpty() && extra.isEmpty(); return mismatch.isEmpty() && extra.isEmpty();
} }
@ -105,11 +104,11 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
@LauncherNetworkAPI @LauncherNetworkAPI
private final Map<String, HashedEntry> map = new HashMap<>(32); private final Map<String, HashedEntry> map = new HashMap<>(32);
@LauncherAPI
public HashedDir() { public HashedDir() {
} }
@LauncherAPI
public HashedDir(HInput input) throws IOException { public HashedDir(HInput input) throws IOException {
int entriesCount = input.readLength(0); int entriesCount = input.readLength(0);
for (int i = 0; i < entriesCount; i++) { for (int i = 0; i < entriesCount; i++) {
@ -134,19 +133,19 @@ public HashedDir(HInput input) throws IOException {
} }
} }
@LauncherAPI
public HashedDir(Path dir, FileNameMatcher matcher, boolean allowSymlinks, boolean digest) throws IOException { public HashedDir(Path dir, FileNameMatcher matcher, boolean allowSymlinks, boolean digest) throws IOException {
IOHelper.walk(dir, new HashFileVisitor(dir, matcher, allowSymlinks, digest), true); IOHelper.walk(dir, new HashFileVisitor(dir, matcher, allowSymlinks, digest), true);
} }
@LauncherAPI
public Diff diff(HashedDir other, FileNameMatcher matcher) { public Diff diff(HashedDir other, FileNameMatcher matcher) {
HashedDir mismatch = sideDiff(other, matcher, new LinkedList<>(), true); HashedDir mismatch = sideDiff(other, matcher, new LinkedList<>(), true);
HashedDir extra = other.sideDiff(this, matcher, new LinkedList<>(), false); HashedDir extra = other.sideDiff(this, matcher, new LinkedList<>(), false);
return new Diff(mismatch, extra); return new Diff(mismatch, extra);
} }
@LauncherAPI
public Diff compare(HashedDir other, FileNameMatcher matcher) { public Diff compare(HashedDir other, FileNameMatcher matcher) {
HashedDir mismatch = sideDiff(other, matcher, new LinkedList<>(), true); HashedDir mismatch = sideDiff(other, matcher, new LinkedList<>(), true);
HashedDir extra = other.sideDiff(this, matcher, new LinkedList<>(), false); HashedDir extra = other.sideDiff(this, matcher, new LinkedList<>(), false);
@ -190,7 +189,7 @@ public void removeR(String name) {
} }
} }
@LauncherAPI
public HashedEntry getEntry(String name) { public HashedEntry getEntry(String name) {
return map.get(name); return map.get(name);
} }
@ -200,17 +199,17 @@ public Type getType() {
return Type.DIR; return Type.DIR;
} }
@LauncherAPI
public boolean isEmpty() { public boolean isEmpty() {
return map.isEmpty(); return map.isEmpty();
} }
@LauncherAPI
public Map<String, HashedEntry> map() { public Map<String, HashedEntry> map() {
return Collections.unmodifiableMap(map); return Collections.unmodifiableMap(map);
} }
@LauncherAPI
public HashedEntry resolve(Iterable<String> path) { public HashedEntry resolve(Iterable<String> path) {
HashedEntry current = this; HashedEntry current = this;
for (String pathEntry : path) { for (String pathEntry : path) {

View file

@ -1,6 +1,6 @@
package pro.gravit.launcher.hasher; package pro.gravit.launcher.hasher;
import pro.gravit.launcher.LauncherAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.stream.EnumSerializer; import pro.gravit.launcher.serialize.stream.EnumSerializer;
import pro.gravit.launcher.serialize.stream.StreamObject; import pro.gravit.launcher.serialize.stream.StreamObject;
@ -8,7 +8,7 @@
import java.io.IOException; import java.io.IOException;
public abstract class HashedEntry extends StreamObject { public abstract class HashedEntry extends StreamObject {
@LauncherAPI
public enum Type implements EnumSerializer.Itf { public enum Type implements EnumSerializer.Itf {
DIR(1), FILE(2); DIR(1), FILE(2);
private static final EnumSerializer<Type> SERIALIZER = new EnumSerializer<>(Type.class); private static final EnumSerializer<Type> SERIALIZER = new EnumSerializer<>(Type.class);
@ -29,12 +29,12 @@ public int getNumber() {
} }
} }
@LauncherAPI @LauncherNetworkAPI
public boolean flag; // For external usage public boolean flag; // For external usage
@LauncherAPI
public abstract Type getType(); public abstract Type getType();
@LauncherAPI
public abstract long size(); public abstract long size();
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.hasher; package pro.gravit.launcher.hasher;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
@ -17,23 +16,23 @@ public final class HashedFile extends HashedEntry {
public static final DigestAlgorithm DIGEST_ALGO = DigestAlgorithm.MD5; public static final DigestAlgorithm DIGEST_ALGO = DigestAlgorithm.MD5;
// Instance // Instance
@LauncherAPI @LauncherNetworkAPI
public final long size; public final long size;
@LauncherNetworkAPI @LauncherNetworkAPI
private final byte[] digest; private final byte[] digest;
@LauncherAPI
public HashedFile(HInput input) throws IOException { public HashedFile(HInput input) throws IOException {
this(input.readVarLong(), input.readBoolean() ? input.readByteArray(-DIGEST_ALGO.bytes) : null); this(input.readVarLong(), input.readBoolean() ? input.readByteArray(-DIGEST_ALGO.bytes) : null);
} }
@LauncherAPI
public HashedFile(long size, byte[] digest) { public HashedFile(long size, byte[] digest) {
this.size = VerifyHelper.verifyLong(size, VerifyHelper.L_NOT_NEGATIVE, "Illegal size: " + size); this.size = VerifyHelper.verifyLong(size, VerifyHelper.L_NOT_NEGATIVE, "Illegal size: " + size);
this.digest = digest == null ? null : DIGEST_ALGO.verify(digest).clone(); this.digest = digest == null ? null : DIGEST_ALGO.verify(digest).clone();
} }
@LauncherAPI
public HashedFile(Path file, long size, boolean digest) throws IOException { public HashedFile(Path file, long size, boolean digest) throws IOException {
this(size, digest ? SecurityHelper.digest(DIGEST_ALGO, file) : null); this(size, digest ? SecurityHelper.digest(DIGEST_ALGO, file) : null);
} }
@ -43,12 +42,12 @@ public Type getType() {
return Type.FILE; return Type.FILE;
} }
@LauncherAPI
public boolean isSame(HashedFile o) { public boolean isSame(HashedFile o) {
return size == o.size && (digest == null || o.digest == null || Arrays.equals(digest, o.digest)); return size == o.size && (digest == null || o.digest == null || Arrays.equals(digest, o.digest));
} }
@LauncherAPI
public boolean isSame(Path file, boolean digest) throws IOException { public boolean isSame(Path file, boolean digest) throws IOException {
if (size != IOHelper.readAttributes(file).size()) if (size != IOHelper.readAttributes(file).size())
return false; return false;
@ -60,7 +59,7 @@ public boolean isSame(Path file, boolean digest) throws IOException {
return Arrays.equals(this.digest, actualDigest); return Arrays.equals(this.digest, actualDigest);
} }
@LauncherAPI
public boolean isSameDigest(byte[] digest) { public boolean isSameDigest(byte[] digest) {
return this.digest == null || digest == null || Arrays.equals(this.digest, digest); return this.digest == null || digest == null || Arrays.equals(this.digest, digest);
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.serialize; package pro.gravit.launcher.serialize;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -12,15 +11,15 @@
import java.util.UUID; import java.util.UUID;
public final class HInput implements AutoCloseable { public final class HInput implements AutoCloseable {
@LauncherAPI
public final InputStream stream; public final InputStream stream;
@LauncherAPI
public HInput(byte[] bytes) { public HInput(byte[] bytes) {
stream = new ByteArrayInputStream(bytes); stream = new ByteArrayInputStream(bytes);
} }
@LauncherAPI
public HInput(InputStream stream) { public HInput(InputStream stream) {
this.stream = Objects.requireNonNull(stream, "stream"); this.stream = Objects.requireNonNull(stream, "stream");
} }
@ -30,17 +29,17 @@ public void close() throws IOException {
stream.close(); stream.close();
} }
@LauncherAPI
public String readASCII(int maxBytes) throws IOException { public String readASCII(int maxBytes) throws IOException {
return IOHelper.decodeASCII(readByteArray(maxBytes)); return IOHelper.decodeASCII(readByteArray(maxBytes));
} }
@LauncherAPI
public BigInteger readBigInteger(int maxBytes) throws IOException { public BigInteger readBigInteger(int maxBytes) throws IOException {
return new BigInteger(readByteArray(maxBytes)); return new BigInteger(readByteArray(maxBytes));
} }
@LauncherAPI
public boolean readBoolean() throws IOException { public boolean readBoolean() throws IOException {
int b = readUnsignedByte(); int b = readUnsignedByte();
switch (b) { switch (b) {
@ -53,41 +52,41 @@ public boolean readBoolean() throws IOException {
} }
} }
@LauncherAPI
public byte[] readByteArray(int max) throws IOException { public byte[] readByteArray(int max) throws IOException {
byte[] bytes = new byte[readLength(max)]; byte[] bytes = new byte[readLength(max)];
IOHelper.read(stream, bytes); IOHelper.read(stream, bytes);
return bytes; return bytes;
} }
@LauncherAPI
public int readInt() throws IOException { public int readInt() throws IOException {
return (readUnsignedByte() << 24) + (readUnsignedByte() << 16) + (readUnsignedByte() << 8) + readUnsignedByte(); return (readUnsignedByte() << 24) + (readUnsignedByte() << 16) + (readUnsignedByte() << 8) + readUnsignedByte();
} }
@LauncherAPI
public int readLength(int max) throws IOException { public int readLength(int max) throws IOException {
if (max < 0) if (max < 0)
return -max; return -max;
return IOHelper.verifyLength(readVarInt(), max); return IOHelper.verifyLength(readVarInt(), max);
} }
@LauncherAPI
public long readLong() throws IOException { public long readLong() throws IOException {
return (long) readInt() << 32 | readInt() & 0xFFFFFFFFL; return (long) readInt() << 32 | readInt() & 0xFFFFFFFFL;
} }
@LauncherAPI
public short readShort() throws IOException { public short readShort() throws IOException {
return (short) ((readUnsignedByte() << 8) + readUnsignedByte()); return (short) ((readUnsignedByte() << 8) + readUnsignedByte());
} }
@LauncherAPI
public String readString(int maxBytes) throws IOException { public String readString(int maxBytes) throws IOException {
return IOHelper.decode(readByteArray(maxBytes)); return IOHelper.decode(readByteArray(maxBytes));
} }
@LauncherAPI
public int readUnsignedByte() throws IOException { public int readUnsignedByte() throws IOException {
int b = stream.read(); int b = stream.read();
if (b < 0) if (b < 0)
@ -95,17 +94,17 @@ public int readUnsignedByte() throws IOException {
return b; return b;
} }
@LauncherAPI
public int readUnsignedShort() throws IOException { public int readUnsignedShort() throws IOException {
return Short.toUnsignedInt(readShort()); return Short.toUnsignedInt(readShort());
} }
@LauncherAPI
public UUID readUUID() throws IOException { public UUID readUUID() throws IOException {
return new UUID(readLong(), readLong()); return new UUID(readLong(), readLong());
} }
@LauncherAPI
public int readVarInt() throws IOException { public int readVarInt() throws IOException {
int shift = 0; int shift = 0;
int result = 0; int result = 0;
@ -119,7 +118,7 @@ public int readVarInt() throws IOException {
throw new IOException("VarInt too big"); throw new IOException("VarInt too big");
} }
@LauncherAPI
public long readVarLong() throws IOException { public long readVarLong() throws IOException {
int shift = 0; int shift = 0;
long result = 0; long result = 0;

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.serialize; package pro.gravit.launcher.serialize;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
import java.io.Flushable; import java.io.Flushable;
@ -11,10 +10,10 @@
import java.util.UUID; import java.util.UUID;
public final class HOutput implements AutoCloseable, Flushable { public final class HOutput implements AutoCloseable, Flushable {
@LauncherAPI
public final OutputStream stream; public final OutputStream stream;
@LauncherAPI
public HOutput(OutputStream stream) { public HOutput(OutputStream stream) {
this.stream = Objects.requireNonNull(stream, "stream"); this.stream = Objects.requireNonNull(stream, "stream");
} }
@ -29,28 +28,28 @@ public void flush() throws IOException {
stream.flush(); stream.flush();
} }
@LauncherAPI
public void writeASCII(String s, int maxBytes) throws IOException { public void writeASCII(String s, int maxBytes) throws IOException {
writeByteArray(IOHelper.encodeASCII(s), maxBytes); writeByteArray(IOHelper.encodeASCII(s), maxBytes);
} }
@LauncherAPI
public void writeBigInteger(BigInteger bi, int max) throws IOException { public void writeBigInteger(BigInteger bi, int max) throws IOException {
writeByteArray(bi.toByteArray(), max); writeByteArray(bi.toByteArray(), max);
} }
@LauncherAPI
public void writeBoolean(boolean b) throws IOException { public void writeBoolean(boolean b) throws IOException {
writeUnsignedByte(b ? 0b1 : 0b0); writeUnsignedByte(b ? 0b1 : 0b0);
} }
@LauncherAPI
public void writeByteArray(byte[] bytes, int max) throws IOException { public void writeByteArray(byte[] bytes, int max) throws IOException {
writeLength(bytes.length, max); writeLength(bytes.length, max);
stream.write(bytes); stream.write(bytes);
} }
@LauncherAPI
public void writeInt(int i) throws IOException { public void writeInt(int i) throws IOException {
writeUnsignedByte(i >>> 24 & 0xFF); writeUnsignedByte(i >>> 24 & 0xFF);
writeUnsignedByte(i >>> 16 & 0xFF); writeUnsignedByte(i >>> 16 & 0xFF);
@ -58,42 +57,42 @@ public void writeInt(int i) throws IOException {
writeUnsignedByte(i & 0xFF); writeUnsignedByte(i & 0xFF);
} }
@LauncherAPI
public void writeLength(int length, int max) throws IOException { public void writeLength(int length, int max) throws IOException {
IOHelper.verifyLength(length, max); IOHelper.verifyLength(length, max);
if (max >= 0) if (max >= 0)
writeVarInt(length); writeVarInt(length);
} }
@LauncherAPI
public void writeLong(long l) throws IOException { public void writeLong(long l) throws IOException {
writeInt((int) (l >> 32)); writeInt((int) (l >> 32));
writeInt((int) l); writeInt((int) l);
} }
@LauncherAPI
public void writeShort(short s) throws IOException { public void writeShort(short s) throws IOException {
writeUnsignedByte(s >>> 8 & 0xFF); writeUnsignedByte(s >>> 8 & 0xFF);
writeUnsignedByte(s & 0xFF); writeUnsignedByte(s & 0xFF);
} }
@LauncherAPI
public void writeString(String s, int maxBytes) throws IOException { public void writeString(String s, int maxBytes) throws IOException {
writeByteArray(IOHelper.encode(s), maxBytes); writeByteArray(IOHelper.encode(s), maxBytes);
} }
@LauncherAPI
public void writeUnsignedByte(int b) throws IOException { public void writeUnsignedByte(int b) throws IOException {
stream.write(b); stream.write(b);
} }
@LauncherAPI
public void writeUUID(UUID uuid) throws IOException { public void writeUUID(UUID uuid) throws IOException {
writeLong(uuid.getMostSignificantBits()); writeLong(uuid.getMostSignificantBits());
writeLong(uuid.getLeastSignificantBits()); writeLong(uuid.getLeastSignificantBits());
} }
@LauncherAPI
public void writeVarInt(int i) throws IOException { public void writeVarInt(int i) throws IOException {
while ((i & ~0x7FL) != 0) { while ((i & ~0x7FL) != 0) {
writeUnsignedByte(i & 0x7F | 0x80); writeUnsignedByte(i & 0x7F | 0x80);
@ -102,7 +101,7 @@ public void writeVarInt(int i) throws IOException {
writeUnsignedByte(i); writeUnsignedByte(i);
} }
@LauncherAPI
public void writeVarLong(long l) throws IOException { public void writeVarLong(long l) throws IOException {
while ((l & ~0x7FL) != 0) { while ((l & ~0x7FL) != 0) {
writeUnsignedByte((int) l & 0x7F | 0x80); writeUnsignedByte((int) l & 0x7F | 0x80);

View file

@ -1,12 +1,10 @@
package pro.gravit.launcher.serialize; package pro.gravit.launcher.serialize;
import pro.gravit.launcher.LauncherAPI;
public class SerializeLimits { public class SerializeLimits {
@LauncherAPI
public static final int MAX_BATCH_SIZE = 128; public static final int MAX_BATCH_SIZE = 128;
@LauncherAPI
public static final byte EXPECTED_BYTE = 0b01010101; public static final byte EXPECTED_BYTE = 0b01010101;
@LauncherAPI
public static final int MAX_DIGEST = 512; public static final int MAX_DIGEST = 512;
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.serialize.signed; package pro.gravit.launcher.serialize.signed;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.stream.StreamObject; import pro.gravit.launcher.serialize.stream.StreamObject;
@ -14,7 +13,7 @@ public class DigestBytesHolder extends StreamObject {
protected final byte[] bytes; protected final byte[] bytes;
private final byte[] digest; private final byte[] digest;
@LauncherAPI
public DigestBytesHolder(byte[] bytes, byte[] digest, SecurityHelper.DigestAlgorithm algorithm) throws SignatureException { public DigestBytesHolder(byte[] bytes, byte[] digest, SecurityHelper.DigestAlgorithm algorithm) throws SignatureException {
if (Arrays.equals(SecurityHelper.digest(algorithm, bytes), digest)) if (Arrays.equals(SecurityHelper.digest(algorithm, bytes), digest))
throw new SignatureException("Invalid digest"); throw new SignatureException("Invalid digest");
@ -22,23 +21,23 @@ public DigestBytesHolder(byte[] bytes, byte[] digest, SecurityHelper.DigestAlgor
this.digest = digest.clone(); this.digest = digest.clone();
} }
@LauncherAPI
public DigestBytesHolder(byte[] bytes, SecurityHelper.DigestAlgorithm algorithm) { public DigestBytesHolder(byte[] bytes, SecurityHelper.DigestAlgorithm algorithm) {
this.bytes = bytes.clone(); this.bytes = bytes.clone();
this.digest = SecurityHelper.digest(algorithm, bytes); this.digest = SecurityHelper.digest(algorithm, bytes);
} }
@LauncherAPI
public DigestBytesHolder(HInput input, SecurityHelper.DigestAlgorithm algorithm) throws IOException, SignatureException { public DigestBytesHolder(HInput input, SecurityHelper.DigestAlgorithm algorithm) throws IOException, SignatureException {
this(input.readByteArray(0), input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH), algorithm); this(input.readByteArray(0), input.readByteArray(-SecurityHelper.RSA_KEY_LENGTH), algorithm);
} }
@LauncherAPI
public final byte[] getBytes() { public final byte[] getBytes() {
return bytes.clone(); return bytes.clone();
} }
@LauncherAPI
public final byte[] getDigest() { public final byte[] getDigest() {
return digest.clone(); return digest.clone();
} }

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.serialize.stream; package pro.gravit.launcher.serialize.stream;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.launcher.serialize.stream.EnumSerializer.Itf; import pro.gravit.launcher.serialize.stream.EnumSerializer.Itf;
@ -13,24 +12,24 @@
public final class EnumSerializer<E extends Enum<?> & Itf> { public final class EnumSerializer<E extends Enum<?> & Itf> {
@FunctionalInterface @FunctionalInterface
public interface Itf { public interface Itf {
@LauncherAPI
int getNumber(); int getNumber();
} }
@LauncherAPI
public static void write(HOutput output, Itf itf) throws IOException { public static void write(HOutput output, Itf itf) throws IOException {
output.writeVarInt(itf.getNumber()); output.writeVarInt(itf.getNumber());
} }
private final Map<Integer, E> map = new HashMap<>(16); private final Map<Integer, E> map = new HashMap<>(16);
@LauncherAPI
public EnumSerializer(Class<E> clazz) { public EnumSerializer(Class<E> clazz) {
for (E e : clazz.getEnumConstants()) for (E e : clazz.getEnumConstants())
VerifyHelper.putIfAbsent(map, e.getNumber(), e, "Duplicate number for enum constant " + e.name()); VerifyHelper.putIfAbsent(map, e.getNumber(), e, "Duplicate number for enum constant " + e.name());
} }
@LauncherAPI
public E read(HInput input) throws IOException { public E read(HInput input) throws IOException {
int n = input.readVarInt(); int n = input.readVarInt();
return VerifyHelper.getMapValue(map, n, "Unknown enum number: " + n); return VerifyHelper.getMapValue(map, n, "Unknown enum number: " + n);

View file

@ -1,6 +1,5 @@
package pro.gravit.launcher.serialize.stream; package pro.gravit.launcher.serialize.stream;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.serialize.HInput; import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput; import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.IOHelper;
@ -13,11 +12,11 @@ public abstract class StreamObject {
@FunctionalInterface @FunctionalInterface
public interface Adapter<O extends StreamObject> { public interface Adapter<O extends StreamObject> {
@LauncherAPI
O convert(HInput input); O convert(HInput input);
} }
@LauncherAPI
public final byte[] write() throws IOException { public final byte[] write() throws IOException {
try (ByteArrayOutputStream array = IOHelper.newByteArrayOutput()) { try (ByteArrayOutputStream array = IOHelper.newByteArrayOutput()) {
try (HOutput output = new HOutput(array)) { try (HOutput output = new HOutput(array)) {
@ -27,6 +26,6 @@ public final byte[] write() throws IOException {
} }
} }
@LauncherAPI
public abstract void write(HOutput output) throws IOException; public abstract void write(HOutput output) throws IOException;
} }

View file

@ -1,19 +1,9 @@
package pro.gravit.utils; package pro.gravit.utils;
import pro.gravit.launcher.LauncherAPI;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
public class PublicURLClassLoader extends URLClassLoader { public class PublicURLClassLoader extends URLClassLoader {
@LauncherAPI
public static ClassLoader systemclassloader = ClassLoader.getSystemClassLoader();
public String nativePath;
@LauncherAPI
public static ClassLoader getSystemClassLoader() {
return systemclassloader;
}
/** /**
* Constructs a new URLClassLoader for the specified URLs using the * Constructs a new URLClassLoader for the specified URLs using the
@ -64,11 +54,6 @@ public PublicURLClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent); super(urls, parent);
} }
@Override
public String findLibrary(String name) {
return nativePath.concat(name);
}
@Override @Override
public void addURL(URL url) { public void addURL(URL url) {
super.addURL(url); super.addURL(url);

View file

@ -1,19 +1,17 @@
package pro.gravit.utils; package pro.gravit.utils;
import pro.gravit.launcher.LauncherAPI;
import java.util.*; import java.util.*;
public final class Version { public final class Version {
@LauncherAPI
public final int major; public final int major;
@LauncherAPI
public final int minor; public final int minor;
@LauncherAPI
public final int patch; public final int patch;
@LauncherAPI
public final int build; public final int build;
@LauncherAPI
public final Type release; public final Type release;
public static final int MAJOR = 5; public static final int MAJOR = 5;
public static final int MINOR = 1; public static final int MINOR = 1;
@ -21,7 +19,7 @@ public final class Version {
public static final int BUILD = 1; public static final int BUILD = 1;
public static final Version.Type RELEASE = Type.DEV; public static final Version.Type RELEASE = Type.DEV;
@LauncherAPI
public Version(int major, int minor, int patch) { public Version(int major, int minor, int patch) {
this.major = major; this.major = major;
this.minor = minor; this.minor = minor;
@ -30,7 +28,7 @@ public Version(int major, int minor, int patch) {
release = Type.UNKNOWN; release = Type.UNKNOWN;
} }
@LauncherAPI
public Version(int major, int minor, int patch, int build) { public Version(int major, int minor, int patch, int build) {
this.major = major; this.major = major;
this.minor = minor; this.minor = minor;
@ -39,7 +37,7 @@ public Version(int major, int minor, int patch, int build) {
release = Type.UNKNOWN; release = Type.UNKNOWN;
} }
@LauncherAPI
public Version(int major, int minor, int patch, int build, Type release) { public Version(int major, int minor, int patch, int build, Type release) {
this.major = major; this.major = major;
this.minor = minor; this.minor = minor;
@ -53,7 +51,7 @@ public static Version getVersion() {
} }
@Override @Override
@LauncherAPI
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
@ -64,30 +62,30 @@ public boolean equals(Object o) {
build == that.build; build == that.build;
} }
@LauncherAPI
public String getVersionString() { public String getVersionString() {
return String.format("%d.%d.%d", major, minor, patch); return String.format("%d.%d.%d", major, minor, patch);
} }
@Override @Override
@LauncherAPI
public int hashCode() { public int hashCode() {
return Objects.hash(major, minor, patch, build); return Objects.hash(major, minor, patch, build);
} }
@LauncherAPI
public String getReleaseStatus() { public String getReleaseStatus() {
if (release.equals(Type.UNKNOWN)) return ""; if (release.equals(Type.UNKNOWN)) return "";
return release.name().toLowerCase(Locale.ENGLISH); return release.name().toLowerCase(Locale.ENGLISH);
} }
@Override @Override
@LauncherAPI
public String toString() { public String toString() {
return String.format("%d.%d.%d-%d %s", major, minor, patch, build, getReleaseStatus()); return String.format("%d.%d.%d-%d %s", major, minor, patch, build, getReleaseStatus());
} }
@LauncherAPI
public enum Type { public enum Type {
LTS, LTS,
STABLE, STABLE,

View file

@ -1,7 +1,6 @@
package pro.gravit.utils.helper; package pro.gravit.utils.helper;
import com.google.gson.*; import com.google.gson.*;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.utils.command.CommandException; import pro.gravit.utils.command.CommandException;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
@ -16,9 +15,9 @@
import java.util.regex.Pattern; import java.util.regex.Pattern;
public final class CommonHelper { public final class CommonHelper {
@LauncherAPI
public static final ScriptEngineManager scriptManager = new ScriptEngineManager(); public static final ScriptEngineManager scriptManager = new ScriptEngineManager();
@LauncherAPI
public static final ScriptEngineFactory nashornFactory = getEngineFactories(scriptManager); public static final ScriptEngineFactory nashornFactory = getEngineFactories(scriptManager);
private static ScriptEngineFactory getEngineFactories(ScriptEngineManager manager) { private static ScriptEngineFactory getEngineFactories(ScriptEngineManager manager) {
@ -28,19 +27,19 @@ private static ScriptEngineFactory getEngineFactories(ScriptEngineManager manage
return null; return null;
} }
@LauncherAPI
public static String low(String s) { public static String low(String s) {
return s.toLowerCase(Locale.US); return s.toLowerCase(Locale.US);
} }
@LauncherAPI
public static boolean multiMatches(Pattern[] pattern, String from) { public static boolean multiMatches(Pattern[] pattern, String from) {
for (Pattern p : pattern) for (Pattern p : pattern)
if (p.matcher(from).matches()) return true; if (p.matcher(from).matches()) return true;
return false; return false;
} }
@LauncherAPI
public static String multiReplace(Pattern[] pattern, String from, String replace) { public static String multiReplace(Pattern[] pattern, String from, String replace) {
Matcher m; Matcher m;
String tmp = null; String tmp = null;
@ -51,12 +50,12 @@ public static String multiReplace(Pattern[] pattern, String from, String replace
return tmp != null ? tmp : from; return tmp != null ? tmp : from;
} }
@LauncherAPI
public static ScriptEngine newScriptEngine() { public static ScriptEngine newScriptEngine() {
return nashornFactory.getScriptEngine(); return nashornFactory.getScriptEngine();
} }
@LauncherAPI
public static Thread newThread(String name, boolean daemon, Runnable runnable) { public static Thread newThread(String name, boolean daemon, Runnable runnable) {
Thread thread = new Thread(runnable); Thread thread = new Thread(runnable);
thread.setDaemon(daemon); thread.setDaemon(daemon);
@ -65,7 +64,7 @@ public static Thread newThread(String name, boolean daemon, Runnable runnable) {
return thread; return thread;
} }
@LauncherAPI
public static String replace(String source, String... params) { public static String replace(String source, String... params) {
for (int i = 0; i < params.length; i += 2) for (int i = 0; i < params.length; i += 2)
source = source.replace('%' + params[i] + '%', params[i + 1]); source = source.replace('%' + params[i] + '%', params[i + 1]);
@ -124,7 +123,7 @@ public static String[] parseCommand(CharSequence line) throws CommandException {
return result.toArray(new String[0]); return result.toArray(new String[0]);
} }
@LauncherAPI
public static GsonBuilder newBuilder() { public static GsonBuilder newBuilder() {
return new GsonBuilder().registerTypeHierarchyAdapter(byte[].class, return new GsonBuilder().registerTypeHierarchyAdapter(byte[].class,
ByteArrayToBase64TypeAdapter.INSTANCE); ByteArrayToBase64TypeAdapter.INSTANCE);

View file

@ -1,7 +1,5 @@
package pro.gravit.utils.helper; package pro.gravit.utils.helper;
import pro.gravit.launcher.LauncherAPI;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.ImageReader; import javax.imageio.ImageReader;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -77,42 +75,42 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce
} }
// Charset // Charset
@LauncherAPI
public static final Charset UNICODE_CHARSET = StandardCharsets.UTF_8; public static final Charset UNICODE_CHARSET = StandardCharsets.UTF_8;
@LauncherAPI
public static final Charset ASCII_CHARSET = StandardCharsets.US_ASCII; public static final Charset ASCII_CHARSET = StandardCharsets.US_ASCII;
// Constants // Constants
@LauncherAPI
public static final int SOCKET_TIMEOUT = VerifyHelper.verifyInt( public static final int SOCKET_TIMEOUT = VerifyHelper.verifyInt(
Integer.parseUnsignedInt(System.getProperty("launcher.socketTimeout", Integer.toString(30000))), Integer.parseUnsignedInt(System.getProperty("launcher.socketTimeout", Integer.toString(30000))),
VerifyHelper.POSITIVE, "launcher.socketTimeout can't be <= 0"); VerifyHelper.POSITIVE, "launcher.socketTimeout can't be <= 0");
@LauncherAPI
public static final int HTTP_TIMEOUT = VerifyHelper.verifyInt( public static final int HTTP_TIMEOUT = VerifyHelper.verifyInt(
Integer.parseUnsignedInt(System.getProperty("launcher.httpTimeout", Integer.toString(5000))), Integer.parseUnsignedInt(System.getProperty("launcher.httpTimeout", Integer.toString(5000))),
VerifyHelper.POSITIVE, "launcher.httpTimeout can't be <= 0"); VerifyHelper.POSITIVE, "launcher.httpTimeout can't be <= 0");
@LauncherAPI
public static final int BUFFER_SIZE = VerifyHelper.verifyInt( public static final int BUFFER_SIZE = VerifyHelper.verifyInt(
Integer.parseUnsignedInt(System.getProperty("launcher.bufferSize", Integer.toString(4096))), Integer.parseUnsignedInt(System.getProperty("launcher.bufferSize", Integer.toString(4096))),
VerifyHelper.POSITIVE, "launcher.bufferSize can't be <= 0"); VerifyHelper.POSITIVE, "launcher.bufferSize can't be <= 0");
// Platform-dependent // Platform-dependent
@LauncherAPI
public static final String CROSS_SEPARATOR = "/"; public static final String CROSS_SEPARATOR = "/";
@LauncherAPI
public static final FileSystem FS = FileSystems.getDefault(); public static final FileSystem FS = FileSystems.getDefault();
@LauncherAPI
public static final String PLATFORM_SEPARATOR = FS.getSeparator(); public static final String PLATFORM_SEPARATOR = FS.getSeparator();
// Увидел исключение на NetBSD beta добавил // Увидел исключение на NetBSD beta добавил
@LauncherAPI
public static final boolean POSIX = FS.supportedFileAttributeViews().contains("posix") || FS.supportedFileAttributeViews().contains("Posix"); public static final boolean POSIX = FS.supportedFileAttributeViews().contains("posix") || FS.supportedFileAttributeViews().contains("Posix");
// Paths // Paths
@LauncherAPI
public static final Path JVM_DIR = Paths.get(System.getProperty("java.home")); public static final Path JVM_DIR = Paths.get(System.getProperty("java.home"));
@LauncherAPI
public static final Path HOME_DIR = Paths.get(System.getProperty("user.home")); public static final Path HOME_DIR = Paths.get(System.getProperty("user.home"));
@LauncherAPI
public static final Path WORKING_DIR = Paths.get(System.getProperty("user.dir")); public static final Path WORKING_DIR = Paths.get(System.getProperty("user.dir"));
// Open options - as arrays // Open options - as arrays
private static final OpenOption[] READ_OPTIONS = {StandardOpenOption.READ}; private static final OpenOption[] READ_OPTIONS = {StandardOpenOption.READ};
@ -131,7 +129,7 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce
private static final Pattern PLATFORM_SEPARATOR_PATTERN = Pattern.compile(PLATFORM_SEPARATOR, Pattern.LITERAL); private static final Pattern PLATFORM_SEPARATOR_PATTERN = Pattern.compile(PLATFORM_SEPARATOR, Pattern.LITERAL);
public static final String USER_AGENT = System.getProperty("launcher.userAgentDefault", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); public static final String USER_AGENT = System.getProperty("launcher.userAgentDefault", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");
@LauncherAPI
public static void close(AutoCloseable closeable) { public static void close(AutoCloseable closeable) {
try { try {
closeable.close(); closeable.close();
@ -140,7 +138,7 @@ public static void close(AutoCloseable closeable) {
} }
} }
@LauncherAPI
public static void close(InputStream in) { public static void close(InputStream in) {
try { try {
in.close(); in.close();
@ -148,7 +146,7 @@ public static void close(InputStream in) {
} }
} }
@LauncherAPI
public static void close(OutputStream out) { public static void close(OutputStream out) {
try { try {
out.flush(); out.flush();
@ -157,7 +155,7 @@ public static void close(OutputStream out) {
} }
} }
@LauncherAPI
public static URL convertToURL(String url) { public static URL convertToURL(String url) {
try { try {
return new URL(url); return new URL(url);
@ -166,70 +164,70 @@ public static URL convertToURL(String url) {
} }
} }
@LauncherAPI
public static void copy(Path source, Path target) throws IOException { public static void copy(Path source, Path target) throws IOException {
createParentDirs(target); createParentDirs(target);
Files.copy(source, target, COPY_OPTIONS); Files.copy(source, target, COPY_OPTIONS);
} }
@LauncherAPI
public static void createParentDirs(Path path) throws IOException { public static void createParentDirs(Path path) throws IOException {
Path parent = path.getParent(); Path parent = path.getParent();
if (parent != null && !isDir(parent)) if (parent != null && !isDir(parent))
Files.createDirectories(parent); Files.createDirectories(parent);
} }
@LauncherAPI
public static String decode(byte[] bytes) { public static String decode(byte[] bytes) {
return new String(bytes, UNICODE_CHARSET); return new String(bytes, UNICODE_CHARSET);
} }
@LauncherAPI
public static String decodeASCII(byte[] bytes) { public static String decodeASCII(byte[] bytes) {
return new String(bytes, ASCII_CHARSET); return new String(bytes, ASCII_CHARSET);
} }
@LauncherAPI
public static void deleteDir(Path dir, boolean self) throws IOException { public static void deleteDir(Path dir, boolean self) throws IOException {
walk(dir, new DeleteDirVisitor(dir, self), true); walk(dir, new DeleteDirVisitor(dir, self), true);
} }
@LauncherAPI
public static byte[] encode(String s) { public static byte[] encode(String s) {
return s.getBytes(UNICODE_CHARSET); return s.getBytes(UNICODE_CHARSET);
} }
@LauncherAPI
public static byte[] encodeASCII(String s) { public static byte[] encodeASCII(String s) {
return s.getBytes(ASCII_CHARSET); return s.getBytes(ASCII_CHARSET);
} }
@LauncherAPI
public static boolean exists(Path path) { public static boolean exists(Path path) {
return Files.exists(path, LINK_OPTIONS); return Files.exists(path, LINK_OPTIONS);
} }
@LauncherAPI
public static Path getCodeSource(Class<?> clazz) { public static Path getCodeSource(Class<?> clazz) {
return Paths.get(toURI(clazz.getProtectionDomain().getCodeSource().getLocation())); return Paths.get(toURI(clazz.getProtectionDomain().getCodeSource().getLocation()));
} }
@LauncherAPI
public static String getFileName(Path path) { public static String getFileName(Path path) {
return path.getFileName().toString(); return path.getFileName().toString();
} }
@LauncherAPI
public static String getIP(SocketAddress address) { public static String getIP(SocketAddress address) {
return ((InetSocketAddress) address).getAddress().getHostAddress(); return ((InetSocketAddress) address).getAddress().getHostAddress();
} }
@LauncherAPI
public static byte[] getResourceBytes(String name) throws IOException { public static byte[] getResourceBytes(String name) throws IOException {
return read(getResourceURL(name)); return read(getResourceURL(name));
} }
@LauncherAPI
public static URL getResourceURL(String name) throws NoSuchFileException { public static URL getResourceURL(String name) throws NoSuchFileException {
URL url = IOHelper.class.getResource('/' + name); URL url = IOHelper.class.getResource('/' + name);
if (url == null) if (url == null)
@ -237,35 +235,35 @@ public static URL getResourceURL(String name) throws NoSuchFileException {
return url; return url;
} }
@LauncherAPI
public static boolean hasExtension(Path file, String extension) { public static boolean hasExtension(Path file, String extension) {
return getFileName(file).endsWith('.' + extension); return getFileName(file).endsWith('.' + extension);
} }
@LauncherAPI
public static boolean isDir(Path path) { public static boolean isDir(Path path) {
return Files.isDirectory(path, LINK_OPTIONS); return Files.isDirectory(path, LINK_OPTIONS);
} }
@LauncherAPI
public static boolean isEmpty(Path dir) throws IOException { public static boolean isEmpty(Path dir) throws IOException {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
return !stream.iterator().hasNext(); return !stream.iterator().hasNext();
} }
} }
@LauncherAPI
public static boolean isFile(Path path) { public static boolean isFile(Path path) {
return Files.isRegularFile(path, LINK_OPTIONS); return Files.isRegularFile(path, LINK_OPTIONS);
} }
@LauncherAPI
public static boolean isValidFileName(String fileName) { public static boolean isValidFileName(String fileName) {
return !fileName.equals(".") && !fileName.equals("..") && return !fileName.equals(".") && !fileName.equals("..") &&
fileName.chars().noneMatch(ch -> ch == '/' || ch == '\\') && isValidPath(fileName); fileName.chars().noneMatch(ch -> ch == '/' || ch == '\\') && isValidPath(fileName);
} }
@LauncherAPI
public static boolean isValidPath(String path) { public static boolean isValidPath(String path) {
try { try {
toPath(path); toPath(path);
@ -275,34 +273,34 @@ public static boolean isValidPath(String path) {
} }
} }
@LauncherAPI
public static boolean isValidTextureBounds(int width, int height, boolean cloak) { public static boolean isValidTextureBounds(int width, int height, boolean cloak) {
return width % 64 == 0 && (height << 1 == width || !cloak && height == width) && width <= 1024 || return width % 64 == 0 && (height << 1 == width || !cloak && height == width) && width <= 1024 ||
cloak && width % 22 == 0 && height % 17 == 0 && width / 22 == height / 17; cloak && width % 22 == 0 && height % 17 == 0 && width / 22 == height / 17;
} }
@LauncherAPI
public static void move(Path source, Path target) throws IOException { public static void move(Path source, Path target) throws IOException {
createParentDirs(target); createParentDirs(target);
Files.move(source, target, COPY_OPTIONS); Files.move(source, target, COPY_OPTIONS);
} }
@LauncherAPI
public static byte[] newBuffer() { public static byte[] newBuffer() {
return new byte[BUFFER_SIZE]; return new byte[BUFFER_SIZE];
} }
@LauncherAPI
public static ByteArrayOutputStream newByteArrayOutput() { public static ByteArrayOutputStream newByteArrayOutput() {
return new ByteArrayOutputStream(); return new ByteArrayOutputStream();
} }
@LauncherAPI
public static char[] newCharBuffer() { public static char[] newCharBuffer() {
return new char[BUFFER_SIZE]; return new char[BUFFER_SIZE];
} }
@LauncherAPI
public static URLConnection newConnection(URL url) throws IOException { public static URLConnection newConnection(URL url) throws IOException {
URLConnection connection = url.openConnection(); URLConnection connection = url.openConnection();
if (connection instanceof HttpURLConnection) { if (connection instanceof HttpURLConnection) {
@ -316,7 +314,7 @@ public static URLConnection newConnection(URL url) throws IOException {
return connection; return connection;
} }
@LauncherAPI
public static HttpURLConnection newConnectionPost(URL url) throws IOException { public static HttpURLConnection newConnectionPost(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) newConnection(url); HttpURLConnection connection = (HttpURLConnection) newConnection(url);
connection.setDoOutput(true); connection.setDoOutput(true);
@ -324,138 +322,138 @@ public static HttpURLConnection newConnectionPost(URL url) throws IOException {
return connection; return connection;
} }
@LauncherAPI
public static Deflater newDeflater() { public static Deflater newDeflater() {
Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
deflater.setStrategy(Deflater.DEFAULT_STRATEGY); deflater.setStrategy(Deflater.DEFAULT_STRATEGY);
return deflater; return deflater;
} }
@LauncherAPI
public static Inflater newInflater() { public static Inflater newInflater() {
return new Inflater(true); return new Inflater(true);
} }
@LauncherAPI
public static InputStream newInput(Path file) throws IOException { public static InputStream newInput(Path file) throws IOException {
return Files.newInputStream(file, READ_OPTIONS); return Files.newInputStream(file, READ_OPTIONS);
} }
@LauncherAPI
public static InputStream newBufferedInput(Path file) throws IOException { public static InputStream newBufferedInput(Path file) throws IOException {
return new BufferedInputStream(Files.newInputStream(file, READ_OPTIONS)); return new BufferedInputStream(Files.newInputStream(file, READ_OPTIONS));
} }
@LauncherAPI
public static InputStream newInput(URL url) throws IOException { public static InputStream newInput(URL url) throws IOException {
return newConnection(url).getInputStream(); return newConnection(url).getInputStream();
} }
@LauncherAPI
public static BufferedInputStream newBufferedInput(URL url) throws IOException { public static BufferedInputStream newBufferedInput(URL url) throws IOException {
return new BufferedInputStream(newConnection(url).getInputStream()); return new BufferedInputStream(newConnection(url).getInputStream());
} }
@LauncherAPI
public static OutputStream newOutput(Path file) throws IOException { public static OutputStream newOutput(Path file) throws IOException {
return newOutput(file, false); return newOutput(file, false);
} }
@LauncherAPI
public static OutputStream newBufferedOutput(Path file) throws IOException { public static OutputStream newBufferedOutput(Path file) throws IOException {
return newBufferedOutput(file, false); return newBufferedOutput(file, false);
} }
@LauncherAPI
public static OutputStream newOutput(Path file, boolean append) throws IOException { public static OutputStream newOutput(Path file, boolean append) throws IOException {
createParentDirs(file); createParentDirs(file);
return Files.newOutputStream(file, append ? APPEND_OPTIONS : WRITE_OPTIONS); return Files.newOutputStream(file, append ? APPEND_OPTIONS : WRITE_OPTIONS);
} }
@LauncherAPI
public static OutputStream newBufferedOutput(Path file, boolean append) throws IOException { public static OutputStream newBufferedOutput(Path file, boolean append) throws IOException {
createParentDirs(file); createParentDirs(file);
return new BufferedOutputStream(Files.newOutputStream(file, append ? APPEND_OPTIONS : WRITE_OPTIONS)); return new BufferedOutputStream(Files.newOutputStream(file, append ? APPEND_OPTIONS : WRITE_OPTIONS));
} }
@LauncherAPI
public static BufferedReader newReader(InputStream input) { public static BufferedReader newReader(InputStream input) {
return newReader(input, UNICODE_CHARSET); return newReader(input, UNICODE_CHARSET);
} }
@LauncherAPI
public static BufferedReader newReader(InputStream input, Charset charset) { public static BufferedReader newReader(InputStream input, Charset charset) {
return new BufferedReader(new InputStreamReader(input, charset)); return new BufferedReader(new InputStreamReader(input, charset));
} }
@LauncherAPI
public static BufferedReader newReader(Path file) throws IOException { public static BufferedReader newReader(Path file) throws IOException {
return Files.newBufferedReader(file, UNICODE_CHARSET); return Files.newBufferedReader(file, UNICODE_CHARSET);
} }
@LauncherAPI
public static BufferedReader newReader(URL url) throws IOException { public static BufferedReader newReader(URL url) throws IOException {
URLConnection connection = newConnection(url); URLConnection connection = newConnection(url);
String charset = connection.getContentEncoding(); String charset = connection.getContentEncoding();
return newReader(connection.getInputStream(), charset == null ? UNICODE_CHARSET : Charset.forName(charset)); return newReader(connection.getInputStream(), charset == null ? UNICODE_CHARSET : Charset.forName(charset));
} }
@LauncherAPI
public static Socket newSocket() throws SocketException { public static Socket newSocket() throws SocketException {
Socket socket = new Socket(); Socket socket = new Socket();
setSocketFlags(socket); setSocketFlags(socket);
return socket; return socket;
} }
@LauncherAPI
public static BufferedWriter newWriter(FileDescriptor fd) { public static BufferedWriter newWriter(FileDescriptor fd) {
return newWriter(new FileOutputStream(fd)); return newWriter(new FileOutputStream(fd));
} }
@LauncherAPI
public static BufferedWriter newWriter(OutputStream output) { public static BufferedWriter newWriter(OutputStream output) {
return new BufferedWriter(new OutputStreamWriter(output, UNICODE_CHARSET)); return new BufferedWriter(new OutputStreamWriter(output, UNICODE_CHARSET));
} }
@LauncherAPI
public static BufferedWriter newWriter(Path file) throws IOException { public static BufferedWriter newWriter(Path file) throws IOException {
return newWriter(file, false); return newWriter(file, false);
} }
@LauncherAPI
public static BufferedWriter newWriter(Path file, boolean append) throws IOException { public static BufferedWriter newWriter(Path file, boolean append) throws IOException {
createParentDirs(file); createParentDirs(file);
return Files.newBufferedWriter(file, UNICODE_CHARSET, append ? APPEND_OPTIONS : WRITE_OPTIONS); return Files.newBufferedWriter(file, UNICODE_CHARSET, append ? APPEND_OPTIONS : WRITE_OPTIONS);
} }
@LauncherAPI
public static ZipEntry newZipEntry(String name) { public static ZipEntry newZipEntry(String name) {
ZipEntry entry = new ZipEntry(name); ZipEntry entry = new ZipEntry(name);
entry.setTime(0); entry.setTime(0);
return entry; return entry;
} }
@LauncherAPI
public static ZipEntry newZipEntry(ZipEntry entry) { public static ZipEntry newZipEntry(ZipEntry entry) {
return newZipEntry(entry.getName()); return newZipEntry(entry.getName());
} }
@LauncherAPI
public static ZipInputStream newZipInput(InputStream input) { public static ZipInputStream newZipInput(InputStream input) {
return new ZipInputStream(input, UNICODE_CHARSET); return new ZipInputStream(input, UNICODE_CHARSET);
} }
@LauncherAPI
public static ZipInputStream newZipInput(Path file) throws IOException { public static ZipInputStream newZipInput(Path file) throws IOException {
return newZipInput(newInput(file)); return newZipInput(newInput(file));
} }
@LauncherAPI
public static ZipInputStream newZipInput(URL url) throws IOException { public static ZipInputStream newZipInput(URL url) throws IOException {
return newZipInput(newInput(url)); return newZipInput(newInput(url));
} }
@LauncherAPI
public static byte[] read(InputStream input) throws IOException { public static byte[] read(InputStream input) throws IOException {
try (ByteArrayOutputStream output = newByteArrayOutput()) { try (ByteArrayOutputStream output = newByteArrayOutput()) {
transfer(input, output); transfer(input, output);
@ -463,7 +461,7 @@ public static byte[] read(InputStream input) throws IOException {
} }
} }
@LauncherAPI
public static void read(InputStream input, byte[] bytes) throws IOException { public static void read(InputStream input, byte[] bytes) throws IOException {
int offset = 0; int offset = 0;
while (offset < bytes.length) { while (offset < bytes.length) {
@ -474,7 +472,7 @@ public static void read(InputStream input, byte[] bytes) throws IOException {
} }
} }
@LauncherAPI
public static byte[] read(Path file) throws IOException { public static byte[] read(Path file) throws IOException {
long size = readAttributes(file).size(); long size = readAttributes(file).size();
if (size > Integer.MAX_VALUE) if (size > Integer.MAX_VALUE)
@ -490,19 +488,19 @@ public static byte[] read(Path file) throws IOException {
return bytes; return bytes;
} }
@LauncherAPI
public static byte[] read(URL url) throws IOException { public static byte[] read(URL url) throws IOException {
try (InputStream input = newInput(url)) { try (InputStream input = newInput(url)) {
return read(input); return read(input);
} }
} }
@LauncherAPI
public static BasicFileAttributes readAttributes(Path path) throws IOException { public static BasicFileAttributes readAttributes(Path path) throws IOException {
return Files.readAttributes(path, BasicFileAttributes.class, LINK_OPTIONS); return Files.readAttributes(path, BasicFileAttributes.class, LINK_OPTIONS);
} }
@LauncherAPI
public static BufferedImage readTexture(Object input, boolean cloak) throws IOException { public static BufferedImage readTexture(Object input, boolean cloak) throws IOException {
ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next(); ImageReader reader = ImageIO.getImageReadersByMIMEType("image/png").next();
try { try {
@ -521,19 +519,19 @@ public static BufferedImage readTexture(Object input, boolean cloak) throws IOEx
} }
} }
@LauncherAPI
public static String request(URL url) throws IOException { public static String request(URL url) throws IOException {
return decode(read(url)).trim(); return decode(read(url)).trim();
} }
@LauncherAPI
public static InetSocketAddress resolve(InetSocketAddress address) { public static InetSocketAddress resolve(InetSocketAddress address) {
if (address.isUnresolved()) if (address.isUnresolved())
return new InetSocketAddress(address.getHostString(), address.getPort()); return new InetSocketAddress(address.getHostString(), address.getPort());
return address; return address;
} }
@LauncherAPI
public static Path resolveIncremental(Path dir, String name, String extension) { public static Path resolveIncremental(Path dir, String name, String extension) {
Path original = dir.resolve(name + '.' + extension); Path original = dir.resolve(name + '.' + extension);
if (!exists(original)) if (!exists(original))
@ -551,7 +549,7 @@ public static Path resolveIncremental(Path dir, String name, String extension) {
} }
} }
@LauncherAPI
public static Path resolveJavaBin(Path javaDir) { public static Path resolveJavaBin(Path javaDir) {
// Get Java binaries path // Get Java binaries path
Path javaBinDir = (javaDir == null ? JVM_DIR : javaDir).resolve("bin"); Path javaBinDir = (javaDir == null ? JVM_DIR : javaDir).resolve("bin");
@ -577,7 +575,7 @@ public static Path resolveJavaBin(Path javaDir) {
throw new RuntimeException("Java binary wasn't found"); throw new RuntimeException("Java binary wasn't found");
} }
@LauncherAPI
public static void setSocketFlags(Socket socket) throws SocketException { public static void setSocketFlags(Socket socket) throws SocketException {
// Set socket flags // Set socket flags
socket.setKeepAlive(false); socket.setKeepAlive(false);
@ -594,34 +592,34 @@ public static void setSocketFlags(Socket socket) throws SocketException {
socket.setPerformancePreferences(1, 0, 2); socket.setPerformancePreferences(1, 0, 2);
} }
@LauncherAPI
public static String toAbsPathString(Path path) { public static String toAbsPathString(Path path) {
return toAbsPath(path).toFile().getAbsolutePath(); return toAbsPath(path).toFile().getAbsolutePath();
} }
@LauncherAPI
public static Path toAbsPath(Path path) { public static Path toAbsPath(Path path) {
return path.normalize().toAbsolutePath(); return path.normalize().toAbsolutePath();
} }
@LauncherAPI
public static byte[] toByteArray(InputStream in) throws IOException { public static byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream(in.available()); ByteArrayOutputStream out = new ByteArrayOutputStream(in.available());
IOHelper.transfer(in, out); IOHelper.transfer(in, out);
return out.toByteArray(); return out.toByteArray();
} }
@LauncherAPI
public static Path toPath(String path) { public static Path toPath(String path) {
return Paths.get(CROSS_SEPARATOR_PATTERN.matcher(path).replaceAll(Matcher.quoteReplacement(PLATFORM_SEPARATOR))); return Paths.get(CROSS_SEPARATOR_PATTERN.matcher(path).replaceAll(Matcher.quoteReplacement(PLATFORM_SEPARATOR)));
} }
@LauncherAPI
public static String toString(Path path) { public static String toString(Path path) {
return PLATFORM_SEPARATOR_PATTERN.matcher(path.toString()).replaceAll(Matcher.quoteReplacement(CROSS_SEPARATOR)); return PLATFORM_SEPARATOR_PATTERN.matcher(path.toString()).replaceAll(Matcher.quoteReplacement(CROSS_SEPARATOR));
} }
@LauncherAPI
public static URI toURI(URL url) { public static URI toURI(URL url) {
try { try {
return url.toURI(); return url.toURI();
@ -630,7 +628,7 @@ public static URI toURI(URL url) {
} }
} }
@LauncherAPI
public static URL toURL(Path path) { public static URL toURL(Path path) {
try { try {
return path.toUri().toURL(); return path.toUri().toURL();
@ -639,14 +637,14 @@ public static URL toURL(Path path) {
} }
} }
@LauncherAPI
public static void transfer(byte[] write, Path file, boolean append) throws IOException { public static void transfer(byte[] write, Path file, boolean append) throws IOException {
try (OutputStream out = newOutput(file, append)) { try (OutputStream out = newOutput(file, append)) {
out.write(write); out.write(write);
} }
} }
@LauncherAPI
public static long transfer(InputStream input, OutputStream output) throws IOException { public static long transfer(InputStream input, OutputStream output) throws IOException {
long transferred = 0; long transferred = 0;
byte[] buffer = newBuffer(); byte[] buffer = newBuffer();
@ -657,26 +655,26 @@ public static long transfer(InputStream input, OutputStream output) throws IOExc
return transferred; return transferred;
} }
@LauncherAPI
public static long transfer(InputStream input, Path file) throws IOException { public static long transfer(InputStream input, Path file) throws IOException {
return transfer(input, file, false); return transfer(input, file, false);
} }
@LauncherAPI
public static long transfer(InputStream input, Path file, boolean append) throws IOException { public static long transfer(InputStream input, Path file, boolean append) throws IOException {
try (OutputStream output = newOutput(file, append)) { try (OutputStream output = newOutput(file, append)) {
return transfer(input, output); return transfer(input, output);
} }
} }
@LauncherAPI
public static void transfer(Path file, OutputStream output) throws IOException { public static void transfer(Path file, OutputStream output) throws IOException {
try (InputStream input = newInput(file)) { try (InputStream input = newInput(file)) {
transfer(input, output); transfer(input, output);
} }
} }
@LauncherAPI
public static String urlDecode(String s) { public static String urlDecode(String s) {
try { try {
return URLDecoder.decode(s, UNICODE_CHARSET.name()); return URLDecoder.decode(s, UNICODE_CHARSET.name());
@ -685,7 +683,7 @@ public static String urlDecode(String s) {
} }
} }
@LauncherAPI
public static String urlEncode(String s) { public static String urlEncode(String s) {
try { try {
return URLEncoder.encode(s, UNICODE_CHARSET.name()); return URLEncoder.encode(s, UNICODE_CHARSET.name());
@ -694,25 +692,25 @@ public static String urlEncode(String s) {
} }
} }
@LauncherAPI
public static String verifyFileName(String fileName) { public static String verifyFileName(String fileName) {
return VerifyHelper.verify(fileName, IOHelper::isValidFileName, String.format("Invalid file name: '%s'", fileName)); return VerifyHelper.verify(fileName, IOHelper::isValidFileName, String.format("Invalid file name: '%s'", fileName));
} }
@LauncherAPI
public static int verifyLength(int length, int max) throws IOException { public static int verifyLength(int length, int max) throws IOException {
if (length < 0 || max < 0 && length != -max || max > 0 && length > max) if (length < 0 || max < 0 && length != -max || max > 0 && length > max)
throw new IOException("Illegal length: " + length); throw new IOException("Illegal length: " + length);
return length; return length;
} }
@LauncherAPI
public static BufferedImage verifyTexture(BufferedImage skin, boolean cloak) { public static BufferedImage verifyTexture(BufferedImage skin, boolean cloak) {
return VerifyHelper.verify(skin, i -> isValidTextureBounds(i.getWidth(), i.getHeight(), cloak), return VerifyHelper.verify(skin, i -> isValidTextureBounds(i.getWidth(), i.getHeight(), cloak),
String.format("Invalid texture bounds: %dx%d", skin.getWidth(), skin.getHeight())); String.format("Invalid texture bounds: %dx%d", skin.getWidth(), skin.getHeight()));
} }
@LauncherAPI
public static String verifyURL(String url) { public static String verifyURL(String url) {
try { try {
new URL(url).toURI(); new URL(url).toURI();
@ -722,12 +720,12 @@ public static String verifyURL(String url) {
} }
} }
@LauncherAPI
public static void walk(Path dir, FileVisitor<Path> visitor, boolean hidden) throws IOException { public static void walk(Path dir, FileVisitor<Path> visitor, boolean hidden) throws IOException {
Files.walkFileTree(dir, WALK_OPTIONS, Integer.MAX_VALUE, hidden ? visitor : new SkipHiddenVisitor(visitor)); Files.walkFileTree(dir, WALK_OPTIONS, Integer.MAX_VALUE, hidden ? visitor : new SkipHiddenVisitor(visitor));
} }
@LauncherAPI
public static void write(Path file, byte[] bytes) throws IOException { public static void write(Path file, byte[] bytes) throws IOException {
createParentDirs(file); createParentDirs(file);
Files.write(file, bytes, WRITE_OPTIONS); Files.write(file, bytes, WRITE_OPTIONS);

View file

@ -1,7 +1,5 @@
package pro.gravit.utils.helper; package pro.gravit.utils.helper;
import pro.gravit.launcher.LauncherAPI;
import java.io.File; import java.io.File;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
@ -16,7 +14,7 @@
import java.util.Map; import java.util.Map;
public final class JVMHelper { public final class JVMHelper {
@LauncherAPI
public enum OS { public enum OS {
MUSTDIE("mustdie"), LINUX("linux"), MACOSX("macosx"); MUSTDIE("mustdie"), LINUX("linux"), MACOSX("macosx");
@ -43,16 +41,16 @@ public static OS byName(String name) {
public static final OperatingSystemMXBean OPERATING_SYSTEM_MXBEAN = public static final OperatingSystemMXBean OPERATING_SYSTEM_MXBEAN =
ManagementFactory.getOperatingSystemMXBean(); ManagementFactory.getOperatingSystemMXBean();
// System properties // System properties
@LauncherAPI
public static final OS OS_TYPE = OS.byName(OPERATING_SYSTEM_MXBEAN.getName()); public static final OS OS_TYPE = OS.byName(OPERATING_SYSTEM_MXBEAN.getName());
@LauncherAPI
public static final String OS_VERSION = OPERATING_SYSTEM_MXBEAN.getVersion(); public static final String OS_VERSION = OPERATING_SYSTEM_MXBEAN.getVersion();
@LauncherAPI
public static final int OS_BITS = getCorrectOSArch(); public static final int OS_BITS = getCorrectOSArch();
@LauncherAPI
public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model")); public static final int JVM_BITS = Integer.parseInt(System.getProperty("sun.arch.data.model"));
@LauncherAPI
public static final SecurityManager SECURITY_MANAGER = System.getSecurityManager(); public static final SecurityManager SECURITY_MANAGER = System.getSecurityManager();
// Public static fields // Public static fields
public static final Runtime RUNTIME = Runtime.getRuntime(); public static final Runtime RUNTIME = Runtime.getRuntime();
@ -93,7 +91,7 @@ public static Class<?> firstClass(String... names) throws ClassNotFoundException
throw new ClassNotFoundException(Arrays.toString(names)); throw new ClassNotFoundException(Arrays.toString(names));
} }
@LauncherAPI
public static void fullGC() { public static void fullGC() {
RUNTIME.gc(); RUNTIME.gc();
RUNTIME.runFinalization(); RUNTIME.runFinalization();
@ -146,27 +144,27 @@ private static int getCorrectOSArch() {
return System.getProperty("os.arch").contains("64") ? 64 : 32; return System.getProperty("os.arch").contains("64") ? 64 : 32;
} }
@LauncherAPI
public static String getEnvPropertyCaseSensitive(String name) { public static String getEnvPropertyCaseSensitive(String name) {
return System.getenv().get(name); return System.getenv().get(name);
} }
@LauncherAPI
public static boolean isJVMMatchesSystemArch() { public static boolean isJVMMatchesSystemArch() {
return JVM_BITS == OS_BITS; return JVM_BITS == OS_BITS;
} }
@LauncherAPI
public static String jvmProperty(String name, String value) { public static String jvmProperty(String name, String value) {
return String.format("-D%s=%s", name, value); return String.format("-D%s=%s", name, value);
} }
@LauncherAPI
public static String systemToJvmProperty(String name) { public static String systemToJvmProperty(String name) {
return String.format("-D%s=%s", name, System.getProperties().getProperty(name)); return String.format("-D%s=%s", name, System.getProperties().getProperty(name));
} }
@LauncherAPI
public static void addSystemPropertyToArgs(Collection<String> args, String name) { public static void addSystemPropertyToArgs(Collection<String> args, String name) {
String property = System.getProperty(name); String property = System.getProperty(name);
if (property != null) if (property != null)

View file

@ -3,7 +3,6 @@
import org.fusesource.jansi.Ansi; import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole; import org.fusesource.jansi.AnsiConsole;
import org.fusesource.jansi.AnsiOutputStream; import org.fusesource.jansi.AnsiOutputStream;
import pro.gravit.launcher.LauncherAPI;
import pro.gravit.launcher.LauncherNetworkAPI; import pro.gravit.launcher.LauncherNetworkAPI;
import java.io.*; import java.io.*;
@ -20,15 +19,15 @@
import java.util.function.Supplier; import java.util.function.Supplier;
public final class LogHelper { public final class LogHelper {
@LauncherAPI
public static final String DEBUG_PROPERTY = "launcher.debug"; public static final String DEBUG_PROPERTY = "launcher.debug";
@LauncherAPI
public static final String DEV_PROPERTY = "launcher.dev"; public static final String DEV_PROPERTY = "launcher.dev";
@LauncherAPI
public static final String STACKTRACE_PROPERTY = "launcher.stacktrace"; public static final String STACKTRACE_PROPERTY = "launcher.stacktrace";
@LauncherAPI
public static final String NO_JANSI_PROPERTY = "launcher.noJAnsi"; public static final String NO_JANSI_PROPERTY = "launcher.noJAnsi";
@LauncherAPI
public static final boolean JANSI; public static final boolean JANSI;
// Output settings // Output settings
@ -63,22 +62,22 @@ public enum OutputTypes {
private LogHelper() { private LogHelper() {
} }
@LauncherAPI
public static void addOutput(OutputEnity output) { public static void addOutput(OutputEnity output) {
OUTPUTS.add(Objects.requireNonNull(output, "output")); OUTPUTS.add(Objects.requireNonNull(output, "output"));
} }
@LauncherAPI
public static void addExcCallback(Consumer<Throwable> output) { public static void addExcCallback(Consumer<Throwable> output) {
EXCEPTIONS_CALLBACKS.add(Objects.requireNonNull(output, "output")); EXCEPTIONS_CALLBACKS.add(Objects.requireNonNull(output, "output"));
} }
@LauncherAPI
public static void addOutput(Output output, OutputTypes type) { public static void addOutput(Output output, OutputTypes type) {
OUTPUTS.add(new OutputEnity(Objects.requireNonNull(output, "output"), type)); OUTPUTS.add(new OutputEnity(Objects.requireNonNull(output, "output"), type));
} }
@LauncherAPI
public static void addOutput(Path file) throws IOException { public static void addOutput(Path file) throws IOException {
if (JANSI) { if (JANSI) {
addOutput(new JAnsiOutput(IOHelper.newOutput(file, true)), OutputTypes.JANSI); addOutput(new JAnsiOutput(IOHelper.newOutput(file, true)), OutputTypes.JANSI);
@ -87,89 +86,89 @@ public static void addOutput(Path file) throws IOException {
} }
} }
@LauncherAPI
public static void addOutput(Writer writer) { public static void addOutput(Writer writer) {
addOutput(new WriterOutput(writer), OutputTypes.PLAIN); addOutput(new WriterOutput(writer), OutputTypes.PLAIN);
} }
@LauncherAPI
public static void debug(String message) { public static void debug(String message) {
if (isDebugEnabled()) { if (isDebugEnabled()) {
log(Level.DEBUG, message, false); log(Level.DEBUG, message, false);
} }
} }
@LauncherAPI
public static void dev(String message) { public static void dev(String message) {
if (isDevEnabled()) { if (isDevEnabled()) {
log(Level.DEV, message, false); log(Level.DEV, message, false);
} }
} }
@LauncherAPI
public static void debug(String format, Object... args) { public static void debug(String format, Object... args) {
debug(String.format(format, args)); debug(String.format(format, args));
} }
@LauncherAPI
public static void dev(String format, Object... args) { public static void dev(String format, Object... args) {
if (isDevEnabled()) { if (isDevEnabled()) {
dev(String.format(format, args)); dev(String.format(format, args));
} }
} }
@LauncherAPI
public static void error(Throwable exc) { public static void error(Throwable exc) {
EXCEPTIONS_CALLBACKS.forEach(e -> e.accept(exc)); EXCEPTIONS_CALLBACKS.forEach(e -> e.accept(exc));
error(isStacktraceEnabled() ? toString(exc) : exc.toString()); error(isStacktraceEnabled() ? toString(exc) : exc.toString());
} }
@LauncherAPI
public static void error(String message) { public static void error(String message) {
log(Level.ERROR, message, false); log(Level.ERROR, message, false);
} }
@LauncherAPI
public static void error(String format, Object... args) { public static void error(String format, Object... args) {
error(String.format(format, args)); error(String.format(format, args));
} }
@LauncherAPI
public static void info(String message) { public static void info(String message) {
log(Level.INFO, message, false); log(Level.INFO, message, false);
} }
@LauncherAPI
public static void info(String format, Object... args) { public static void info(String format, Object... args) {
info(String.format(format, args)); info(String.format(format, args));
} }
@LauncherAPI
public static boolean isDebugEnabled() { public static boolean isDebugEnabled() {
return DEBUG_ENABLED.get(); return DEBUG_ENABLED.get();
} }
@LauncherAPI
public static void setDebugEnabled(boolean debugEnabled) { public static void setDebugEnabled(boolean debugEnabled) {
DEBUG_ENABLED.set(debugEnabled); DEBUG_ENABLED.set(debugEnabled);
} }
@LauncherAPI
public static boolean isStacktraceEnabled() { public static boolean isStacktraceEnabled() {
return STACKTRACE_ENABLED.get(); return STACKTRACE_ENABLED.get();
} }
@LauncherAPI
public static boolean isDevEnabled() { public static boolean isDevEnabled() {
return DEV_ENABLED.get(); return DEV_ENABLED.get();
} }
@LauncherAPI
public static void setStacktraceEnabled(boolean stacktraceEnabled) { public static void setStacktraceEnabled(boolean stacktraceEnabled) {
STACKTRACE_ENABLED.set(stacktraceEnabled); STACKTRACE_ENABLED.set(stacktraceEnabled);
} }
@LauncherAPI
public static void setDevEnabled(boolean stacktraceEnabled) { public static void setDevEnabled(boolean stacktraceEnabled) {
DEV_ENABLED.set(stacktraceEnabled); DEV_ENABLED.set(stacktraceEnabled);
} }
@ -178,7 +177,7 @@ public static String getDataTime() {
return DATE_TIME_FORMATTER.format(LocalDateTime.now()); return DATE_TIME_FORMATTER.format(LocalDateTime.now());
} }
@LauncherAPI
public static void log(Level level, String message, boolean sub) { public static void log(Level level, String message, boolean sub) {
String dateTime = DATE_TIME_FORMATTER.format(LocalDateTime.now()); String dateTime = DATE_TIME_FORMATTER.format(LocalDateTime.now());
String jansiString = null, plainString = null, htmlString = null; String jansiString = null, plainString = null, htmlString = null;
@ -211,12 +210,12 @@ public static void log(Level level, String message, boolean sub) {
} }
} }
@LauncherAPI
public static void rawLog(Supplier<String> plainStr, Supplier<String> jansiStr) { public static void rawLog(Supplier<String> plainStr, Supplier<String> jansiStr) {
rawLog(plainStr, jansiStr, null); rawLog(plainStr, jansiStr, null);
} }
@LauncherAPI
public static void rawLog(Supplier<String> plainStr, Supplier<String> jansiStr, Supplier<String> htmlStr) { public static void rawLog(Supplier<String> plainStr, Supplier<String> jansiStr, Supplier<String> htmlStr) {
String jansiString = null, plainString = null, htmlString = null; String jansiString = null, plainString = null, htmlString = null;
for (OutputEnity output : OUTPUTS) { for (OutputEnity output : OUTPUTS) {
@ -248,7 +247,7 @@ public static void rawLog(Supplier<String> plainStr, Supplier<String> jansiStr,
} }
} }
@LauncherAPI
public static void printVersion(String product) { public static void printVersion(String product) {
String jansiString = null, plainString = null; String jansiString = null, plainString = null;
for (OutputEnity output : OUTPUTS) { for (OutputEnity output : OUTPUTS) {
@ -272,7 +271,7 @@ public static void printVersion(String product) {
} }
} }
@LauncherAPI
public static void printLicense(String product) { public static void printLicense(String product) {
String jansiString = null, plainString = null; String jansiString = null, plainString = null;
for (OutputEnity output : OUTPUTS) { for (OutputEnity output : OUTPUTS) {
@ -296,61 +295,61 @@ public static void printLicense(String product) {
} }
} }
@LauncherAPI
public static boolean removeOutput(OutputEnity output) { public static boolean removeOutput(OutputEnity output) {
return OUTPUTS.remove(output); return OUTPUTS.remove(output);
} }
@LauncherAPI
public static boolean removeStdOutput() { public static boolean removeStdOutput() {
return removeOutput(STD_OUTPUT); return removeOutput(STD_OUTPUT);
} }
@LauncherAPI
public static void subDebug(String message) { public static void subDebug(String message) {
if (isDebugEnabled()) { if (isDebugEnabled()) {
log(Level.DEBUG, message, true); log(Level.DEBUG, message, true);
} }
} }
@LauncherAPI
public static void subDebug(String format, Object... args) { public static void subDebug(String format, Object... args) {
subDebug(String.format(format, args)); subDebug(String.format(format, args));
} }
@LauncherAPI
public static void subInfo(String message) { public static void subInfo(String message) {
log(Level.INFO, message, true); log(Level.INFO, message, true);
} }
@LauncherAPI
public static void subInfo(String format, Object... args) { public static void subInfo(String format, Object... args) {
subInfo(String.format(format, args)); subInfo(String.format(format, args));
} }
@LauncherAPI
public static void subWarning(String message) { public static void subWarning(String message) {
log(Level.WARNING, message, true); log(Level.WARNING, message, true);
} }
@LauncherAPI
public static void subWarning(String format, Object... args) { public static void subWarning(String format, Object... args) {
subWarning(String.format(format, args)); subWarning(String.format(format, args));
} }
@LauncherAPI
public static String toString(Throwable exc) { public static String toString(Throwable exc) {
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
exc.printStackTrace(new PrintWriter(sw)); exc.printStackTrace(new PrintWriter(sw));
return sw.toString(); return sw.toString();
} }
@LauncherAPI
public static void warning(String message) { public static void warning(String message) {
log(Level.WARNING, message, false); log(Level.WARNING, message, false);
} }
@LauncherAPI
public static void warning(String format, Object... args) { public static void warning(String format, Object... args) {
warning(String.format(format, args)); warning(String.format(format, args));
} }
@ -425,13 +424,13 @@ private static String formatLog(Level level, String message, String dateTime, bo
} }
} }
@LauncherAPI
@FunctionalInterface @FunctionalInterface
public interface Output { public interface Output {
void println(String message); void println(String message);
} }
@LauncherAPI
public enum Level { public enum Level {
DEV("DEV"), DEBUG("DEBUG"), INFO("INFO"), WARNING("WARN"), ERROR("ERROR"); DEV("DEV"), DEBUG("DEBUG"), INFO("INFO"), WARNING("WARN"), ERROR("ERROR");
public final String name; public final String name;

View file

@ -1,7 +1,5 @@
package pro.gravit.utils.helper; package pro.gravit.utils.helper;
import pro.gravit.launcher.LauncherAPI;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator; import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException; import javax.crypto.NoSuchPaddingException;
@ -266,12 +264,12 @@ public static byte[] randomBytes(Random random, int length) {
return bytes; return bytes;
} }
@LauncherAPI
public static String randomStringToken() { public static String randomStringToken() {
return randomStringToken(newRandom()); return randomStringToken(newRandom());
} }
@LauncherAPI
public static String randomStringToken(Random random) { public static String randomStringToken(Random random) {
return toHex(randomToken(random)); return toHex(randomToken(random));
} }

View file

@ -1,7 +1,5 @@
package pro.gravit.utils.helper; package pro.gravit.utils.helper;
import pro.gravit.launcher.LauncherAPI;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.DoublePredicate; import java.util.function.DoublePredicate;
@ -11,95 +9,95 @@
import java.util.regex.Pattern; import java.util.regex.Pattern;
public final class VerifyHelper { public final class VerifyHelper {
@LauncherAPI
public static final IntPredicate POSITIVE = i -> i > 0; public static final IntPredicate POSITIVE = i -> i > 0;
@LauncherAPI
public static final IntPredicate NOT_NEGATIVE = i -> i >= 0; public static final IntPredicate NOT_NEGATIVE = i -> i >= 0;
@LauncherAPI
public static final LongPredicate L_POSITIVE = l -> l > 0; public static final LongPredicate L_POSITIVE = l -> l > 0;
@LauncherAPI
public static final LongPredicate L_NOT_NEGATIVE = l -> l >= 0; public static final LongPredicate L_NOT_NEGATIVE = l -> l >= 0;
@LauncherAPI
public static final Predicate<String> NOT_EMPTY = s -> !s.isEmpty(); public static final Predicate<String> NOT_EMPTY = s -> !s.isEmpty();
@LauncherAPI
public static final Pattern USERNAME_PATTERN = Pattern.compile(Boolean.parseBoolean(System.getProperty("username.russian", "true")) ? "[a-zA-Zа-яА-Я0-9_.\\-]{1,16}" : "[a-zA-Z0-9-_\\\\.]{1,16}"); public static final Pattern USERNAME_PATTERN = Pattern.compile(Boolean.parseBoolean(System.getProperty("username.russian", "true")) ? "[a-zA-Zа-яА-Я0-9_.\\-]{1,16}" : "[a-zA-Z0-9-_\\\\.]{1,16}");
private static final Pattern SERVERID_PATTERN = Pattern.compile("-?[0-9a-f]{1,40}"); private static final Pattern SERVERID_PATTERN = Pattern.compile("-?[0-9a-f]{1,40}");
@LauncherAPI
public static <K, V> V getMapValue(Map<K, V> map, K key, String error) { public static <K, V> V getMapValue(Map<K, V> map, K key, String error) {
return verify(map.get(key), Objects::nonNull, error); return verify(map.get(key), Objects::nonNull, error);
} }
@LauncherAPI
public static boolean isValidIDName(String name) { public static boolean isValidIDName(String name) {
return !name.isEmpty() && name.length() <= 255 && name.chars().allMatch(VerifyHelper::isValidIDNameChar); return !name.isEmpty() && name.length() <= 255 && name.chars().allMatch(VerifyHelper::isValidIDNameChar);
} }
@LauncherAPI
public static boolean isValidIDNameChar(int ch) { public static boolean isValidIDNameChar(int ch) {
return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '-' || ch == '_'; return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch == '-' || ch == '_';
} }
@LauncherAPI
public static boolean isValidServerID(CharSequence serverID) { public static boolean isValidServerID(CharSequence serverID) {
return SERVERID_PATTERN.matcher(serverID).matches(); return SERVERID_PATTERN.matcher(serverID).matches();
} }
@LauncherAPI
public static boolean isValidUsername(CharSequence username) { public static boolean isValidUsername(CharSequence username) {
return USERNAME_PATTERN.matcher(username).matches(); return USERNAME_PATTERN.matcher(username).matches();
} }
@LauncherAPI
public static <K, V> void putIfAbsent(Map<K, V> map, K key, V value, String error) { public static <K, V> void putIfAbsent(Map<K, V> map, K key, V value, String error) {
verify(map.putIfAbsent(key, value), Objects::isNull, error); verify(map.putIfAbsent(key, value), Objects::isNull, error);
} }
@LauncherAPI
public static IntPredicate range(int min, int max) { public static IntPredicate range(int min, int max) {
return i -> i >= min && i <= max; return i -> i >= min && i <= max;
} }
@LauncherAPI
public static <T> T verify(T object, Predicate<T> predicate, String error) { public static <T> T verify(T object, Predicate<T> predicate, String error) {
if (predicate.test(object)) if (predicate.test(object))
return object; return object;
throw new IllegalArgumentException(error); throw new IllegalArgumentException(error);
} }
@LauncherAPI
public static double verifyDouble(double d, DoublePredicate predicate, String error) { public static double verifyDouble(double d, DoublePredicate predicate, String error) {
if (predicate.test(d)) if (predicate.test(d))
return d; return d;
throw new IllegalArgumentException(error); throw new IllegalArgumentException(error);
} }
@LauncherAPI
public static String verifyIDName(String name) { public static String verifyIDName(String name) {
return verify(name, VerifyHelper::isValidIDName, String.format("Invalid name: '%s'", name)); return verify(name, VerifyHelper::isValidIDName, String.format("Invalid name: '%s'", name));
} }
@LauncherAPI
public static int verifyInt(int i, IntPredicate predicate, String error) { public static int verifyInt(int i, IntPredicate predicate, String error) {
if (predicate.test(i)) if (predicate.test(i))
return i; return i;
throw new IllegalArgumentException(error); throw new IllegalArgumentException(error);
} }
@LauncherAPI
public static long verifyLong(long l, LongPredicate predicate, String error) { public static long verifyLong(long l, LongPredicate predicate, String error) {
if (predicate.test(l)) if (predicate.test(l))
return l; return l;
throw new IllegalArgumentException(error); throw new IllegalArgumentException(error);
} }
@LauncherAPI
public static String verifyServerID(String serverID) { public static String verifyServerID(String serverID) {
return verify(serverID, VerifyHelper::isValidServerID, return verify(serverID, VerifyHelper::isValidServerID,
String.format("Invalid server ID: '%s'", serverID)); String.format("Invalid server ID: '%s'", serverID));
} }
@LauncherAPI
public static String verifyUsername(String username) { public static String verifyUsername(String username) {
return verify(username, VerifyHelper::isValidUsername, String.format("Invalid username: '%s'", username)); return verify(username, VerifyHelper::isValidUsername, String.format("Invalid username: '%s'", username));
} }

@ -1 +1 @@
Subproject commit bf7994eb6358c6440cb84846918afbc118fa3dae Subproject commit 9ee94152da6ae8e3ea045484f60b2a2246b4e993