mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-11-15 11:39:11 +03:00
Merge branch 'release/v4.3.0'
This commit is contained in:
commit
e85b674f38
26 changed files with 478 additions and 241 deletions
|
@ -44,8 +44,9 @@ pack project(':libLauncher')
|
||||||
bundle 'org.fusesource.jansi:jansi:1.17.1'
|
bundle 'org.fusesource.jansi:jansi:1.17.1'
|
||||||
bundle 'commons-io:commons-io:2.6'
|
bundle 'commons-io:commons-io:2.6'
|
||||||
bundle 'commons-codec:commons-codec:1.11'
|
bundle 'commons-codec:commons-codec:1.11'
|
||||||
bundle 'org.javassist:javassist:3.23.1-GA'
|
bundle 'org.javassist:javassist:3.24.1-GA'
|
||||||
bundle 'io.netty:netty-all:4.1.32.Final'
|
bundle 'io.netty:netty-all:4.1.32.Final'
|
||||||
|
bundle 'org.kohsuke:github-api:1.95'
|
||||||
|
|
||||||
bundle 'org.slf4j:slf4j-simple:1.7.25'
|
bundle 'org.slf4j:slf4j-simple:1.7.25'
|
||||||
bundle 'org.slf4j:slf4j-api:1.7.25'
|
bundle 'org.slf4j:slf4j-api:1.7.25'
|
||||||
|
|
|
@ -111,6 +111,7 @@ public static final class Config {
|
||||||
|
|
||||||
public String startScript;
|
public String startScript;
|
||||||
|
|
||||||
|
public boolean updatesNotify = true; // Defaultly to true
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return address;
|
return address;
|
||||||
|
@ -289,6 +290,8 @@ public static void main(String... args) throws Throwable {
|
||||||
|
|
||||||
public volatile Map<String, SignedObjectHolder<HashedDir>> updatesDirMap;
|
public volatile Map<String, SignedObjectHolder<HashedDir>> updatesDirMap;
|
||||||
|
|
||||||
|
public final Updater updater;
|
||||||
|
|
||||||
public static Gson gson;
|
public static Gson gson;
|
||||||
public static GsonBuilder gsonBuilder;
|
public static GsonBuilder gsonBuilder;
|
||||||
|
|
||||||
|
@ -342,8 +345,8 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
|
||||||
publicKey = (RSAPublicKey) pair.getPublic();
|
publicKey = (RSAPublicKey) pair.getPublic();
|
||||||
privateKey = (RSAPrivateKey) pair.getPrivate();
|
privateKey = (RSAPrivateKey) pair.getPrivate();
|
||||||
|
|
||||||
// Write key pair files
|
// Write key pair list
|
||||||
LogHelper.info("Writing RSA keypair files");
|
LogHelper.info("Writing RSA keypair list");
|
||||||
IOHelper.write(publicKeyFile, publicKey.getEncoded());
|
IOHelper.write(publicKeyFile, publicKey.getEncoded());
|
||||||
IOHelper.write(privateKeyFile, privateKey.getEncoded());
|
IOHelper.write(privateKeyFile, privateKey.getEncoded());
|
||||||
}
|
}
|
||||||
|
@ -439,6 +442,8 @@ public LaunchServer(Path dir, String[] args) throws IOException, InvalidKeySpecE
|
||||||
|
|
||||||
// post init modules
|
// post init modules
|
||||||
modulesManager.postInitModules();
|
modulesManager.postInitModules();
|
||||||
|
// start updater
|
||||||
|
this.updater = new Updater(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initGson() {
|
public static void initGson() {
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package ru.gravit.launchserver;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.kohsuke.github.GHRelease;
|
||||||
|
import org.kohsuke.github.GHRepository;
|
||||||
|
import org.kohsuke.github.GitHub;
|
||||||
|
|
||||||
|
import ru.gravit.launcher.Launcher;
|
||||||
|
import ru.gravit.utils.Version;
|
||||||
|
import ru.gravit.utils.Version.Type;
|
||||||
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
public class Updater extends TimerTask {
|
||||||
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss", Locale.US);
|
||||||
|
private static final long period = 1000*3600;
|
||||||
|
private static final Version VERSION = Launcher.getVersion();
|
||||||
|
private final Timer taskPool;
|
||||||
|
private final GHRepository gravitLauncher;
|
||||||
|
private Version parent = VERSION;
|
||||||
|
|
||||||
|
public Updater(LaunchServer srv) {
|
||||||
|
this.taskPool = new Timer("Updater thread", true);
|
||||||
|
|
||||||
|
GHRepository gravitLauncherTmp = null;
|
||||||
|
try {
|
||||||
|
gravitLauncherTmp = GitHub.connectAnonymously().getOrganization("GravitLauncher").getRepository("Launcher");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
this.gravitLauncher = gravitLauncherTmp;
|
||||||
|
run();
|
||||||
|
if (srv.config.updatesNotify) taskPool.schedule(this, new Date(System.currentTimeMillis()+period), period);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
GHRelease rel = gravitLauncher.getLatestRelease();
|
||||||
|
Version relV = parseVer(rel.getTagName());
|
||||||
|
if (relV == null) {
|
||||||
|
LogHelper.debug("Updater: parsing version error.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!parent.equals(relV)) parent = relV;
|
||||||
|
if (VERSION.major >= relV.major && VERSION.minor >= relV.minor
|
||||||
|
&& VERSION.patch >= relV.patch && VERSION.build >= relV.build) return;
|
||||||
|
if (relV.release.equals(Type.STABLE) || relV.release.equals(Type.LTS)) {
|
||||||
|
LogHelper.warning("New %s release: %s", relV.getReleaseStatus(), relV.getVersionString());
|
||||||
|
LogHelper.warning("You can download it: " + rel.getHtmlUrl().toString());
|
||||||
|
LogHelper.warning("It`s published at: " + DATE_TIME_FORMATTER.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(rel.getPublished_at().getTime()), ZoneId.systemDefault())));
|
||||||
|
} else {
|
||||||
|
LogHelper.debug("New %s release: %s", relV.getReleaseStatus(), relV.getVersionString());
|
||||||
|
LogHelper.debug("You can download it: " + rel.getHtmlUrl());
|
||||||
|
LogHelper.debug("It`s published at: " + DATE_TIME_FORMATTER.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(rel.getPublished_at().getTime()), ZoneId.systemDefault())));
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Pattern startingVerPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+");
|
||||||
|
private static final Pattern pointPatternSpltitter = Pattern.compile("\\.");
|
||||||
|
|
||||||
|
private static Version parseVer(String relS) {
|
||||||
|
Matcher verMatcher = startingVerPattern.matcher(relS);
|
||||||
|
if (!verMatcher.find()) return VERSION;
|
||||||
|
String[] ver = pointPatternSpltitter.split(relS.substring(verMatcher.start(), verMatcher.end()));
|
||||||
|
if (ver.length < 3) return VERSION;
|
||||||
|
return new Version(Integer.parseInt(ver[0]), Integer.parseInt(ver[1]),
|
||||||
|
Integer.parseInt(ver[2]), ver.length > 3 ? Integer.parseInt(ver[3]) : 0, findRelType(relS.substring(verMatcher.end()+1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Type findRelType(String substring) {
|
||||||
|
if (substring.length() < 3 || substring.isEmpty()) return Type.UNKNOWN;
|
||||||
|
String tS = substring;
|
||||||
|
if (tS.startsWith("-")) tS = tS.substring(1);
|
||||||
|
final String wrk = tS.toLowerCase(Locale.ENGLISH);
|
||||||
|
final AtomicReference<Type> t = new AtomicReference<Type>(Type.UNKNOWN);
|
||||||
|
Type.unModTypes.forEach((s, type) -> {
|
||||||
|
if (wrk.startsWith(s)) t.set(type);
|
||||||
|
});
|
||||||
|
return t.get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package ru.gravit.launchserver.auth.permissions;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import ru.gravit.launcher.ClientPermissions;
|
||||||
|
import ru.gravit.launcher.Launcher;
|
||||||
|
import ru.gravit.launchserver.Reloadable;
|
||||||
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class JsonLongFilePermissionsHandler extends PermissionsHandler implements Reloadable {
|
||||||
|
public String filename = "permissions.json";
|
||||||
|
public long defaultPerms = 0L;
|
||||||
|
public static Map<String, Long> map;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
map.clear();
|
||||||
|
Path path = Paths.get(filename);
|
||||||
|
Type type = new TypeToken<Map<String, Long>>() {
|
||||||
|
}.getType();
|
||||||
|
try (Reader reader = IOHelper.newReader(path)) {
|
||||||
|
map = Launcher.gson.fromJson(reader, type);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Enity {
|
||||||
|
public String username;
|
||||||
|
public ClientPermissions permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ClientPermissions getPermissions(String username) {
|
||||||
|
return new ClientPermissions(map.getOrDefault(username, defaultPerms));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonLongFilePermissionsHandler() {
|
||||||
|
Type type = new TypeToken<Map<String, ClientPermissions>>() {
|
||||||
|
}.getType();
|
||||||
|
Path path = Paths.get(filename);
|
||||||
|
if (!IOHelper.exists(path)) {
|
||||||
|
map = new HashMap<>();
|
||||||
|
try (Writer writer = IOHelper.newWriter(path)) {
|
||||||
|
Launcher.gson.toJson(map, writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try (Reader reader = IOHelper.newReader(path)) {
|
||||||
|
map = Launcher.gson.fromJson(reader, type);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ public static String getHandlerName(Class<? extends PermissionsHandler> clazz) {
|
||||||
public static void registerHandlers() {
|
public static void registerHandlers() {
|
||||||
if (!registredHandl) {
|
if (!registredHandl) {
|
||||||
registerHandler("json", JsonFilePermissionsHandler.class);
|
registerHandler("json", JsonFilePermissionsHandler.class);
|
||||||
|
registerHandler("json-long", JsonLongFilePermissionsHandler.class);
|
||||||
registerHandler("config", ConfigPermissionsHandler.class);
|
registerHandler("config", ConfigPermissionsHandler.class);
|
||||||
registerHandler("default", DefaultPermissionsHandler.class);
|
registerHandler("default", DefaultPermissionsHandler.class);
|
||||||
registredHandl = true;
|
registredHandl = true;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ru.gravit.launchserver.auth.provider;
|
package ru.gravit.launchserver.auth.provider;
|
||||||
|
|
||||||
import ru.gravit.launcher.ClientPermissions;
|
import ru.gravit.launcher.ClientPermissions;
|
||||||
|
import ru.gravit.launchserver.LaunchServer;
|
||||||
import ru.gravit.launchserver.auth.AuthException;
|
import ru.gravit.launchserver.auth.AuthException;
|
||||||
import ru.gravit.launchserver.auth.MySQLSourceConfig;
|
import ru.gravit.launchserver.auth.MySQLSourceConfig;
|
||||||
import ru.gravit.utils.helper.CommonHelper;
|
import ru.gravit.utils.helper.CommonHelper;
|
||||||
|
@ -35,7 +36,7 @@ public AuthProviderResult auth(String login, String password, String ip) throws
|
||||||
// Execute SQL query
|
// Execute SQL query
|
||||||
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
s.setQueryTimeout(MySQLSourceConfig.TIMEOUT);
|
||||||
try (ResultSet set = s.executeQuery()) {
|
try (ResultSet set = s.executeQuery()) {
|
||||||
return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(set.getLong(2)) : new ClientPermissions()) : authError(message);
|
return set.next() ? new AuthProviderResult(set.getString(1), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(set.getLong(2)) : LaunchServer.server.config.permissionsHandler.getPermissions(set.getString(1))) : authError(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package ru.gravit.launchserver.auth.provider;
|
package ru.gravit.launchserver.auth.provider;
|
||||||
|
|
||||||
import ru.gravit.launcher.ClientPermissions;
|
import ru.gravit.launcher.ClientPermissions;
|
||||||
|
import ru.gravit.launchserver.LaunchServer;
|
||||||
import ru.gravit.utils.helper.CommonHelper;
|
import ru.gravit.utils.helper.CommonHelper;
|
||||||
import ru.gravit.utils.helper.IOHelper;
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
import ru.gravit.utils.helper.LogHelper;
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
|
@ -31,7 +32,7 @@ public AuthProviderResult auth(String login, String password, String ip) throws
|
||||||
// Match username
|
// Match username
|
||||||
Matcher matcher = pattern.matcher(currentResponse);
|
Matcher matcher = pattern.matcher(currentResponse);
|
||||||
return matcher.matches() && matcher.groupCount() >= 1 ?
|
return matcher.matches() && matcher.groupCount() >= 1 ?
|
||||||
new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(Long.getLong(matcher.group("permission"))) : new ClientPermissions()) :
|
new AuthProviderResult(matcher.group("username"), SecurityHelper.randomStringToken(), usePermission ? new ClientPermissions(Long.getLong(matcher.group("permission"))) : LaunchServer.server.config.permissionsHandler.getPermissions(login)) :
|
||||||
authError(currentResponse);
|
authError(currentResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ public boolean allowDelete() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tryUnpack() throws IOException {
|
public void tryUnpack() throws IOException {
|
||||||
LogHelper.info("Unpacking launcher native guard files and runtime");
|
LogHelper.info("Unpacking launcher native guard list and runtime");
|
||||||
UnpackHelper.unpackZipNoCheck("guard.zip", server.launcherBinary.guardDir);
|
UnpackHelper.unpackZipNoCheck("guard.zip", server.launcherBinary.guardDir);
|
||||||
UnpackHelper.unpackZipNoCheck("runtime.zip", server.launcherBinary.runtimeDir);
|
UnpackHelper.unpackZipNoCheck("runtime.zip", server.launcherBinary.runtimeDir);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"isDownloadJava": false,
|
"isDownloadJava": false,
|
||||||
"isWarningMissArchJava": true,
|
"isWarningMissArchJava": true,
|
||||||
"enabledProGuard": true,
|
"enabledProGuard": true,
|
||||||
|
"updatesNotify": true,
|
||||||
"stripLineNumbers": true,
|
"stripLineNumbers": true,
|
||||||
"deleteTempFiles": true,
|
"deleteTempFiles": true,
|
||||||
"startScript": ".\\start.sh"
|
"startScript": ".\\start.sh"
|
||||||
|
|
|
@ -43,15 +43,16 @@ var options = {
|
||||||
for(var j = 0; j < listSize; j++)
|
for(var j = 0; j < listSize; j++)
|
||||||
{
|
{
|
||||||
var mark = input.readBoolean();
|
var mark = input.readBoolean();
|
||||||
|
var modType = OptionalFile.readType(input);
|
||||||
var modFile = input.readString(0);
|
var modFile = input.readString(0);
|
||||||
if(mark)
|
if(mark)
|
||||||
{
|
{
|
||||||
profile.markOptional(modFile);
|
profile.markOptional(modFile,modType);
|
||||||
LogHelper.debug("Load options %s marked",modFile);
|
LogHelper.debug("Load options %s marked",modFile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
profile.unmarkOptional(modFile);
|
profile.unmarkOptional(modFile,modType);
|
||||||
LogHelper.debug("Load options %s unmarked",modFile);
|
LogHelper.debug("Load options %s unmarked",modFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,8 @@ var options = {
|
||||||
output.writeInt(profile.getSortIndex());
|
output.writeInt(profile.getSortIndex());
|
||||||
list.forEach(function(modFile,j,arr2) {
|
list.forEach(function(modFile,j,arr2) {
|
||||||
output.writeBoolean(modFile.mark);
|
output.writeBoolean(modFile.mark);
|
||||||
output.writeString(modFile.file, 0);
|
modFile.writeType(output);
|
||||||
|
output.writeString(modFile.name, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -96,16 +98,19 @@ var options = {
|
||||||
var profile = profilesList[serverHolder.old];
|
var profile = profilesList[serverHolder.old];
|
||||||
var list = profile.getOptional();
|
var list = profile.getOptional();
|
||||||
var checkBoxList = new java.util.ArrayList;
|
var checkBoxList = new java.util.ArrayList;
|
||||||
var dModsIds = [];
|
|
||||||
|
|
||||||
list.forEach(function(modFile) {
|
list.forEach(function(modFile) {
|
||||||
dModsIds.push(modFile.string);
|
var modName = modFile.name, modDescription = "", subLevel = 1;
|
||||||
|
if(!modFile.isVisible)
|
||||||
var modName = modFile.file, modDescription = "", subLevel = 1;
|
{
|
||||||
if(modFile.isAdminOnly && !loginData.permissions.canAdmin)
|
LogHelper.debug("optionalMod %s hidden",modFile.name);
|
||||||
return;
|
return;
|
||||||
if(modFile.name != null)//Есть ли у модификации имя?
|
}
|
||||||
modName = modFile.name;
|
|
||||||
|
if(modFile.permissions != 0 && ((loginData.permissions.toLong() & modFile.permissions) != 0))
|
||||||
|
{
|
||||||
|
LogHelper.debug("optionalMod %s permissions deny",modFile.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(modFile.info != null) //Есть ли описание?
|
if(modFile.info != null) //Есть ли описание?
|
||||||
modDescription = modFile.info;
|
modDescription = modFile.info;
|
||||||
if(modFile.subTreeLevel != null && modFile.subTreeLevel > 1)//Это суб-модификация?
|
if(modFile.subTreeLevel != null && modFile.subTreeLevel > 1)//Это суб-модификация?
|
||||||
|
@ -121,18 +126,17 @@ var options = {
|
||||||
var isSelected = event.getSource().isSelected();
|
var isSelected = event.getSource().isSelected();
|
||||||
if(isSelected)
|
if(isSelected)
|
||||||
{
|
{
|
||||||
profile.markOptional(modFile.file);
|
profile.markOptional(modFile);
|
||||||
LogHelper.debug("Selected mod %s", modFile.file);
|
LogHelper.debug("Selected mod %s", modFile.name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
profile.unmarkOptional(modFile.file);
|
profile.unmarkOptional(modFile);
|
||||||
LogHelper.debug("Unselected mod %s", modFile.file);
|
LogHelper.debug("Unselected mod %s", modFile.name);
|
||||||
}
|
}
|
||||||
options.update();
|
options.update();
|
||||||
});
|
});
|
||||||
checkBoxList.add(testMod);
|
checkBoxList.add(testMod);
|
||||||
|
|
||||||
if(modDescription != "") { //Добавляем описание?
|
if(modDescription != "") { //Добавляем описание?
|
||||||
textDescr = new javafx.scene.text.Text(modDescription);
|
textDescr = new javafx.scene.text.Text(modDescription);
|
||||||
if(subLevel > 1) {
|
if(subLevel > 1) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ var StreamObjectAdapter = StreamObjectAdapterClass.static;
|
||||||
var SignedBytesHolder = SignedBytesHolderClass.static;
|
var SignedBytesHolder = SignedBytesHolderClass.static;
|
||||||
var SignedObjectHolder = SignedObjectHolderClass.static;
|
var SignedObjectHolder = SignedObjectHolderClass.static;
|
||||||
var EnumSerializer = EnumSerializerClass.static;
|
var EnumSerializer = EnumSerializerClass.static;
|
||||||
|
var OptionalFile = OptionalFileClass.static;
|
||||||
|
|
||||||
// Helper class API imports
|
// Helper class API imports
|
||||||
var CommonHelper = CommonHelperClass.static;
|
var CommonHelper = CommonHelperClass.static;
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.nio.file.SimpleFileVisitor;
|
import java.nio.file.SimpleFileVisitor;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.nio.file.attribute.PosixFilePermission;
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
|
@ -68,12 +67,6 @@ public static final class Params extends StreamObject {
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public final PlayerProfile pp;
|
public final PlayerProfile pp;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public final Set<ClientProfile.OptionalFile> updateOptional;
|
|
||||||
@LauncherAPI
|
|
||||||
public final Set<ClientProfile.OptionalArgs> optionalClientArgs;
|
|
||||||
@LauncherAPI
|
|
||||||
public final Set<ClientProfile.OptionalArgs> optionalClassPath;
|
|
||||||
@LauncherAPI
|
|
||||||
public final String accessToken;
|
public final String accessToken;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public final boolean autoEnter;
|
public final boolean autoEnter;
|
||||||
|
@ -93,18 +86,6 @@ public static final class Params extends StreamObject {
|
||||||
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) {
|
||||||
this.launcherDigest = launcherDigest.clone();
|
this.launcherDigest = launcherDigest.clone();
|
||||||
this.updateOptional = new HashSet<>();
|
|
||||||
this.optionalClientArgs = new HashSet<>();
|
|
||||||
this.optionalClassPath = new HashSet<>();
|
|
||||||
for (ClientProfile.OptionalFile s : Launcher.profile.getOptional()) {
|
|
||||||
if (s.mark) updateOptional.add(s);
|
|
||||||
}
|
|
||||||
for (ClientProfile.OptionalArgs s : Launcher.profile.getOptionalClientArgs()) {
|
|
||||||
if (s.mark) optionalClientArgs.add(s);
|
|
||||||
}
|
|
||||||
for (ClientProfile.OptionalArgs s : Launcher.profile.getOptionalClassPath()) {
|
|
||||||
if (s.mark) optionalClassPath.add(s);
|
|
||||||
}
|
|
||||||
// Client paths
|
// Client paths
|
||||||
this.assetDir = assetDir;
|
this.assetDir = assetDir;
|
||||||
this.clientDir = clientDir;
|
this.clientDir = clientDir;
|
||||||
|
@ -126,31 +107,6 @@ public Params(HInput input) throws Exception {
|
||||||
// Client paths
|
// Client paths
|
||||||
assetDir = IOHelper.toPath(input.readString(0));
|
assetDir = IOHelper.toPath(input.readString(0));
|
||||||
clientDir = IOHelper.toPath(input.readString(0));
|
clientDir = IOHelper.toPath(input.readString(0));
|
||||||
updateOptional = new HashSet<>();
|
|
||||||
optionalClientArgs = new HashSet<>();
|
|
||||||
optionalClassPath = new HashSet<>();
|
|
||||||
int len = input.readLength(128);
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
String file = input.readString(512);
|
|
||||||
boolean mark = input.readBoolean();
|
|
||||||
updateOptional.add(new ClientProfile.OptionalFile(file, mark));
|
|
||||||
}
|
|
||||||
len = input.readLength(256);
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
int len2 = input.readLength(16);
|
|
||||||
boolean mark = input.readBoolean();
|
|
||||||
String[] optArgs = new String[len];
|
|
||||||
for (int j = 0; j < len2; ++j) optArgs[j] = input.readString(512);
|
|
||||||
optionalClientArgs.add(new ClientProfile.OptionalArgs(optArgs, mark));
|
|
||||||
}
|
|
||||||
len = input.readLength(256);
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
int len2 = input.readLength(16);
|
|
||||||
boolean mark = input.readBoolean();
|
|
||||||
String[] optArgs = new String[len];
|
|
||||||
for (int j = 0; j < len2; ++j) optArgs[j] = input.readString(512);
|
|
||||||
optionalClassPath.add(new ClientProfile.OptionalArgs(optArgs, mark));
|
|
||||||
}
|
|
||||||
// Client params
|
// Client params
|
||||||
pp = new PlayerProfile(input);
|
pp = new PlayerProfile(input);
|
||||||
byte[] encryptedAccessToken = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
|
byte[] encryptedAccessToken = input.readByteArray(SecurityHelper.CRYPTO_MAX_LENGTH);
|
||||||
|
@ -170,24 +126,6 @@ public void write(HOutput output) throws IOException {
|
||||||
// Client paths
|
// Client paths
|
||||||
output.writeString(assetDir.toString(), 0);
|
output.writeString(assetDir.toString(), 0);
|
||||||
output.writeString(clientDir.toString(), 0);
|
output.writeString(clientDir.toString(), 0);
|
||||||
output.writeLength(updateOptional.size(), 128);
|
|
||||||
for (ClientProfile.OptionalFile s : updateOptional) {
|
|
||||||
output.writeString(s.file, 512);
|
|
||||||
output.writeBoolean(s.mark);
|
|
||||||
}
|
|
||||||
output.writeLength(optionalClientArgs.size(), 256);
|
|
||||||
for (ClientProfile.OptionalArgs s : optionalClientArgs) {
|
|
||||||
output.writeLength(s.args.length, 16);
|
|
||||||
output.writeBoolean(s.mark);
|
|
||||||
for (String f : s.args) output.writeString(f, 512);
|
|
||||||
}
|
|
||||||
output.writeLength(optionalClassPath.size(), 256);
|
|
||||||
for (ClientProfile.OptionalArgs s : optionalClassPath) {
|
|
||||||
output.writeLength(s.args.length, 16);
|
|
||||||
output.writeBoolean(s.mark);
|
|
||||||
for (String f : s.args) output.writeString(f, 512);
|
|
||||||
}
|
|
||||||
// Client params
|
|
||||||
pp.write(output);
|
pp.write(output);
|
||||||
try {
|
try {
|
||||||
output.writeByteArray(SecurityHelper.encrypt(Launcher.getConfig().secretKeyClient.getBytes(), accessToken.getBytes()), SecurityHelper.CRYPTO_MAX_LENGTH);
|
output.writeByteArray(SecurityHelper.encrypt(Launcher.getConfig().secretKeyClient.getBytes(), accessToken.getBytes()), SecurityHelper.CRYPTO_MAX_LENGTH);
|
||||||
|
@ -284,9 +222,7 @@ private static void addClientArgs(Collection<String> args, ClientProfile profile
|
||||||
Collections.addAll(args, "--server", profile.getServerAddress());
|
Collections.addAll(args, "--server", profile.getServerAddress());
|
||||||
Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
|
Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
|
||||||
}
|
}
|
||||||
for (ClientProfile.OptionalArgs optionalArgs : params.optionalClientArgs) {
|
profile.pushOptionalClientArgs(args);
|
||||||
if (optionalArgs.mark) Collections.addAll(args, optionalArgs.args);
|
|
||||||
}
|
|
||||||
// Add window size args
|
// Add window size args
|
||||||
if (params.fullScreen)
|
if (params.fullScreen)
|
||||||
Collections.addAll(args, "--fullscreen", Boolean.toString(true));
|
Collections.addAll(args, "--fullscreen", Boolean.toString(true));
|
||||||
|
@ -425,11 +361,7 @@ public static Process launch(
|
||||||
// Add classpath and main class
|
// Add classpath and main class
|
||||||
String pathLauncher = IOHelper.getCodeSource(ClientLauncher.class).toString();
|
String pathLauncher = IOHelper.getCodeSource(ClientLauncher.class).toString();
|
||||||
Collections.addAll(args, profile.getJvmArgs());
|
Collections.addAll(args, profile.getJvmArgs());
|
||||||
if (profile.getOptionalJVMArgs() != null) {
|
profile.pushOptionalJvmArgs(args);
|
||||||
for (ClientProfile.OptionalArgs addArgs : profile.getOptionalJVMArgs()) {
|
|
||||||
if (addArgs.mark) Collections.addAll(args, addArgs.args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Collections.addAll(args, "-Djava.library.path=".concat(params.clientDir.resolve(NATIVES_DIR).toString())); // Add Native Path
|
Collections.addAll(args, "-Djava.library.path=".concat(params.clientDir.resolve(NATIVES_DIR).toString())); // Add Native Path
|
||||||
Collections.addAll(args, "-javaagent:".concat(pathLauncher));
|
Collections.addAll(args, "-javaagent:".concat(pathLauncher));
|
||||||
if (wrapper)
|
if (wrapper)
|
||||||
|
@ -512,14 +444,12 @@ public static void main(String... args) throws Throwable {
|
||||||
for (Path classpathURL : classPath) {
|
for (Path classpathURL : classPath) {
|
||||||
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
|
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
|
||||||
}
|
}
|
||||||
for (ClientProfile.OptionalArgs optionalArgs : params.optionalClassPath) {
|
profile.pushOptionalClassPath(cp -> {
|
||||||
if (!optionalArgs.mark) continue;
|
LinkedList<Path> optionalClassPath = resolveClassPathList(params.clientDir, cp);
|
||||||
LinkedList<Path> optionalClassPath = resolveClassPathList(params.clientDir, optionalArgs.args);
|
|
||||||
for (Path classpathURL : optionalClassPath) {
|
for (Path classpathURL : optionalClassPath) {
|
||||||
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
|
LauncherAgent.addJVMClassPath(classpathURL.toAbsolutePath().toString());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
URL[] classpathurls = resolveClassPath(params.clientDir, profile.getClassPath());
|
URL[] classpathurls = resolveClassPath(params.clientDir, profile.getClassPath());
|
||||||
classLoader = new PublicURLClassLoader(classpathurls, ClassLoader.getSystemClassLoader());
|
classLoader = new PublicURLClassLoader(classpathurls, ClassLoader.getSystemClassLoader());
|
||||||
Thread.currentThread().setContextClassLoader(classLoader);
|
Thread.currentThread().setContextClassLoader(classLoader);
|
||||||
|
@ -535,10 +465,11 @@ public static void main(String... args) throws Throwable {
|
||||||
// Verify current state of all dirs
|
// Verify current state of all dirs
|
||||||
//verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null, digest);
|
//verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null, digest);
|
||||||
HashedDir hdir = clientHDir.object;
|
HashedDir hdir = clientHDir.object;
|
||||||
for (ClientProfile.OptionalFile s : Launcher.profile.getOptional()) {
|
//for (OptionalFile s : Launcher.profile.getOptional()) {
|
||||||
if (params.updateOptional.contains(s)) s.mark = true;
|
// if (params.updateOptional.contains(s)) s.mark = true;
|
||||||
else hdir.removeR(s.file);
|
// else hdir.removeR(s.file);
|
||||||
}
|
//}
|
||||||
|
Launcher.profile.pushOptionalFile(hdir,false);
|
||||||
verifyHDir(params.assetDir, assetHDir.object, assetMatcher, digest);
|
verifyHDir(params.assetDir, assetHDir.object, assetMatcher, digest);
|
||||||
verifyHDir(params.clientDir, hdir, clientMatcher, digest);
|
verifyHDir(params.clientDir, hdir, clientMatcher, digest);
|
||||||
Launcher.modulesManager.postInitModules();
|
Launcher.modulesManager.postInitModules();
|
||||||
|
@ -574,10 +505,11 @@ public void launchLocal(SignedObjectHolder<HashedDir> assetHDir, SignedObjectHol
|
||||||
// Verify current state of all dirs
|
// Verify current state of all dirs
|
||||||
//verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null, digest);
|
//verifyHDir(IOHelper.JVM_DIR, jvmHDir.object, null, digest);
|
||||||
HashedDir hdir = clientHDir.object;
|
HashedDir hdir = clientHDir.object;
|
||||||
for (ClientProfile.OptionalFile s : Launcher.profile.getOptional()) {
|
//for (OptionalFile s : Launcher.profile.getOptional()) {
|
||||||
if (params.updateOptional.contains(s)) s.mark = true;
|
// if (params.updateOptional.contains(s)) s.mark = true;
|
||||||
else hdir.removeR(s.file);
|
// else hdir.removeR(s.file);
|
||||||
}
|
//}
|
||||||
|
Launcher.profile.pushOptionalFile(hdir,false);
|
||||||
verifyHDir(params.assetDir, assetHDir.object, assetMatcher, digest);
|
verifyHDir(params.assetDir, assetHDir.object, assetMatcher, digest);
|
||||||
verifyHDir(params.clientDir, hdir, clientMatcher, digest);
|
verifyHDir(params.clientDir, hdir, clientMatcher, digest);
|
||||||
Launcher.modulesManager.postInitModules();
|
Launcher.modulesManager.postInitModules();
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class LauncherSettings {
|
public class LauncherSettings {
|
||||||
public static int settingsMagic = 0xc0de8;
|
public static int settingsMagic = 0xc0de9;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public Path file = DirBridge.dir.resolve("settings.bin");
|
public Path file = DirBridge.dir.resolve("settings.bin");
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
|
|
|
@ -16,7 +16,7 @@ public String getName() {
|
||||||
@Override
|
@Override
|
||||||
public Path getJavaBinPath() {
|
public Path getJavaBinPath() {
|
||||||
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE)
|
if (JVMHelper.OS_TYPE == JVMHelper.OS.MUSTDIE)
|
||||||
return ClientLauncher.getJavaBinPath();
|
return IOHelper.resolveJavaBin(ClientLauncher.getJavaBinPath());
|
||||||
else
|
else
|
||||||
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home")));
|
return IOHelper.resolveJavaBin(Paths.get(System.getProperty("java.home")));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ru.gravit.launcher.guard;
|
package ru.gravit.launcher.guard;
|
||||||
|
|
||||||
|
import ru.gravit.launcher.Launcher;
|
||||||
import ru.gravit.launcher.client.DirBridge;
|
import ru.gravit.launcher.client.DirBridge;
|
||||||
import ru.gravit.utils.helper.IOHelper;
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
import ru.gravit.utils.helper.JVMHelper;
|
import ru.gravit.utils.helper.JVMHelper;
|
||||||
|
@ -27,7 +28,10 @@ public Path getJavaBinPath() {
|
||||||
@Override
|
@Override
|
||||||
public void init(boolean clientInstance) {
|
public void init(boolean clientInstance) {
|
||||||
try {
|
try {
|
||||||
UnpackHelper.unpack(IOHelper.getResourceURL(JVMHelper.JVM_BITS == 64 ? "wrapper64.exe" : "wrapper32.exe"),DirBridge.getGuardDir());
|
String wrapperName = JVMHelper.JVM_BITS == 64 ? "wrapper64.exe" : "wrapper32.exe";
|
||||||
|
String antiInjectName = JVMHelper.JVM_BITS == 64 ? "AntiInject64.dll" : "AntiInject32.dll";
|
||||||
|
UnpackHelper.unpack(Launcher.getResourceURL(wrapperName, "guard"),DirBridge.getGuardDir().resolve(wrapperName));
|
||||||
|
UnpackHelper.unpack(Launcher.getResourceURL(antiInjectName, "guard"),DirBridge.getGuardDir().resolve(antiInjectName));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new SecurityException(e);
|
throw new SecurityException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
import ru.gravit.launcher.profiles.ClientProfile;
|
import ru.gravit.launcher.profiles.ClientProfile;
|
||||||
import ru.gravit.launcher.profiles.PlayerProfile;
|
import ru.gravit.launcher.profiles.PlayerProfile;
|
||||||
import ru.gravit.launcher.profiles.Texture;
|
import ru.gravit.launcher.profiles.Texture;
|
||||||
|
import ru.gravit.launcher.profiles.optional.OptionalFile;
|
||||||
import ru.gravit.launcher.request.*;
|
import ru.gravit.launcher.request.*;
|
||||||
import ru.gravit.launcher.request.auth.AuthRequest;
|
import ru.gravit.launcher.request.auth.AuthRequest;
|
||||||
import ru.gravit.launcher.request.auth.CheckServerRequest;
|
import ru.gravit.launcher.request.auth.CheckServerRequest;
|
||||||
|
@ -95,6 +96,7 @@ public static void addLauncherClassBindings(Map<String, Object> bindings) {
|
||||||
bindings.put("SignedBytesHolderClass", SignedBytesHolder.class);
|
bindings.put("SignedBytesHolderClass", SignedBytesHolder.class);
|
||||||
bindings.put("SignedObjectHolderClass", SignedObjectHolder.class);
|
bindings.put("SignedObjectHolderClass", SignedObjectHolder.class);
|
||||||
bindings.put("EnumSerializerClass", EnumSerializer.class);
|
bindings.put("EnumSerializerClass", EnumSerializer.class);
|
||||||
|
bindings.put("OptionalFileClass", OptionalFile.class);
|
||||||
|
|
||||||
// Set helper class bindings
|
// Set helper class bindings
|
||||||
bindings.put("CommonHelperClass", CommonHelper.class);
|
bindings.put("CommonHelperClass", CommonHelper.class);
|
||||||
|
|
|
@ -224,7 +224,7 @@ private void deleteExtraDir(Path subDir, HashedDir subHDir, boolean flag) throws
|
||||||
String name = mapEntry.getKey();
|
String name = mapEntry.getKey();
|
||||||
Path path = subDir.resolve(name);
|
Path path = subDir.resolve(name);
|
||||||
|
|
||||||
// Delete files and dirs based on type
|
// Delete list and dirs based on type
|
||||||
HashedEntry entry = mapEntry.getValue();
|
HashedEntry entry = mapEntry.getValue();
|
||||||
HashedEntry.Type entryType = entry.getType();
|
HashedEntry.Type entryType = entry.getType();
|
||||||
switch (entryType) {
|
switch (entryType) {
|
||||||
|
@ -308,7 +308,7 @@ protected SignedObjectHolder<HashedDir> requestDo(HInput input, HOutput output)
|
||||||
// Get diff between local and remote dir
|
// Get diff between local and remote dir
|
||||||
SignedObjectHolder<HashedDir> remoteHDirHolder = new SignedObjectHolder<>(input, config.publicKey, HashedDir::new);
|
SignedObjectHolder<HashedDir> remoteHDirHolder = new SignedObjectHolder<>(input, config.publicKey, HashedDir::new);
|
||||||
HashedDir hackHackedDir = remoteHDirHolder.object;
|
HashedDir hackHackedDir = remoteHDirHolder.object;
|
||||||
Launcher.profile.pushOptional(hackHackedDir, !Launcher.profile.isUpdateFastCheck());
|
Launcher.profile.pushOptionalFile(hackHackedDir, !Launcher.profile.isUpdateFastCheck());
|
||||||
HashedDir.Diff diff = hackHackedDir.diff(localDir, matcher);
|
HashedDir.Diff diff = hackHackedDir.diff(localDir, matcher);
|
||||||
totalSize = diff.mismatch.size();
|
totalSize = diff.mismatch.size();
|
||||||
boolean compress = input.readBoolean();
|
boolean compress = input.readBoolean();
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
public class ServerAgent {
|
public class ServerAgent {
|
||||||
|
|
|
@ -8,23 +8,55 @@
|
||||||
public class ClientPermissions {
|
public class ClientPermissions {
|
||||||
public static final ClientPermissions DEFAULT = new ClientPermissions();
|
public static final ClientPermissions DEFAULT = new ClientPermissions();
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public boolean canAdmin;
|
public boolean canAdmin = false;
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public boolean canServer;
|
public boolean canServer = false;
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean canUSR1 = false;
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean canUSR2 = false;
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean canUSR3 = false;
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean canBot = false;
|
||||||
|
|
||||||
public ClientPermissions(HInput input) throws IOException {
|
public ClientPermissions(HInput input) throws IOException {
|
||||||
canAdmin = input.readBoolean();
|
canAdmin = input.readBoolean();
|
||||||
canServer = input.readBoolean();
|
canServer = input.readBoolean();
|
||||||
|
canUSR1 = input.readBoolean();
|
||||||
|
canUSR2 = input.readBoolean();
|
||||||
|
canUSR3 = input.readBoolean();
|
||||||
|
canBot = input.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientPermissions() {
|
public ClientPermissions() {
|
||||||
canAdmin = false;
|
canAdmin = false;
|
||||||
canServer = false;
|
canServer = false;
|
||||||
|
canUSR1 = false;
|
||||||
|
canUSR2 = false;
|
||||||
|
canUSR3 = false;
|
||||||
|
canBot = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientPermissions(long data) {
|
public ClientPermissions(long data) {
|
||||||
canAdmin = (data & (1)) != 0;
|
canAdmin = (data & (1)) != 0;
|
||||||
canServer = (data & (1 << 1)) != 0;
|
canServer = (data & (1 << 1)) != 0;
|
||||||
|
canUSR1 = (data & (1 << 2)) != 0;
|
||||||
|
canUSR2 = (data & (1 << 3)) != 0;
|
||||||
|
canUSR3 = (data & (1 << 4)) != 0;
|
||||||
|
canBot = (data & (1 << 5)) != 0;
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public long toLong()
|
||||||
|
{
|
||||||
|
long result = 0;
|
||||||
|
result |= canAdmin ? 0 : 1;
|
||||||
|
result |= canServer ? 0 : (1 << 1);
|
||||||
|
result |= canUSR1 ? 0 : (1 << 2);
|
||||||
|
result |= canUSR2 ? 0 : (1 << 3);
|
||||||
|
result |= canUSR3 ? 0 : (1 << 4);
|
||||||
|
result |= canBot ? 0 : (1 << 5);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClientPermissions getSuperuserAccount() {
|
public static ClientPermissions getSuperuserAccount() {
|
||||||
|
@ -37,5 +69,9 @@ public static ClientPermissions getSuperuserAccount() {
|
||||||
public void write(HOutput output) throws IOException {
|
public void write(HOutput output) throws IOException {
|
||||||
output.writeBoolean(canAdmin);
|
output.writeBoolean(canAdmin);
|
||||||
output.writeBoolean(canServer);
|
output.writeBoolean(canServer);
|
||||||
|
output.writeBoolean(canUSR1);
|
||||||
|
output.writeBoolean(canUSR2);
|
||||||
|
output.writeBoolean(canUSR3);
|
||||||
|
output.writeBoolean(canBot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,8 +59,8 @@ public final class Launcher {
|
||||||
|
|
||||||
private static final Pattern UUID_PATTERN = Pattern.compile("-", Pattern.LITERAL);
|
private static final Pattern UUID_PATTERN = Pattern.compile("-", Pattern.LITERAL);
|
||||||
public static final int MAJOR = 4;
|
public static final int MAJOR = 4;
|
||||||
public static final int MINOR = 2;
|
public static final int MINOR = 3;
|
||||||
public static final int PATCH = 2;
|
public static final int PATCH = 0;
|
||||||
public static final int BUILD = 1;
|
public static final int BUILD = 1;
|
||||||
public static final Version.Type RELEASE = Version.Type.STABLE;
|
public static final Version.Type RELEASE = Version.Type.STABLE;
|
||||||
public static GsonBuilder gsonBuilder;
|
public static GsonBuilder gsonBuilder;
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
import ru.gravit.launcher.LauncherAPI;
|
import ru.gravit.launcher.LauncherAPI;
|
||||||
import ru.gravit.launcher.hasher.FileNameMatcher;
|
import ru.gravit.launcher.hasher.FileNameMatcher;
|
||||||
import ru.gravit.launcher.hasher.HashedDir;
|
import ru.gravit.launcher.hasher.HashedDir;
|
||||||
|
import ru.gravit.launcher.profiles.optional.OptionalFile;
|
||||||
|
import ru.gravit.launcher.profiles.optional.OptionalType;
|
||||||
import ru.gravit.utils.helper.IOHelper;
|
import ru.gravit.utils.helper.IOHelper;
|
||||||
import ru.gravit.utils.helper.VerifyHelper;
|
import ru.gravit.utils.helper.VerifyHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
@ -79,66 +82,6 @@ public String toString() {
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
private int serverPort;
|
private int serverPort;
|
||||||
|
|
||||||
public static class OptionalFile {
|
|
||||||
@LauncherAPI
|
|
||||||
public String file;
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean mark;
|
|
||||||
@LauncherAPI
|
|
||||||
public String name;
|
|
||||||
@LauncherAPI
|
|
||||||
public String info;
|
|
||||||
@LauncherAPI
|
|
||||||
public String[] dependenciesFile;
|
|
||||||
@LauncherAPI
|
|
||||||
public String[] conflictFile;
|
|
||||||
@LauncherAPI
|
|
||||||
public transient OptionalFile[] dependencies;
|
|
||||||
@LauncherAPI
|
|
||||||
public transient OptionalFile[] conflict;
|
|
||||||
@LauncherAPI
|
|
||||||
public int subTreeLevel = 1;
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean isAdminOnly = false;
|
|
||||||
@LauncherAPI
|
|
||||||
public transient Set<OptionalFile> dependenciesCount;
|
|
||||||
|
|
||||||
public OptionalFile(String file, boolean mark) {
|
|
||||||
this.file = file;
|
|
||||||
this.mark = mark;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OptionalFile(String file) {
|
|
||||||
this.file = file;
|
|
||||||
this.mark = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
OptionalFile that = (OptionalFile) o;
|
|
||||||
return Objects.equals(file, that.file);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class OptionalArgs {
|
|
||||||
@LauncherAPI
|
|
||||||
public boolean mark;
|
|
||||||
@LauncherAPI
|
|
||||||
public String[] args;
|
|
||||||
|
|
||||||
public OptionalArgs(String[] args, boolean mark) {
|
|
||||||
this.mark = mark;
|
|
||||||
this.args = args;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updater and client watch service
|
// Updater and client watch service
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
private final List<String> update = new ArrayList<>();
|
private final List<String> update = new ArrayList<>();
|
||||||
|
@ -165,12 +108,6 @@ public OptionalArgs(String[] args, boolean mark) {
|
||||||
private final List<String> clientArgs = new ArrayList<>();
|
private final List<String> clientArgs = new ArrayList<>();
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
private final List<String> whitelist = new ArrayList<>();
|
private final List<String> whitelist = new ArrayList<>();
|
||||||
@LauncherAPI
|
|
||||||
private final List<OptionalArgs> optionalJVMArgs = new ArrayList<>();
|
|
||||||
@LauncherAPI
|
|
||||||
private final List<OptionalArgs> optionalClientArgs = new ArrayList<>();
|
|
||||||
@LauncherAPI
|
|
||||||
private final List<OptionalArgs> optionalClassPath = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ClientProfile o) {
|
public int compareTo(ClientProfile o) {
|
||||||
|
@ -192,21 +129,6 @@ public String[] getClassPath() {
|
||||||
return classPath.toArray(new String[0]);
|
return classPath.toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public List<OptionalArgs> getOptionalJVMArgs() {
|
|
||||||
return optionalJVMArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public List<OptionalArgs> getOptionalClientArgs() {
|
|
||||||
return optionalClientArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
|
||||||
public List<OptionalArgs> getOptionalClassPath() {
|
|
||||||
return optionalClassPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public String[] getClientArgs() {
|
public String[] getClientArgs() {
|
||||||
return clientArgs.toArray(new String[0]);
|
return clientArgs.toArray(new String[0]);
|
||||||
|
@ -269,22 +191,22 @@ public void updateOptionalGraph() {
|
||||||
if (file.dependenciesFile != null) {
|
if (file.dependenciesFile != null) {
|
||||||
file.dependencies = new OptionalFile[file.dependenciesFile.length];
|
file.dependencies = new OptionalFile[file.dependenciesFile.length];
|
||||||
for (int i = 0; i < file.dependenciesFile.length; ++i) {
|
for (int i = 0; i < file.dependenciesFile.length; ++i) {
|
||||||
file.dependencies[i] = getOptionalFile(file.dependenciesFile[i]);
|
file.dependencies[i] = getOptionalFile(file.dependenciesFile[i].name, file.dependenciesFile[i].type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (file.conflictFile != null) {
|
if (file.conflictFile != null) {
|
||||||
file.conflict = new OptionalFile[file.conflictFile.length];
|
file.conflict = new OptionalFile[file.conflictFile.length];
|
||||||
for (int i = 0; i < file.conflictFile.length; ++i) {
|
for (int i = 0; i < file.conflictFile.length; ++i) {
|
||||||
file.conflict[i] = getOptionalFile(file.conflictFile[i]);
|
file.conflict[i] = getOptionalFile(file.conflictFile[i].name, file.conflictFile[i].type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public OptionalFile getOptionalFile(String file) {
|
public OptionalFile getOptionalFile(String file, OptionalType type) {
|
||||||
for (OptionalFile f : updateOptional)
|
for (OptionalFile f : updateOptional)
|
||||||
if (f.file.equals(file)) return f;
|
if (f.type.equals(type) && f.name.equals(file)) return f;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,10 +216,11 @@ public Collection<String> getShared() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public void markOptional(String opt) {
|
public void markOptional(String name, OptionalType type) {
|
||||||
if (!updateOptional.contains(new OptionalFile(opt)))
|
OptionalFile file = getOptionalFile(name, type);
|
||||||
throw new SecurityException(String.format("Optional mod %s not found in optionalList", opt));
|
if (file == null) {
|
||||||
OptionalFile file = getOptionalFile(opt);
|
throw new SecurityException(String.format("Optional %s not found in optionalList", name));
|
||||||
|
}
|
||||||
markOptional(file);
|
markOptional(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,10 +244,11 @@ public void markOptional(OptionalFile file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public void unmarkOptional(String opt) {
|
public void unmarkOptional(String name, OptionalType type) {
|
||||||
if (!updateOptional.contains(new OptionalFile(opt)))
|
OptionalFile file = getOptionalFile(name, type);
|
||||||
throw new SecurityException(String.format("Optional mod %s not found in optionalList", opt));
|
if (file == null) {
|
||||||
OptionalFile file = getOptionalFile(opt);
|
throw new SecurityException(String.format("Optional %s not found in optionalList", name));
|
||||||
|
}
|
||||||
unmarkOptional(file);
|
unmarkOptional(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,12 +277,45 @@ public void unmarkOptional(OptionalFile file) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pushOptional(HashedDir dir, boolean digest) {
|
public void pushOptionalFile(HashedDir dir, boolean digest) {
|
||||||
for (OptionalFile opt : updateOptional) {
|
for (OptionalFile opt : updateOptional) {
|
||||||
if (!opt.mark) dir.removeR(opt.file);
|
if (opt.type.equals(OptionalType.FILE) && !opt.mark) {
|
||||||
|
for (String file : opt.list)
|
||||||
|
dir.removeR(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pushOptionalJvmArgs(Collection<String> jvmArgs1)
|
||||||
|
{
|
||||||
|
for (OptionalFile opt : updateOptional) {
|
||||||
|
if (opt.type.equals(OptionalType.JVMARGS) && opt.mark) {
|
||||||
|
jvmArgs1.addAll(Arrays.asList(opt.list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void pushOptionalClientArgs(Collection<String> clientArgs1)
|
||||||
|
{
|
||||||
|
for (OptionalFile opt : updateOptional) {
|
||||||
|
if (opt.type.equals(OptionalType.CLIENTARGS) && opt.mark) {
|
||||||
|
clientArgs1.addAll(Arrays.asList(opt.list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void pushOptionalClassPath(pushOptionalClassPathCallback callback) throws IOException
|
||||||
|
{
|
||||||
|
for (OptionalFile opt : updateOptional) {
|
||||||
|
if (opt.type.equals(OptionalType.CLASSPATH) && opt.mark) {
|
||||||
|
callback.run(opt.list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface pushOptionalClassPathCallback
|
||||||
|
{
|
||||||
|
void run(String[] opt) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public int getServerPort() {
|
public int getServerPort() {
|
||||||
return serverPort;
|
return serverPort;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package ru.gravit.launcher.profiles.optional;
|
||||||
|
|
||||||
|
import ru.gravit.launcher.LauncherAPI;
|
||||||
|
|
||||||
|
public class OptionalDepend {
|
||||||
|
@LauncherAPI
|
||||||
|
public String name;
|
||||||
|
@LauncherAPI
|
||||||
|
public OptionalType type;
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
package ru.gravit.launcher.profiles.optional;
|
||||||
|
|
||||||
|
import ru.gravit.launcher.LauncherAPI;
|
||||||
|
import ru.gravit.launcher.serialize.HInput;
|
||||||
|
import ru.gravit.launcher.serialize.HOutput;
|
||||||
|
import ru.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class OptionalFile {
|
||||||
|
@LauncherAPI
|
||||||
|
public String[] list;
|
||||||
|
@LauncherAPI
|
||||||
|
public OptionalType type;
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean mark;
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean visible = true;
|
||||||
|
@LauncherAPI
|
||||||
|
public String name;
|
||||||
|
@LauncherAPI
|
||||||
|
public String info;
|
||||||
|
@LauncherAPI
|
||||||
|
public OptionalDepend[] dependenciesFile;
|
||||||
|
@LauncherAPI
|
||||||
|
public OptionalDepend[] conflictFile;
|
||||||
|
@LauncherAPI
|
||||||
|
public transient OptionalFile[] dependencies;
|
||||||
|
@LauncherAPI
|
||||||
|
public transient OptionalFile[] conflict;
|
||||||
|
@LauncherAPI
|
||||||
|
public int subTreeLevel = 1;
|
||||||
|
@LauncherAPI
|
||||||
|
public long permissions = 0L;
|
||||||
|
@LauncherAPI
|
||||||
|
public transient Set<OptionalFile> dependenciesCount;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
OptionalFile that = (OptionalFile) o;
|
||||||
|
return Objects.equals(name, that.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(name);
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public OptionalType getType() {
|
||||||
|
return OptionalType.FILE;
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean isVisible() {
|
||||||
|
return visible;
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public boolean isMark() {
|
||||||
|
return mark;
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public long getPermissions() {
|
||||||
|
return permissions;
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public void writeType(HOutput output) throws IOException
|
||||||
|
{
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
|
||||||
|
case FILE:
|
||||||
|
output.writeInt(1);
|
||||||
|
break;
|
||||||
|
case CLASSPATH:
|
||||||
|
output.writeInt(2);
|
||||||
|
break;
|
||||||
|
case JVMARGS:
|
||||||
|
output.writeInt(3);
|
||||||
|
break;
|
||||||
|
case CLIENTARGS:
|
||||||
|
output.writeInt(4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
output.writeInt(5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@LauncherAPI
|
||||||
|
public static OptionalType readType(HInput input) throws IOException
|
||||||
|
{
|
||||||
|
int t = input.readInt();
|
||||||
|
OptionalType type;
|
||||||
|
switch(t)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
type = OptionalType.FILE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
type = OptionalType.CLASSPATH;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
type = OptionalType.JVMARGS;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
type = OptionalType.CLIENTARGS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogHelper.error("readType failed. Read int %d",t);
|
||||||
|
type = OptionalType.FILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package ru.gravit.launcher.profiles.optional;
|
||||||
|
|
||||||
|
import ru.gravit.launcher.LauncherAPI;
|
||||||
|
|
||||||
|
@LauncherAPI
|
||||||
|
public enum OptionalType
|
||||||
|
{
|
||||||
|
@LauncherAPI
|
||||||
|
FILE,
|
||||||
|
@LauncherAPI
|
||||||
|
CLASSPATH,
|
||||||
|
@LauncherAPI
|
||||||
|
JVMARGS,
|
||||||
|
@LauncherAPI
|
||||||
|
CLIENTARGS
|
||||||
|
}
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
import ru.gravit.launcher.LauncherAPI;
|
import ru.gravit.launcher.LauncherAPI;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public final class Version {
|
public final class Version {
|
||||||
|
@ -68,34 +73,8 @@ public int hashCode() {
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public String getReleaseStatus() {
|
public String getReleaseStatus() {
|
||||||
String result;
|
if (release.equals(Type.UNKNOWN)) return "";
|
||||||
switch (release) {
|
return release.name().toLowerCase(Locale.ENGLISH);
|
||||||
case LTS:
|
|
||||||
result = "lts";
|
|
||||||
break;
|
|
||||||
case STABLE:
|
|
||||||
result = "stable";
|
|
||||||
break;
|
|
||||||
case BETA:
|
|
||||||
result = "beta";
|
|
||||||
break;
|
|
||||||
case ALPHA:
|
|
||||||
result = "alpha";
|
|
||||||
break;
|
|
||||||
case DEV:
|
|
||||||
result = "dev";
|
|
||||||
break;
|
|
||||||
case EXPERIMENTAL:
|
|
||||||
result = "experimental";
|
|
||||||
break;
|
|
||||||
case UNKNOWN:
|
|
||||||
result = "";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
result = "";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,6 +91,13 @@ public enum Type {
|
||||||
ALPHA,
|
ALPHA,
|
||||||
DEV,
|
DEV,
|
||||||
EXPERIMENTAL,
|
EXPERIMENTAL,
|
||||||
UNKNOWN
|
UNKNOWN;
|
||||||
|
|
||||||
|
private static final Map<String, Type> types = new HashMap<>();
|
||||||
|
public static final Map<String, Type> unModTypes = Collections.unmodifiableMap(types);
|
||||||
|
|
||||||
|
static {
|
||||||
|
Arrays.asList(values()).stream().forEach(type -> types.put(type.name().substring(0, type.name().length() < 3 ? type.name().length() : 3), type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
modules
2
modules
|
@ -1 +1 @@
|
||||||
Subproject commit 38e11640ce4a4ed3e9745718db02a888770a22bb
|
Subproject commit 53106ee20700cb73ad65fd7dddf69b0d0b766f4c
|
Loading…
Reference in a new issue