mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 03:31:15 +03:00
Merge branch 'release/5.0.9'
This commit is contained in:
commit
610b6de76f
39 changed files with 674 additions and 296 deletions
|
@ -1,41 +1,49 @@
|
|||
image: frekele/java
|
||||
image: docker:latest
|
||||
services:
|
||||
- docker:dind
|
||||
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
CI_VERSION: '6.6.$CI_PIPELINE_IID'
|
||||
|
||||
stages:
|
||||
- build
|
||||
- test
|
||||
- deploy
|
||||
|
||||
before_script:
|
||||
# - echo `pwd` # debug
|
||||
# - echo "$CI_BUILD_NAME, $CI_BUILD_REF_NAME $CI_BUILD_STAGE" # debug
|
||||
- export GRADLE_USER_HOME=`pwd`/.gradle
|
||||
- apt-get update -qq && apt-get install -y -qq git git-core
|
||||
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_NAME}
|
||||
paths:
|
||||
- .gradle/wrapper
|
||||
- .gradle/caches
|
||||
- build
|
||||
- test
|
||||
|
||||
build:
|
||||
image: frekele/java
|
||||
stage: build
|
||||
before_script:
|
||||
- apt-get -y update
|
||||
- apt-get -y install zip git
|
||||
- export GRADLE_USER_HOME=`pwd`/.gradle
|
||||
- chmod +x gradlew
|
||||
- sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
|
||||
- git submodule sync
|
||||
- git submodule update --init --recursive
|
||||
script:
|
||||
- sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
|
||||
- git submodule sync
|
||||
- git submodule update --init --recursive
|
||||
- ./gradlew assemble
|
||||
- mv LaunchServer/build/libs/*.jar LaunchServer
|
||||
- mv ServerWrapper/build/libs/*.jar ServerWrapper
|
||||
- mv modules/*_module/build/libs/*.jar modules
|
||||
artifacts:
|
||||
- ./gradlew assemble
|
||||
after_script:
|
||||
- mkdir -p artifacts/modules
|
||||
- cd LaunchServer/build/libs/
|
||||
- zip -r -9 ../../../artifacts/libraries.zip * -x "LaunchServer.jar" -x "LaunchServer-clean.jar"
|
||||
- mv LaunchServer.jar ../../../artifacts/LaunchServer.jar
|
||||
- cd ../../../ServerWrapper/build/libs
|
||||
- mv ServerWrapper.jar ../../../artifacts/ServerWrapper.jar
|
||||
- cd ../../../
|
||||
- mv modules/*_module/build/libs/*.jar artifacts/modules
|
||||
- mv modules/*_swmodule/build/libs/*.jar artifacts/modules
|
||||
- mv modules/*_lmodule/build/libs/*.jar artifacts/modules
|
||||
cache:
|
||||
paths:
|
||||
- LaunchServer/*.jar
|
||||
- ServerWrapper/*.jar
|
||||
- modules/*.jar
|
||||
- .gradle
|
||||
artifacts:
|
||||
expire_in: 6 week
|
||||
paths:
|
||||
- artifacts
|
||||
|
||||
test:
|
||||
image: frekele/java
|
||||
stage: test
|
||||
script:
|
||||
- ./gradlew check
|
||||
|
||||
after_script:
|
||||
- echo "End CI"
|
||||
- ./gradlew check
|
|
@ -55,6 +55,15 @@ public void acceptVisitor(byte[] classData, ClassVisitor visitor) {
|
|||
public void acceptVisitor(String className, ClassVisitor visitor) throws IOException {
|
||||
acceptVisitor(getClassData(className), visitor);
|
||||
}
|
||||
|
||||
public void acceptVisitor(byte[] classData, ClassVisitor visitor, int flags) {
|
||||
new ClassReader(classData).accept(visitor, flags);
|
||||
}
|
||||
|
||||
public void acceptVisitor(String className, ClassVisitor visitor, int flags) throws IOException {
|
||||
acceptVisitor(getClassData(className), visitor, flags);
|
||||
}
|
||||
|
||||
|
||||
public byte[] getClassData(String className) throws IOException {
|
||||
for (JarFile f : cp) {
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
package pro.gravit.launchserver.asm;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public final class NodeUtils {
|
||||
private NodeUtils() { }
|
||||
public static ClassNode forClass(Class<?> cls, int flags) {
|
||||
try (InputStream in = cls.getClassLoader().getResourceAsStream(cls.getName().replace('.', '/') + ".class")) {
|
||||
ClassNode ret = new ClassNode();
|
||||
new ClassReader(IOHelper.read(in)).accept(ret, flags);
|
||||
return ret;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassNode forClass(String clazz, int flags, ClassMetadataReader r) {
|
||||
try {
|
||||
ClassNode ret = new ClassNode();
|
||||
r.acceptVisitor(clazz, ret, flags);
|
||||
return ret;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<AnnotationNode> annots(String clazz, String method, ClassMetadataReader r) {
|
||||
if (clazz.startsWith("L")) clazz = Type.getType(clazz).getInternalName();
|
||||
try {
|
||||
List<AnnotationNode> ret = new ArrayList<>();
|
||||
ClassNode n = forClass(clazz, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG, r);
|
||||
if (n.visibleAnnotations != null) ret.addAll(n.visibleAnnotations);
|
||||
if (n.invisibleAnnotations != null) ret.addAll(n.invisibleAnnotations);
|
||||
for (MethodNode m : n.methods)
|
||||
if (method.equals(m.name)) {
|
||||
if (m.visibleAnnotations != null) ret.addAll(m.visibleAnnotations);
|
||||
if (m.invisibleAnnotations != null) ret.addAll(m.invisibleAnnotations);
|
||||
}
|
||||
return ret;
|
||||
} catch (Throwable e) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static int doMethodEmulation(String desc) {
|
||||
int result = 0;
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
|
||||
if (returnType.getSort() == Type.LONG || returnType.getSort() == Type.DOUBLE)
|
||||
result++;
|
||||
if (returnType.getSort() != Type.VOID)
|
||||
result++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int opcodeEmulation(AbstractInsnNode e) {
|
||||
int stackSize = 0;
|
||||
switch (e.getOpcode()) {
|
||||
case NOP:
|
||||
case LALOAD: // (index, arrayref) -> (long, long_top)
|
||||
case DALOAD: // (index, arrayref) -> (double, double_top)
|
||||
case SWAP: // (value1, value2) -> (value2, value1)
|
||||
case INEG:
|
||||
case LNEG:
|
||||
case FNEG:
|
||||
case DNEG:
|
||||
case IINC:
|
||||
case I2F:
|
||||
case L2D:
|
||||
case F2I:
|
||||
case D2L:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
case GOTO:
|
||||
case RETURN:
|
||||
case NEWARRAY:
|
||||
case ANEWARRAY:
|
||||
case ARRAYLENGTH:
|
||||
case CHECKCAST:
|
||||
case INSTANCEOF:
|
||||
// Does nothing
|
||||
break;
|
||||
case ACONST_NULL:
|
||||
case ICONST_M1:
|
||||
case ICONST_0:
|
||||
case ICONST_1:
|
||||
case ICONST_2:
|
||||
case ICONST_3:
|
||||
case ICONST_4:
|
||||
case ICONST_5:
|
||||
case FCONST_0:
|
||||
case FCONST_1:
|
||||
case FCONST_2:
|
||||
case BIPUSH:
|
||||
case SIPUSH:
|
||||
case ILOAD:
|
||||
case FLOAD:
|
||||
case ALOAD:
|
||||
case DUP:
|
||||
case DUP_X1:
|
||||
case DUP_X2:
|
||||
case I2L:
|
||||
case I2D:
|
||||
case F2L:
|
||||
case F2D:
|
||||
case NEW:
|
||||
// Pushes one-word constant to stack
|
||||
stackSize++;
|
||||
break;
|
||||
case LDC:
|
||||
LdcInsnNode ldc = (LdcInsnNode) e;
|
||||
if (ldc.cst instanceof Long || ldc.cst instanceof Double)
|
||||
stackSize++;
|
||||
|
||||
stackSize++;
|
||||
break;
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
case LLOAD:
|
||||
case DLOAD:
|
||||
case DUP2:
|
||||
case DUP2_X1:
|
||||
case DUP2_X2:
|
||||
// Pushes two-word constant or two one-word constants to stack
|
||||
stackSize++;
|
||||
stackSize++;
|
||||
break;
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKESPECIAL:
|
||||
case INVOKEINTERFACE:
|
||||
stackSize += doMethodEmulation(((MethodInsnNode) e).desc);
|
||||
break;
|
||||
case INVOKESTATIC:
|
||||
stackSize += doMethodEmulation(((MethodInsnNode) e).desc);
|
||||
break;
|
||||
case INVOKEDYNAMIC:
|
||||
stackSize += doMethodEmulation(((InvokeDynamicInsnNode) e).desc);
|
||||
break;
|
||||
case JSR:
|
||||
case RET:
|
||||
throw new RuntimeException("Did not expect JSR/RET instructions");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return stackSize;
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@ public static void apply(Path inputFile, Path addFile, ZipOutputStream output, L
|
|||
try {
|
||||
bytes = classFix(bytes, reader, srv.config.launcher.stripLineNumbers);
|
||||
} catch (Throwable t) {
|
||||
LogHelper.subWarning("Error on fixing class: " + t);
|
||||
LogHelper.error(t);
|
||||
}
|
||||
output.write(bytes);
|
||||
} else
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import pro.gravit.launchserver.LaunchServer;
|
||||
import pro.gravit.launchserver.command.Command;
|
||||
import pro.gravit.launchserver.dao.User;
|
||||
import pro.gravit.launchserver.dao.UserHWID;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public class GetUserCommand extends Command {
|
||||
|
@ -31,9 +30,9 @@ public void invoke(String... args) throws Exception {
|
|||
return;
|
||||
}
|
||||
LogHelper.info("[%s] UUID: %s", user.username, user.uuid.toString());
|
||||
for(UserHWID hwid : user.hwids)
|
||||
{
|
||||
LogHelper.info("[%s] HWID: memory: %d | serial %s | hwdiskserial: %s | processorID %s | macAddr %s", user.username, hwid.totalMemory, hwid.serialNumber, hwid.HWDiskSerial, hwid.processorID, hwid.macAddr);
|
||||
}
|
||||
//for(UserHWID hwid : user.hwids)
|
||||
//{
|
||||
// LogHelper.info("[%s] HWID: memory: %d | serial %s | hwdiskserial: %s | processorID %s | macAddr %s", user.username, hwid.totalMemory, hwid.serialNumber, hwid.HWDiskSerial, hwid.processorID, hwid.macAddr);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,13 @@
|
|||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
|
@ -39,12 +34,6 @@ public class User {
|
|||
public String serverID;
|
||||
private String password_salt;
|
||||
public long permissions;
|
||||
//TODO: заменить EAGER на LASY и придумать способ сохранить сессию
|
||||
// [ERROR] org.hibernate.LazyInitializationException:
|
||||
// failed to lazily initialize a collection of role: pro.gravit.launchserver.dao.User.hwids, could not initialize proxy - no Session
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "user_id")
|
||||
public Collection<UserHWID> hwids;
|
||||
public void setPassword(String password)
|
||||
{
|
||||
password_salt = SecurityHelper.randomStringAESKey();
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"version": "1.14.4",
|
||||
"assetIndex": "1.14.4",
|
||||
"assetDir": "asset1.14.4",
|
||||
"dir": "HiTech",
|
||||
"info": "Информация о сервере",
|
||||
"sortIndex": 0,
|
||||
"title": "xxxxxxxx",
|
||||
"serverAddress": "localhost",
|
||||
"serverPort": 25565,
|
||||
"update": [
|
||||
"servers.dat"
|
||||
],
|
||||
"updateExclusions": [],
|
||||
"updateShared": [],
|
||||
"updateVerify": [
|
||||
"libraries",
|
||||
"natives",
|
||||
"minecraft.jar"
|
||||
],
|
||||
"updateOptional": [],
|
||||
"updateFastCheck": true,
|
||||
"useWhitelist": false,
|
||||
"mainClass": "net.minecraft.client.main.Main",
|
||||
"jvmArgs": [
|
||||
"-Dfml.ignorePatchDiscrepancies=true",
|
||||
"-Dfml.ignoreInvalidMinecraftCertificates=rue",
|
||||
"-XX:+UseConcMarkSweepGC",
|
||||
"-XX:+CMSIncrementalMode",
|
||||
"-XX:-UseAdaptiveSizePolicy",
|
||||
"-Xmn128M",
|
||||
"-XX:+DisableAttachMechanism"
|
||||
],
|
||||
"classPath": [
|
||||
"minecraft.jar",
|
||||
"libraries"
|
||||
],
|
||||
"clientArgs": [],
|
||||
"whitelist": []
|
||||
}
|
|
@ -20,9 +20,9 @@
|
|||
-keepattributes Signature
|
||||
-adaptresourcefilecontents META-INF/MANIFEST.MF
|
||||
|
||||
-keeppackagenames com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**
|
||||
-keeppackagenames 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.** {
|
||||
-keep class com.mojang.**,net.minecraftforge.fml.**,cpw.mods.fml.**,com.google.gson.**,pro.gravit.repackage.**,org.fusesource.**, pro.gravit.launcher.api.** {
|
||||
*;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package pro.gravit.launcher;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -8,6 +9,7 @@
|
|||
import java.util.List;
|
||||
|
||||
import pro.gravit.launcher.client.ClientLauncher;
|
||||
import pro.gravit.launcher.client.ClientModuleManager;
|
||||
import pro.gravit.launcher.client.DirBridge;
|
||||
import pro.gravit.utils.helper.EnvHelper;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
|
@ -17,7 +19,9 @@
|
|||
public class ClientLauncherWrapper {
|
||||
public static final String MAGIC_ARG = "-Djdk.attach.allowAttachSelf";
|
||||
public static final String WAIT_PROCESS_PROPERTY = "launcher.waitProcess";
|
||||
public static final String NO_JAVA9_CHECK_PROPERTY = "launcher.noJava9Check";
|
||||
public static boolean waitProcess = Boolean.getBoolean(WAIT_PROCESS_PROPERTY);
|
||||
public static boolean noJava9check = Boolean.getBoolean(NO_JAVA9_CHECK_PROPERTY);
|
||||
|
||||
public static void main(String[] arguments) throws IOException, InterruptedException {
|
||||
LogHelper.printVersion("Launcher");
|
||||
|
@ -26,6 +30,9 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
|
|||
JVMHelper.verifySystemProperties(Launcher.class, true);
|
||||
EnvHelper.checkDangerousParams();
|
||||
LauncherConfig config = Launcher.getConfig();
|
||||
LauncherEngine.modulesManager = new ClientModuleManager();
|
||||
LauncherConfig.getAutogenConfig().initModules();
|
||||
|
||||
LogHelper.info("Launcher for project %s", config.projectname);
|
||||
if (config.environment.equals(LauncherConfig.LauncherEnvironment.PROD)) {
|
||||
if (System.getProperty(LogHelper.DEBUG_PROPERTY) != null) {
|
||||
|
@ -53,12 +60,34 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
|
|||
JVMHelper.addSystemPropertyToArgs(args, DirBridge.CUSTOMDIR_PROPERTY);
|
||||
JVMHelper.addSystemPropertyToArgs(args, DirBridge.USE_CUSTOMDIR_PROPERTY);
|
||||
JVMHelper.addSystemPropertyToArgs(args, DirBridge.USE_OPTDIR_PROPERTY);
|
||||
if (!noJava9check && !System.getProperty("java.version").startsWith("1.8"))
|
||||
{
|
||||
LogHelper.debug("Found Java 9+ ( %s )", System.getProperty("java.version"));
|
||||
Collections.addAll(args, "--add-modules");
|
||||
Collections.addAll(args, "javafx.base,javafx.fxml,javafx.controls,jdk.unsupported");
|
||||
Path jvmDir = Paths.get(System.getProperty("java.home"));
|
||||
String pathToFx = System.getenv("PATH_TO_FX");
|
||||
Path fxPath = pathToFx == null ? null : Paths.get(pathToFx);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Path[] findPath = new Path[]{jvmDir, fxPath};
|
||||
tryAddModule(findPath, "javafx.base", builder);
|
||||
tryAddModule(findPath, "javafx.graphics", builder);
|
||||
tryAddModule(findPath, "javafx.fxml", builder);
|
||||
tryAddModule(findPath, "javafx.controls", builder);
|
||||
String modulePath = builder.toString();
|
||||
if(!modulePath.isEmpty())
|
||||
{
|
||||
Collections.addAll(args, "--module-path");
|
||||
Collections.addAll(args, modulePath);
|
||||
}
|
||||
}
|
||||
Collections.addAll(args, MAGIC_ARG);
|
||||
Collections.addAll(args, "-XX:+DisableAttachMechanism");
|
||||
Collections.addAll(args, "-javaagent:".concat(pathLauncher).concat("=pr"));
|
||||
Collections.addAll(args, "-javaagent:".concat(pathLauncher));
|
||||
Collections.addAll(args, "-cp");
|
||||
Collections.addAll(args, pathLauncher);
|
||||
Collections.addAll(args, LauncherEngine.class.getName());
|
||||
LauncherEngine.modulesManager.callWrapper(processBuilder, args);
|
||||
EnvHelper.addEnv(processBuilder);
|
||||
LogHelper.debug("Commandline: " + args);
|
||||
processBuilder.command(args);
|
||||
|
@ -78,4 +107,30 @@ public static void main(String[] arguments) throws IOException, InterruptedExcep
|
|||
process.waitFor();
|
||||
}
|
||||
}
|
||||
public static Path tryFindModule(Path path, String moduleName)
|
||||
{
|
||||
Path result = path.resolve(moduleName.concat(".jar"));
|
||||
LogHelper.dev("Try resolve %s", result.toString());
|
||||
if(!IOHelper.isFile(result))
|
||||
result = path.resolve("lib").resolve(moduleName.concat(".jar"));
|
||||
else return result;
|
||||
if(!IOHelper.isFile(result))
|
||||
return null;
|
||||
else return result;
|
||||
}
|
||||
public static boolean tryAddModule(Path[] paths, String moduleName, StringBuilder args)
|
||||
{
|
||||
for(Path path : paths)
|
||||
{
|
||||
if(path == null) continue;
|
||||
Path result = tryFindModule(path, moduleName);
|
||||
if(result != null)
|
||||
{
|
||||
if(args.length() != 0) args.append(File.pathSeparatorChar);
|
||||
args.append(result.toAbsolutePath().toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,14 @@
|
|||
package pro.gravit.launcher;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ACONST_NULL;
|
||||
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import cpw.mods.fml.SafeExitJVMLegacy;
|
||||
import net.minecraftforge.fml.SafeExitJVM;
|
||||
import pro.gravit.launcher.utils.NativeJVMHalt;
|
||||
import pro.gravit.utils.helper.JVMHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
@LauncherAPI
|
||||
|
@ -52,138 +37,16 @@ public static void premain(String agentArgument, Instrumentation instrumentation
|
|||
SafeExitJVM.class.getName();
|
||||
NativeJVMHalt.class.getName();
|
||||
NativeJVMHalt.initFunc();
|
||||
isAgentStarted = true;
|
||||
if (System.getProperty("java.vm.name").toUpperCase(Locale.US).contains("HOTSPOT"))
|
||||
try {
|
||||
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) {
|
||||
boolean pb = true;
|
||||
boolean rt = true;
|
||||
if (agentArgument != null) {
|
||||
String trimmedArg = agentArgument.trim();
|
||||
if (!trimmedArg.isEmpty()) {
|
||||
if (trimmedArg.contains("p")) pb = false;
|
||||
if (trimmedArg.contains("r")) rt = false;
|
||||
}
|
||||
}
|
||||
replaceClasses(pb, rt);
|
||||
} else replaceClasses(false, false);
|
||||
} catch (Error e) {
|
||||
NativeJVMHalt.haltA(294);
|
||||
throw e;
|
||||
}
|
||||
boolean bad = false;
|
||||
try {
|
||||
for (StackTraceElement e : new Throwable().getStackTrace())
|
||||
if (Class.forName(e.getClassName()).getClassLoader() != Runtime.class.getClassLoader() && Class.forName(e.getClassName()) != LauncherAgent.class) bad = true;
|
||||
} catch(Throwable e) { bad = true; }
|
||||
if (bad) NativeJVMHalt.haltA(-17);
|
||||
else isAgentStarted = true;
|
||||
}
|
||||
|
||||
public static boolean isStarted() {
|
||||
return isAgentStarted;
|
||||
}
|
||||
|
||||
private static void replaceClasses(boolean pb, boolean rt) {
|
||||
java.awt.Robot.class.getName();
|
||||
List<java.lang.instrument.ClassDefinition> defs = new ArrayList<>();
|
||||
if (rt) {
|
||||
try {
|
||||
defs.add(new java.lang.instrument.ClassDefinition(java.lang.Runtime.class, transformClass(java.lang.Runtime.class.getName(), getClassFile(java.lang.Runtime.class))));
|
||||
} catch (Exception e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
if (pb) {
|
||||
try {
|
||||
defs.add(new java.lang.instrument.ClassDefinition(java.lang.ProcessBuilder.class, transformClass(java.lang.ProcessBuilder.class.getName(), getClassFile(java.lang.ProcessBuilder.class))));
|
||||
} catch (Exception e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
defs.add(new java.lang.instrument.ClassDefinition(java.awt.Robot.class, transformClass(java.awt.Robot.class.getName(), getClassFile(java.awt.Robot.class))));
|
||||
} catch (Exception e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
try {
|
||||
inst.redefineClasses(defs.toArray(new java.lang.instrument.ClassDefinition[0]));
|
||||
} catch (Exception e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @author https://github.com/Konloch/JVM-Sandbox
|
||||
* Use ASM to modify the byte array
|
||||
*/
|
||||
private static byte[] transformClass(String className, byte[] classBytes) {
|
||||
switch (className) {
|
||||
case "java.lang.Runtime": {
|
||||
ClassReader cr = new ClassReader(classBytes);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
for (Object o : cn.methods.toArray()) {
|
||||
MethodNode m = (MethodNode) o;
|
||||
if (m.name.equals("exec")) {
|
||||
m.instructions.insert(new InsnNode(ARETURN));
|
||||
m.instructions.insert(new InsnNode(ACONST_NULL));
|
||||
}
|
||||
}
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
case "java.lang.ProcessBuilder": {
|
||||
ClassReader cr = new ClassReader(classBytes);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
for (Object o : cn.methods.toArray()) {
|
||||
MethodNode m = (MethodNode) o;
|
||||
if (m.name.equals("start")) {
|
||||
m.instructions.insert(new InsnNode(ARETURN));
|
||||
m.instructions.insert(new InsnNode(ACONST_NULL));
|
||||
}
|
||||
}
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
case "java.awt.Robot": {
|
||||
ClassReader cr = new ClassReader(classBytes);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
|
||||
for (Object o : cn.methods.toArray()) {
|
||||
MethodNode m = (MethodNode) o;
|
||||
if (m.name.equals("createScreenCapture") || m.name.equals("getPixelColor") ||
|
||||
m.name.equals("keyPress") || m.name.equals("keyRelease") ||
|
||||
m.name.equals("mouseMove") || m.name.equals("mousePress") ||
|
||||
m.name.equals("mouseWheel")) {
|
||||
m.instructions.insert(new InsnNode(ARETURN));
|
||||
m.instructions.insert(new InsnNode(ACONST_NULL));
|
||||
}
|
||||
}
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
cn.accept(cw);
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
return classBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz
|
||||
* @return array, respending this class in bytecode.
|
||||
* @throws IOException
|
||||
* @author https://github.com/Konloch/JVM-Sandbox
|
||||
* Do not remove this method. Do not to cause classloading!
|
||||
* Grab the byte array from the loaded Class object
|
||||
*/
|
||||
private static byte[] getClassFile(Class<?> clazz) throws IOException {
|
||||
try (InputStream is = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
|
||||
int r;
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((r = is.read(buffer)) >= 0) {
|
||||
baos.write(buffer, 0, r);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package pro.gravit.launcher.api;
|
||||
|
||||
import pro.gravit.launcher.ClientPermissions;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AuthService {
|
||||
public static String username;
|
||||
public static ClientPermissions permissions = new ClientPermissions();
|
||||
public static UUID uuid;
|
||||
public static boolean isAdmin()
|
||||
{
|
||||
return permissions.canAdmin;
|
||||
}
|
||||
public static boolean isServer()
|
||||
{
|
||||
return permissions.canServer;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package pro.gravit.launcher.api;
|
||||
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.net.URL;
|
||||
|
||||
public class ClientService {
|
||||
public static Instrumentation instrumentation;
|
||||
public static ClassLoader classLoader;
|
||||
public static URL[] baseURLs;
|
||||
}
|
|
@ -32,7 +32,11 @@
|
|||
import pro.gravit.launcher.LauncherAgent;
|
||||
import pro.gravit.launcher.LauncherConfig;
|
||||
import pro.gravit.launcher.LauncherEngine;
|
||||
import pro.gravit.launcher.api.AuthService;
|
||||
import pro.gravit.launcher.api.ClientService;
|
||||
import pro.gravit.launcher.client.events.ClientLaunchPhase;
|
||||
import pro.gravit.launcher.client.events.ClientLauncherInitPhase;
|
||||
import pro.gravit.launcher.client.events.ClientLauncherPostInitPhase;
|
||||
import pro.gravit.launcher.guard.LauncherGuardManager;
|
||||
import pro.gravit.launcher.gui.JSRuntimeProvider;
|
||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
||||
|
@ -40,7 +44,6 @@
|
|||
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||
import pro.gravit.launcher.managers.ClientGsonManager;
|
||||
import pro.gravit.launcher.managers.ClientHookManager;
|
||||
import pro.gravit.launcher.modules.events.PostInitPhase;
|
||||
import pro.gravit.launcher.modules.events.PreConfigPhase;
|
||||
import pro.gravit.launcher.profiles.ClientProfile;
|
||||
import pro.gravit.launcher.profiles.PlayerProfile;
|
||||
|
@ -51,6 +54,7 @@
|
|||
import pro.gravit.launcher.serialize.HOutput;
|
||||
import pro.gravit.launcher.serialize.stream.StreamObject;
|
||||
import pro.gravit.launcher.utils.DirWatcher;
|
||||
import pro.gravit.launcher.utils.NativeJVMHalt;
|
||||
import pro.gravit.utils.PublicURLClassLoader;
|
||||
import pro.gravit.utils.Version;
|
||||
import pro.gravit.utils.helper.CommonHelper;
|
||||
|
@ -300,11 +304,11 @@ private static void launch(ClientProfile profile, Params params) throws Throwabl
|
|||
LogHelper.debug("Args: " + copy);
|
||||
// Resolve main class and method
|
||||
Class<?> mainClass = classLoader.loadClass(profile.getMainClass());
|
||||
MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class));
|
||||
MethodHandle mainMethod = MethodHandles.publicLookup().findStatic(mainClass, "main", MethodType.methodType(void.class, String[].class)).asFixedArity();
|
||||
Launcher.LAUNCHED.set(true);
|
||||
JVMHelper.fullGC();
|
||||
// Invoke main method
|
||||
mainMethod.invoke((Object) args.toArray(new String[0]));
|
||||
mainMethod.invokeWithArguments((Object)args.toArray(new String[0]));
|
||||
}
|
||||
|
||||
private static Process process = null;
|
||||
|
@ -410,9 +414,16 @@ public static Process launch(
|
|||
builder.redirectErrorStream(true);
|
||||
builder.redirectOutput(Redirect.PIPE);
|
||||
}
|
||||
List<String> command = builder.command();
|
||||
// Let's rock!
|
||||
ClientHookManager.preStartHook.hook(context, builder);
|
||||
process = builder.start();
|
||||
if (builder.command() != command) {
|
||||
LogHelper.error("Something strange cheating...");
|
||||
System.exit(100);
|
||||
clientStarted = false;
|
||||
return null;
|
||||
}
|
||||
if(ClientHookManager.postStartHook.hook(context, builder)) return process;
|
||||
if (!pipeOutput) {
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
|
@ -434,6 +445,21 @@ public static Process launch(
|
|||
clientStarted = false;
|
||||
return process;
|
||||
}
|
||||
public static class ClientLaunchContext
|
||||
{
|
||||
public final Params params;
|
||||
public final ClientProfile profile;
|
||||
public final HashedDir assetHDir, clientHDir;
|
||||
public DirWatcher assetWatcher, clientWatcher;
|
||||
|
||||
|
||||
public ClientLaunchContext(Params params, ClientProfile profile, HashedDir assetHDir, HashedDir clientHDir) {
|
||||
this.params = params;
|
||||
this.profile = profile;
|
||||
this.assetHDir = assetHDir;
|
||||
this.clientHDir = clientHDir;
|
||||
}
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public static void main(String... args) throws Throwable {
|
||||
|
@ -444,6 +470,10 @@ public static void main(String... args) throws Throwable {
|
|||
LauncherEngine.modulesManager.initModules(null);
|
||||
initGson(LauncherEngine.modulesManager);
|
||||
//Launcher.modulesManager.preInitModules();
|
||||
if (!LauncherAgent.isStarted()) {
|
||||
NativeJVMHalt.haltA(100);
|
||||
return;
|
||||
}
|
||||
LauncherEngine.modulesManager.invokeEvent(new PreConfigPhase());
|
||||
JVMHelper.verifySystemProperties(ClientLauncher.class, true);
|
||||
EnvHelper.checkDangerousParams();
|
||||
|
@ -474,11 +504,12 @@ public static void main(String... args) throws Throwable {
|
|||
System.exit(-98);
|
||||
return;
|
||||
}
|
||||
ClientLaunchContext context = new ClientLaunchContext(params, profile, assetHDir, clientHDir);
|
||||
Launcher.profile = profile;
|
||||
playerProfile = params.pp;
|
||||
Request.setSession(params.session);
|
||||
checkJVMBitsAndVersion();
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherInitPhase());
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherInitPhase(context));
|
||||
// Verify ClientLauncher sign and classpath
|
||||
LogHelper.debug("Verifying ClientLauncher sign and classpath");
|
||||
LinkedList<Path> classPath = resolveClassPathList(params.clientDir, profile.getClassPath());
|
||||
|
@ -518,6 +549,11 @@ public static void main(String... args) throws Throwable {
|
|||
LogHelper.error(e);
|
||||
}
|
||||
};
|
||||
AuthService.username = params.pp.username;
|
||||
AuthService.uuid = params.pp.uuid;
|
||||
ClientService.instrumentation = LauncherAgent.inst;
|
||||
ClientService.classLoader = classLoader;
|
||||
ClientService.baseURLs = classpathurls;
|
||||
LogHelper.debug("Starting JVM and client WatchService");
|
||||
FileNameMatcher assetMatcher = profile.getAssetUpdateMatcher();
|
||||
FileNameMatcher clientMatcher = profile.getClientUpdateMatcher();
|
||||
|
@ -529,13 +565,16 @@ public static void main(String... args) throws Throwable {
|
|||
// if (params.updateOptional.contains(s)) s.mark = true;
|
||||
// else hdir.removeR(s.file);
|
||||
//}
|
||||
context.assetWatcher = assetWatcher;
|
||||
context.clientWatcher = clientWatcher;
|
||||
Launcher.profile.pushOptionalFile(clientHDir, false);
|
||||
LauncherEngine.modulesManager.invokeEvent(new PostInitPhase());
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientLauncherPostInitPhase(context));
|
||||
// Start WatchService, and only then client
|
||||
CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
|
||||
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
|
||||
verifyHDir(params.assetDir, assetHDir, assetMatcher, digest);
|
||||
verifyHDir(params.clientDir, clientHDir, clientMatcher, digest);
|
||||
LauncherEngine.modulesManager.invokeEvent(new ClientLaunchPhase(context));
|
||||
launch(profile, params);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||
|
@ -25,4 +26,14 @@ public void autoload(Path dir) throws IOException {
|
|||
public LauncherModule loadModule(Path file) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void callWrapper(ProcessBuilder processBuilder, Collection<String> jvmArgs)
|
||||
{
|
||||
for(LauncherModule module : modules)
|
||||
{
|
||||
if(module instanceof ClientWrapperModule)
|
||||
{
|
||||
((ClientWrapperModule) module).wrapperPhase(processBuilder, jvmArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package pro.gravit.launcher.client;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface ClientWrapperModule {
|
||||
void wrapperPhase(ProcessBuilder processBuilder, Collection<String> jvmArgs);
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import pro.gravit.launcher.LauncherAPI;
|
||||
import pro.gravit.launcher.api.AuthService;
|
||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||
import pro.gravit.launcher.guard.LauncherGuardManager;
|
||||
import pro.gravit.launcher.hasher.FileNameMatcher;
|
||||
|
@ -100,6 +101,12 @@ public static void setAuthParams(AuthRequestEvent event) {
|
|||
Request.setSession(event.session);
|
||||
}
|
||||
LauncherGuardManager.guard.setProtectToken(event.protectToken);
|
||||
AuthService.permissions = event.permissions;
|
||||
if(event.playerProfile != null)
|
||||
{
|
||||
AuthService.username = event.playerProfile.username;
|
||||
AuthService.uuid = event.playerProfile.uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
|
|
@ -76,6 +76,7 @@ public void postDiff(UpdateRequest request, UpdateRequestEvent e, HashedDir.Diff
|
|||
LogHelper.debug("Copy file %s to %s", ret.toAbsolutePath().toString(), source.toAbsolutePath().toString());
|
||||
}
|
||||
//Let's go!
|
||||
Files.deleteIfExists(source);
|
||||
Files.copy(ret, source);
|
||||
try (InputStream input = IOHelper.newInput(ret)) {
|
||||
IOHelper.transfer(input, source);
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.client.ClientLauncher;
|
||||
import pro.gravit.launcher.modules.LauncherModule;
|
||||
|
||||
public class ClientLaunchPhase extends LauncherModule.Event {
|
||||
public final ClientLauncher.ClientLaunchContext context;
|
||||
|
||||
public ClientLaunchPhase(ClientLauncher.ClientLaunchContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.client.ClientLauncher;
|
||||
import pro.gravit.launcher.modules.events.InitPhase;
|
||||
|
||||
public class ClientLauncherInitPhase extends InitPhase {
|
||||
public final ClientLauncher.ClientLaunchContext context;
|
||||
|
||||
public ClientLauncherInitPhase(ClientLauncher.ClientLaunchContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package pro.gravit.launcher.client.events;
|
||||
|
||||
import pro.gravit.launcher.client.ClientLauncher;
|
||||
import pro.gravit.launcher.modules.events.PostInitPhase;
|
||||
|
||||
public class ClientLauncherPostInitPhase extends PostInitPhase {
|
||||
public final ClientLauncher.ClientLaunchContext context;
|
||||
|
||||
public ClientLauncherPostInitPhase(ClientLauncher.ClientLaunchContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
}
|
|
@ -23,19 +23,15 @@ public class LauncherGravitGuard implements LauncherGuardInterface {
|
|||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "wrapper";
|
||||
return "gravitguard";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getJavaBinPath() {
|
||||
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) {
|
||||
String projectName = Launcher.getConfig().projectname;
|
||||
String wrapperUnpackName = JVMHelper.JVM_BITS == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe");
|
||||
return DirBridge.getGuardDir().resolve(wrapperUnpackName);
|
||||
} else if (ClientLauncher.getJavaBinPath() != null) {
|
||||
javaBinPath = ClientLauncher.getJavaBinPath();
|
||||
String projectName = Launcher.getConfig().projectname;
|
||||
String wrapperUnpackName = JVMHelper.JVM_BITS == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe");
|
||||
String wrapperUnpackName = ( javaBinPath == null ? JVMHelper.JVM_BITS : JVMHelper.OS_BITS ) == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe");
|
||||
return DirBridge.getGuardDir().resolve(wrapperUnpackName);
|
||||
} else
|
||||
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home")));
|
||||
|
@ -43,22 +39,26 @@ public Path getJavaBinPath() {
|
|||
|
||||
@Override
|
||||
public int getClientJVMBits() {
|
||||
return JVMHelper.JVM_BITS;
|
||||
//При использовании GravitGuard без своей джавы
|
||||
//Если при запуске лаунчера используется 32 бит джава, а ОС 64бит
|
||||
//То в окне настроек будет отображаться >1.5Гб доступной памяти
|
||||
//Однако при выставлении >1.5Гб JVM x32 работать откажеться
|
||||
return JVMHelper.OS_BITS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean clientInstance) {
|
||||
try {
|
||||
String wrapperName = JVMHelper.JVM_BITS == 64 ? "wrapper64.exe" : "wrapper32.exe";
|
||||
String projectName = Launcher.getConfig().projectname;
|
||||
String wrapperUnpackName = JVMHelper.JVM_BITS == 64 ? projectName.concat("64.exe") : projectName.concat("32.exe");
|
||||
String antiInjectName = JVMHelper.JVM_BITS == 64 ? "AntiInject64.dll" : "AntiInject32.dll";
|
||||
UnpackHelper.unpack(Launcher.getResourceURL(wrapperName, "guard"), DirBridge.getGuardDir().resolve(wrapperUnpackName));
|
||||
UnpackHelper.unpack(Launcher.getResourceURL(antiInjectName, "guard"), DirBridge.getGuardDir().resolve(antiInjectName));
|
||||
UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("64.exe")));
|
||||
UnpackHelper.unpack(Launcher.getResourceURL("AntiInject64.dll", "guard"), DirBridge.getGuardDir().resolve("AntiInject64.dll"));
|
||||
|
||||
UnpackHelper.unpack(Launcher.getResourceURL("wrapper32.exe", "guard"), DirBridge.getGuardDir().resolve(projectName.concat("32.exe")));
|
||||
UnpackHelper.unpack(Launcher.getResourceURL("AntiInject32.dll", "guard"), DirBridge.getGuardDir().resolve("AntiInject32.dll"));
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
if (clientInstance) GravitGuardBridge.callGuard();
|
||||
if (clientInstance && JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE) GravitGuardBridge.callGuard();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package pro.gravit.launcher.managers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
@ -102,9 +101,4 @@ public void loadHDirStore() throws IOException {
|
|||
public void saveHDirStore() throws IOException {
|
||||
saveHDirStore(DirBridge.dirProjectStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Type type) {
|
||||
super.setType(type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
package pro.gravit.launcher.config;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherAPI;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public abstract class JsonConfigurable<T> {
|
||||
private Type type;
|
||||
protected Path configPath;
|
||||
|
||||
@LauncherAPI
|
||||
public void saveConfig() throws IOException {
|
||||
saveConfig(configPath);
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public void loadConfig() throws IOException {
|
||||
loadConfig(configPath);
|
||||
}
|
||||
public abstract class JsonConfigurable<T> implements JsonConfigurableInterface<T> {
|
||||
private transient final Type type;
|
||||
protected transient final Path configPath;
|
||||
|
||||
@LauncherAPI
|
||||
public JsonConfigurable(Type type, Path configPath) {
|
||||
|
@ -31,55 +15,14 @@ public JsonConfigurable(Type type, Path configPath) {
|
|||
this.configPath = configPath;
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public void saveConfig(Path configPath) throws IOException {
|
||||
try (BufferedWriter writer = IOHelper.newWriter(configPath)) {
|
||||
Launcher.gsonManager.configGson.toJson(getConfig(), type, writer);
|
||||
}
|
||||
@Override
|
||||
public Path getPath() {
|
||||
return configPath;
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public void loadConfig(Path configPath) throws IOException {
|
||||
if (generateConfigIfNotExists(configPath)) return;
|
||||
try (BufferedReader reader = IOHelper.newReader(configPath)) {
|
||||
setConfig(Launcher.gsonManager.configGson.fromJson(reader, type));
|
||||
} catch (Exception e)
|
||||
{
|
||||
LogHelper.error(e);
|
||||
resetConfig(configPath);
|
||||
}
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public void resetConfig() throws IOException {
|
||||
setConfig(getDefaultConfig());
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public void resetConfig(Path newPath) throws IOException {
|
||||
setConfig(getDefaultConfig());
|
||||
saveConfig(newPath);
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public boolean generateConfigIfNotExists(Path path) throws IOException {
|
||||
if (IOHelper.isFile(path))
|
||||
return false;
|
||||
resetConfig(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public boolean generateConfigIfNotExists() throws IOException {
|
||||
if (IOHelper.isFile(configPath))
|
||||
return false;
|
||||
resetConfig();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void setType(Type type) {
|
||||
this.type = type;
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
package pro.gravit.launcher.config;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import pro.gravit.launcher.Launcher;
|
||||
import pro.gravit.launcher.LauncherAPI;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface JsonConfigurableInterface<T> {
|
||||
@LauncherAPI
|
||||
default void saveConfig() throws IOException {
|
||||
saveConfig(getPath());
|
||||
}
|
||||
@LauncherAPI
|
||||
default void loadConfig() throws IOException {
|
||||
loadConfig(getPath());
|
||||
}
|
||||
@LauncherAPI
|
||||
default void saveConfig(Gson gson, Path configPath) throws IOException {
|
||||
try (BufferedWriter writer = IOHelper.newWriter(configPath)) {
|
||||
gson.toJson(getConfig(), getType(), writer);
|
||||
}
|
||||
}
|
||||
@LauncherAPI
|
||||
default void loadConfig(Gson gson, Path configPath) throws IOException {
|
||||
if (generateConfigIfNotExists(configPath)) return;
|
||||
try (BufferedReader reader = IOHelper.newReader(configPath)) {
|
||||
setConfig(gson.fromJson(reader, getType()));
|
||||
} catch (Exception e)
|
||||
{
|
||||
LogHelper.error(e);
|
||||
resetConfig(configPath);
|
||||
}
|
||||
}
|
||||
@LauncherAPI
|
||||
default void saveConfig(Path configPath) throws IOException {
|
||||
saveConfig(Launcher.gsonManager.configGson, configPath);
|
||||
}
|
||||
@LauncherAPI
|
||||
default void loadConfig(Path configPath) throws IOException {
|
||||
loadConfig(Launcher.gsonManager.configGson, configPath);
|
||||
}
|
||||
@LauncherAPI
|
||||
default void resetConfig() throws IOException {
|
||||
setConfig(getDefaultConfig());
|
||||
saveConfig();
|
||||
}
|
||||
@LauncherAPI
|
||||
default void resetConfig(Path newPath) throws IOException {
|
||||
setConfig(getDefaultConfig());
|
||||
saveConfig(newPath);
|
||||
}
|
||||
@LauncherAPI
|
||||
default boolean generateConfigIfNotExists(Path path) throws IOException {
|
||||
if (IOHelper.isFile(path))
|
||||
return false;
|
||||
resetConfig(path);
|
||||
return true;
|
||||
}
|
||||
@LauncherAPI
|
||||
default boolean generateConfigIfNotExists() throws IOException {
|
||||
if (IOHelper.isFile(getPath()))
|
||||
return false;
|
||||
resetConfig();
|
||||
return true;
|
||||
}
|
||||
@LauncherAPI
|
||||
T getConfig();
|
||||
@LauncherAPI
|
||||
T getDefaultConfig();
|
||||
@LauncherAPI
|
||||
void setConfig(T config);
|
||||
@LauncherAPI
|
||||
Path getPath();
|
||||
|
||||
Type getType();
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package pro.gravit.launcher.config;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public abstract class SimpleConfig<T> implements JsonConfigurableInterface<T> {
|
||||
private transient final Class<T> type;
|
||||
protected transient final Path configPath;
|
||||
|
||||
protected SimpleConfig(Class<T> type, Path configPath) {
|
||||
this.type = type;
|
||||
this.configPath = configPath;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T getConfig() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getDefaultConfig() {
|
||||
try {
|
||||
return type.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getPath() {
|
||||
return configPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package pro.gravit.launcher.config;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class SimpleConfigurable<T> extends JsonConfigurable<T> {
|
||||
public T config;
|
||||
private final Class<T> tClass;
|
||||
|
||||
public SimpleConfigurable(Class<T> type, Path configPath) {
|
||||
super(type, configPath);
|
||||
tClass = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getDefaultConfig() {
|
||||
try {
|
||||
return tClass.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConfig(T config) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import pro.gravit.launcher.config.SimpleConfigurable;
|
||||
import pro.gravit.launcher.modules.ModulesConfigManager;
|
||||
import pro.gravit.utils.helper.IOHelper;
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
@ -34,4 +35,9 @@ public Path getModuleConfigDir(String moduleName) {
|
|||
}
|
||||
return configDir.resolve(moduleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> SimpleConfigurable<T> getConfigurable(Class<T> tClass, Path configPath) {
|
||||
return new SimpleConfigurable<>(tClass, configPath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package pro.gravit.launcher.modules;
|
||||
|
||||
import pro.gravit.launcher.config.SimpleConfigurable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface ModulesConfigManager {
|
||||
|
@ -8,4 +10,16 @@ public interface ModulesConfigManager {
|
|||
Path getModuleConfig(String moduleName, String configName);
|
||||
|
||||
Path getModuleConfigDir(String moduleName);
|
||||
|
||||
<T> SimpleConfigurable<T> getConfigurable(Class<T> tClass, Path configPath);
|
||||
|
||||
default <T> SimpleConfigurable<T> getConfigurable(Class<T> tClass, String moduleName)
|
||||
{
|
||||
return getConfigurable(tClass, getModuleConfig(moduleName));
|
||||
}
|
||||
|
||||
default <T> SimpleConfigurable<T> getConfigurable(Class<T> tClass, String moduleName, String configName)
|
||||
{
|
||||
return getConfigurable(tClass, getModuleConfig(moduleName, configName));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package pro.gravit.launcher.request.update;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -25,6 +27,9 @@ public final class LauncherRequest extends Request<LauncherRequestEvent> impleme
|
|||
public int launcher_type = EXE_BINARY ? 2 : 1;
|
||||
@LauncherAPI
|
||||
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");
|
||||
|
||||
@LauncherAPI
|
||||
public static final boolean EXE_BINARY = IOHelper.hasExtension(BINARY_PATH, "exe");
|
||||
|
@ -52,7 +57,12 @@ public static void update(LauncherRequestEvent result) throws IOException {
|
|||
}*/
|
||||
try {
|
||||
ListDownloader downloader = new ListDownloader();
|
||||
downloader.downloadOne(result.url, BINARY_PATH);
|
||||
Files.deleteIfExists(C_BINARY_PATH);
|
||||
downloader.downloadOne(result.url, C_BINARY_PATH);
|
||||
try (InputStream in = IOHelper.newInput(C_BINARY_PATH)) {
|
||||
IOHelper.transfer(in, BINARY_PATH);
|
||||
}
|
||||
Files.deleteIfExists(C_BINARY_PATH);
|
||||
} catch (Throwable e) {
|
||||
LogHelper.error(e);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
public final class MinecraftProfileTexture {
|
||||
public class MinecraftProfileTexture {
|
||||
public enum Type {
|
||||
SKIN,
|
||||
CAPE,
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
// Used to bypass Launcher's class name obfuscation and access API
|
||||
@LauncherAPI
|
||||
public final class CompatBridge {
|
||||
public class CompatBridge {
|
||||
public static final int PROFILES_MAX_BATCH_SIZE = SerializeLimits.MAX_BATCH_SIZE;
|
||||
|
||||
public static CompatProfile checkServer(String username, String serverID) throws Exception {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
@LauncherAPI
|
||||
public final class CompatProfile {
|
||||
public class CompatProfile {
|
||||
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 CLOAK_URL_PROPERTY = Launcher.CLOAK_URL_PROPERTY;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
// Used by 1.6.4 and below versions
|
||||
@LauncherAPI
|
||||
public final class LegacyBridge {
|
||||
public class LegacyBridge {
|
||||
public static boolean checkServer(String username, String serverID) throws Exception {
|
||||
LogHelper.debug("LegacyBridge.checkServer, Username: '%s', Server ID: %s", username, serverID);
|
||||
return new CheckServerRequest(username, serverID).request() != null;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import pro.gravit.utils.helper.LogHelper;
|
||||
|
||||
public final class YggdrasilAuthenticationService implements AuthenticationService {
|
||||
public class YggdrasilAuthenticationService implements AuthenticationService {
|
||||
public YggdrasilAuthenticationService(Proxy proxy, String clientToken) {
|
||||
LogHelper.debug("Patched AuthenticationService created: '%s'", clientToken);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.VerifyHelper;
|
||||
|
||||
public final class YggdrasilGameProfileRepository implements GameProfileRepository {
|
||||
public class YggdrasilGameProfileRepository implements GameProfileRepository {
|
||||
private static final long BUSY_WAIT_MS = VerifyHelper.verifyLong(
|
||||
Long.parseLong(System.getProperty("launcher.com.mojang.authlib.busyWait", Long.toString(100L))),
|
||||
VerifyHelper.L_NOT_NEGATIVE, "launcher.com.mojang.authlib.busyWait can't be < 0");
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
import pro.gravit.utils.helper.LogHelper;
|
||||
import pro.gravit.utils.helper.SecurityHelper;
|
||||
|
||||
public final class YggdrasilMinecraftSessionService extends BaseMinecraftSessionService {
|
||||
public class YggdrasilMinecraftSessionService extends BaseMinecraftSessionService {
|
||||
public static final JsonParser JSON_PARSER = new JsonParser();
|
||||
public static final boolean NO_TEXTURES = Boolean.parseBoolean("launcher.com.mojang.authlib.noTextures");
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ public final class Version {
|
|||
public final Type release;
|
||||
public static final int MAJOR = 5;
|
||||
public static final int MINOR = 0;
|
||||
public static final int PATCH = 8;
|
||||
public static final int PATCH = 9;
|
||||
public static final int BUILD = 1;
|
||||
public static final Version.Type RELEASE = Type.STABLE;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
id 'signing'
|
||||
}
|
||||
group = 'pro.gravit.launcher'
|
||||
version = '5.0.8'
|
||||
version = '5.0.9'
|
||||
|
||||
configure(subprojects.findAll { it.name != 'modules' }) {
|
||||
apply plugin: 'idea'
|
||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
|||
Subproject commit 88bd03c38a2681e997a305e376eb63e446c99a7f
|
||||
Subproject commit 8d7a95d0707539ab18fba83bef6ef9f09b70c0ad
|
Loading…
Reference in a new issue