[FEATURE][EXPERIMENTAL] Новый API опциональных модов

This commit is contained in:
Gravit 2020-09-12 13:41:58 +07:00
parent 383551229d
commit b2a3e5672a
No known key found for this signature in database
GPG key ID: 98A079490768CCE5
16 changed files with 284 additions and 15 deletions

View file

@ -4,6 +4,7 @@
import pro.gravit.launcher.Launcher;
import pro.gravit.launcher.LauncherTrustManager;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launchserver.auth.handler.AuthHandler;
import pro.gravit.launchserver.auth.protect.ProtectHandler;
@ -213,6 +214,7 @@ public static void registerAll() {
DaoProvider.registerProviders();
AuthRequest.registerProviders();
HWIDProvider.registerProviders();
OptionalAction.registerProviders();
}
public static void generateConfigIfNotExists(Path configFile, CommandHandler commandHandler, LaunchServer.LaunchServerEnv env) throws IOException {

View file

@ -3,6 +3,7 @@
import com.google.gson.GsonBuilder;
import pro.gravit.launcher.managers.GsonManager;
import pro.gravit.launcher.modules.events.PreGsonPhase;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.request.JsonResultSerializeAdapter;
import pro.gravit.launcher.request.WebSocketEvent;
import pro.gravit.launcher.request.auth.AuthRequest;
@ -39,6 +40,7 @@ public void registerAdapters(GsonBuilder builder) {
builder.registerTypeAdapter(WebSocketEvent.class, new JsonResultSerializeAdapter());
builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers));
builder.registerTypeAdapter(HWIDProvider.class, new UniversalJsonAdapter<>(HWIDProvider.providers));
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
modulesManager.invokeEvent(new PreGsonPhase(builder));
//ClientWebSocketService.appendTypeAdapters(builder);
}

View file

@ -13,8 +13,10 @@
import pro.gravit.launcher.managers.ClientGsonManager;
import pro.gravit.launcher.managers.ConsoleManager;
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.RestoreSessionRequest;
import pro.gravit.launcher.request.websockets.StdWebSocketService;
import pro.gravit.launcher.utils.NativeJVMHalt;
@ -113,6 +115,8 @@ public static void main(String... args) throws Throwable {
}
public static void initGson(ClientModuleManager modulesManager) {
AuthRequest.registerProviders();
OptionalAction.registerProviders();
Launcher.gsonManager = new ClientGsonManager(modulesManager);
Launcher.gsonManager.initGson();
}

View file

@ -14,8 +14,11 @@
import pro.gravit.launcher.modules.events.PreConfigPhase;
import pro.gravit.launcher.patches.FMLPatcher;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.profiles.optional.actions.OptionalActionClassPath;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.launcher.request.auth.RestoreSessionRequest;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.utils.DirWatcher;
@ -95,9 +98,10 @@ public static void main(String[] args) throws Throwable {
List<URL> classpath = new LinkedList<>();
resolveClassPathStream(clientDir, params.profile.getClassPath()).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath));
params.profile.pushOptionalClassPath((opt) -> {
resolveClassPathStream(clientDir, opt).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath));
});
for(OptionalAction a : params.actions) {
if(a instanceof OptionalActionClassPath)
resolveClassPathStream(clientDir, ((OptionalActionClassPath) a).args).map(IOHelper::toURL).collect(Collectors.toCollection(() -> classpath));
}
classLoader = new ClientClassLoader(classpath.toArray(new URL[0]), ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(classLoader);
classLoader.nativePath = clientDir.resolve("natives").toString();
@ -145,7 +149,6 @@ public static void main(String[] args) throws Throwable {
// if (params.updateOptional.contains(s)) s.mark = true;
// else hdir.removeR(s.file);
//}
Launcher.profile.pushOptionalFile(params.clientHDir, false);
// Start WatchService, and only then client
CommonHelper.newThread("Asset Directory Watcher", true, assetWatcher).start();
CommonHelper.newThread("Client Directory Watcher", true, clientWatcher).start();
@ -162,6 +165,8 @@ public static void main(String[] args) throws Throwable {
}
private static void initGson(ClientModuleManager moduleManager) {
AuthRequest.registerProviders();
OptionalAction.registerProviders();
Launcher.gsonManager = new ClientGsonManager(moduleManager);
Launcher.gsonManager.initGson();
}

View file

@ -10,6 +10,10 @@
import pro.gravit.launcher.hasher.HashedDir;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.profiles.PlayerProfile;
import pro.gravit.launcher.profiles.optional.OptionalView;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.profiles.optional.actions.OptionalActionClientArgs;
import pro.gravit.launcher.profiles.optional.actions.OptionalActionJvmArgs;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.utils.Version;
@ -49,17 +53,17 @@ public ClientLauncherProcess(Path executeFile, Path workDir, Path javaDir, Strin
public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir,
ClientProfile profile, PlayerProfile playerProfile, String accessToken,
HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) {
this(clientDir, assetDir, javaDir, clientDir.resolve("resourcepacks"), profile, playerProfile, accessToken, clientHDir, assetHDir, jvmHDir);
this(clientDir, assetDir, javaDir, clientDir.resolve("resourcepacks"), profile, playerProfile, null, accessToken, clientHDir, assetHDir, jvmHDir);
}
public ClientLauncherProcess(Path clientDir, Path assetDir,
ClientProfile profile, PlayerProfile playerProfile, String accessToken,
HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) {
this(clientDir, assetDir, Paths.get(System.getProperty("java.home")), clientDir.resolve("resourcepacks"), profile, playerProfile, accessToken, clientHDir, assetHDir, jvmHDir);
this(clientDir, assetDir, Paths.get(System.getProperty("java.home")), clientDir.resolve("resourcepacks"), profile, playerProfile, null, accessToken, clientHDir, assetHDir, jvmHDir);
}
public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path resourcePackDir,
ClientProfile profile, PlayerProfile playerProfile, String accessToken,
ClientProfile profile, PlayerProfile playerProfile, OptionalView view, String accessToken,
HashedDir clientHDir, HashedDir assetHDir, HashedDir jvmHDir) {
this.workDir = clientDir.toAbsolutePath();
this.javaDir = javaDir;
@ -74,6 +78,10 @@ public ClientLauncherProcess(Path clientDir, Path assetDir, Path javaDir, Path r
this.params.assetHDir = assetHDir;
this.params.clientHDir = clientHDir;
this.params.javaHDir = jvmHDir;
if(view != null)
{
this.params.actions = view.getEnabledActions();
}
this.bits = JVMHelper.JVM_BITS;
applyClientProfile();
}
@ -88,7 +96,13 @@ public static String getPathSeparator() {
private void applyClientProfile() {
this.systemClassPath.add(IOHelper.getCodeSource(ClientLauncherEntryPoint.class).toAbsolutePath().toString());
Collections.addAll(this.jvmArgs, this.params.profile.getJvmArgs());
this.params.profile.pushOptionalJvmArgs(this.jvmArgs);
for(OptionalAction a : this.params.actions)
{
if(a instanceof OptionalActionJvmArgs)
{
this.jvmArgs.addAll(((OptionalActionJvmArgs) a).args);
}
}
this.systemEnv.put("JAVA_HOME", javaDir.toString());
Collections.addAll(this.systemClassPath, this.params.profile.getAlternativeClassPath());
if (params.ram > 0) {
@ -193,6 +207,8 @@ public static class ClientParams {
public int height;
public Set<OptionalAction> actions = new HashSet<>();
//========
public UUID session;
@ -263,7 +279,13 @@ private void addModernClientArgs(Collection<String> args) {
Collections.addAll(args, "--server", profile.getServerAddress());
Collections.addAll(args, "--port", Integer.toString(profile.getServerPort()));
}
profile.pushOptionalClientArgs(args);
for(OptionalAction a : actions)
{
if(a instanceof OptionalActionClientArgs)
{
args.addAll(((OptionalActionClientArgs) a).args);
}
}
// Add window size args
if (fullScreen)
Collections.addAll(args, "--fullscreen", Boolean.toString(true));

View file

@ -194,7 +194,7 @@ public OptionalFile getOptionalFile(String file, OptionalType type) {
public Collection<String> getShared() {
return updateShared;
}
@Deprecated
public void markOptional(OptionalFile file) {
if (file.mark) return;
@ -213,7 +213,7 @@ public void markOptional(OptionalFile file) {
}
}
}
@Deprecated
public void unmarkOptional(OptionalFile file) {
if (!file.mark) return;
file.mark = false;
@ -239,7 +239,7 @@ public void unmarkOptional(OptionalFile file) {
}
}
}
@Deprecated
public void pushOptionalFile(HashedDir dir, boolean digest) {
for (OptionalFile opt : updateOptional) {
if (opt.type.equals(OptionalType.FILE) && !opt.mark) {
@ -248,7 +248,7 @@ public void pushOptionalFile(HashedDir dir, boolean digest) {
}
}
}
@Deprecated
public void pushOptionalJvmArgs(Collection<String> jvmArgs1) {
for (OptionalFile opt : updateOptional) {
if (opt.type.equals(OptionalType.JVMARGS) && opt.mark) {
@ -256,7 +256,7 @@ public void pushOptionalJvmArgs(Collection<String> jvmArgs1) {
}
}
}
@Deprecated
public void pushOptionalClientArgs(Collection<String> clientArgs1) {
for (OptionalFile opt : updateOptional) {
if (opt.type.equals(OptionalType.CLIENTARGS) && opt.mark) {
@ -264,7 +264,7 @@ public void pushOptionalClientArgs(Collection<String> clientArgs1) {
}
}
}
@Deprecated
public void pushOptionalClassPath(pushOptionalClassPathCallback callback) throws IOException {
for (OptionalFile opt : updateOptional) {
if (opt.type.equals(OptionalType.CLASSPATH) && opt.mark) {

View file

@ -1,12 +1,14 @@
package pro.gravit.launcher.profiles.optional;
import pro.gravit.launcher.LauncherNetworkAPI;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.serialize.HInput;
import pro.gravit.launcher.serialize.HOutput;
import pro.gravit.utils.helper.LogHelper;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@ -16,10 +18,14 @@ public class OptionalFile {
@LauncherNetworkAPI
public final long permissions = 0L;
@LauncherNetworkAPI
@Deprecated
public String[] list;
@LauncherNetworkAPI
@Deprecated
public OptionalType type;
@LauncherNetworkAPI
public List<OptionalAction> actions;
@LauncherNetworkAPI
public boolean mark;
@LauncherNetworkAPI
public boolean visible = true;

View file

@ -0,0 +1,113 @@
package pro.gravit.launcher.profiles.optional;
import pro.gravit.launcher.profiles.ClientProfile;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class OptionalView {
public Set<OptionalFile> enabled = new HashSet<>();
public Set<OptionalFile> all;
@SuppressWarnings("unchecked")
public<T extends OptionalAction> Set<T> getActionsByClass(Class<T> clazz)
{
Set<T> results = new HashSet<>();
for(OptionalFile e : enabled)
{
if(e.actions != null)
{
for(OptionalAction a : e.actions)
{
if(clazz.isAssignableFrom(a.getClass()))
{
results.add((T) a);
}
}
}
}
return results;
}
public Set<OptionalAction> getEnabledActions()
{
Set<OptionalAction> results = new HashSet<>();
for(OptionalFile e : enabled)
{
if(e.actions != null)
{
results.addAll(e.actions);
}
}
return results;
}
public Set<OptionalAction> getDisabledActions()
{
Set<OptionalAction> results = new HashSet<>();
for(OptionalFile e : all)
{
if(enabled.contains(e)) continue;
if(e.actions != null)
{
results.addAll(e.actions);
}
}
return results;
}
public void enable(OptionalFile file)
{
if(enabled.contains(file)) return;
enabled.add(file);
file.watchEvent(true);
if (file.dependencies != null) {
for (OptionalFile dep : file.dependencies) {
if (dep.dependenciesCount == null) dep.dependenciesCount = new HashSet<>();
dep.dependenciesCount.add(file);
enable(dep);
}
}
if (file.conflict != null) {
for (OptionalFile conflict : file.conflict) {
disable(conflict);
}
}
}
public void disable(OptionalFile file)
{
if(!enabled.remove(file)) return;
file.watchEvent(false);
if (file.dependenciesCount != null) {
for (OptionalFile f : file.dependenciesCount) {
if (f.isPreset) continue;
disable(f);
}
file.dependenciesCount.clear();
file.dependenciesCount = null;
}
if (file.dependencies != null) {
for (OptionalFile f : file.dependencies) {
if (!enabled.contains(f)) continue;
if (f.dependenciesCount == null) {
disable(f);
} else if (f.dependenciesCount.size() <= 1) {
f.dependenciesCount.clear();
f.dependenciesCount = null;
disable(f);
}
}
}
}
public OptionalView(ClientProfile profile)
{
this.all = profile.getOptional();
for(OptionalFile f : this.all)
{
if(f.mark) enable(f);
}
}
}

View file

@ -0,0 +1,19 @@
package pro.gravit.launcher.profiles.optional.actions;
import pro.gravit.utils.ProviderMap;
public class OptionalAction {
public static ProviderMap<OptionalAction> providers = new ProviderMap<>();
private static boolean registerProviders = false;
public static void registerProviders()
{
if(!registerProviders)
{
providers.register("file", OptionalActionFile.class);
providers.register("clientArgs", OptionalActionClientArgs.class);
providers.register("jvmArgs", OptionalActionJvmArgs.class);
providers.register("classpath", OptionalActionClassPath.class);
registerProviders = true;
}
}
}

View file

@ -0,0 +1,8 @@
package pro.gravit.launcher.profiles.optional.actions;
import java.util.List;
public class OptionalActionClassPath extends OptionalAction {
public String[] args;
public boolean useAltClasspath = false;
}

View file

@ -0,0 +1,7 @@
package pro.gravit.launcher.profiles.optional.actions;
import java.util.List;
public class OptionalActionClientArgs extends OptionalAction {
public List<String> args;
}

View file

@ -0,0 +1,29 @@
package pro.gravit.launcher.profiles.optional.actions;
import pro.gravit.launcher.hasher.HashedDir;
import java.util.List;
import java.util.Map;
public class OptionalActionFile extends OptionalAction {
public Map<String, String> files;
public void injectToHashedDir(HashedDir dir)
{
if(files == null) return;
files.forEach((k,v) -> {
HashedDir.FindRecursiveResult firstPath = dir.findRecursive(k);
if (v != null && !v.isEmpty()) {
HashedDir.FindRecursiveResult secondPath = dir.findRecursive(v);
firstPath.parent.moveTo(firstPath.name, secondPath.parent, secondPath.name);
}
});
}
public void disableInHashedDir(HashedDir dir)
{
if(files == null) return;
files.forEach((k,v) -> {
HashedDir.FindRecursiveResult firstPath = dir.findRecursive(k);
firstPath.parent.remove(firstPath.name);
});
}
}

View file

@ -0,0 +1,7 @@
package pro.gravit.launcher.profiles.optional.actions;
import java.util.List;
public class OptionalActionJvmArgs extends OptionalAction {
public List<String> args;
}

View file

@ -9,6 +9,7 @@
import pro.gravit.launcher.events.request.*;
import pro.gravit.launcher.hasher.HashedEntry;
import pro.gravit.launcher.hasher.HashedEntryAdapter;
import pro.gravit.launcher.profiles.optional.actions.OptionalAction;
import pro.gravit.launcher.request.WebSocketEvent;
import pro.gravit.launcher.request.auth.AuthRequest;
import pro.gravit.utils.ProviderMap;
@ -40,6 +41,7 @@ public static void appendTypeAdapters(GsonBuilder builder) {
builder.registerTypeAdapter(WebSocketEvent.class, new UniversalJsonAdapter<>(ClientWebSocketService.results));
builder.registerTypeAdapter(WebSocketRequest.class, new UniversalJsonAdapter<>(ClientWebSocketService.requests));
builder.registerTypeAdapter(AuthRequest.AuthPasswordInterface.class, new UniversalJsonAdapter<>(AuthRequest.providers));
builder.registerTypeAdapter(OptionalAction.class, new UniversalJsonAdapter<>(OptionalAction.providers));
}
private static URI createURL(String address) {

View file

@ -100,6 +100,47 @@ public void removeR(String name) {
}
}
}
public void moveTo(String elementName, HashedDir target, String targetElementName)
{
HashedEntry entry = map.remove(elementName);
target.map.put(targetElementName, entry);
}
public static class FindRecursiveResult
{
public HashedDir parent;
public HashedEntry entry;
public String name;
public FindRecursiveResult(HashedDir parent, HashedEntry entry, String name) {
this.parent = parent;
this.entry = entry;
this.name = name;
}
}
public FindRecursiveResult findRecursive(String path)
{
StringTokenizer t = new StringTokenizer(path, "/");
HashedDir current = this;
HashedEntry entry = null;
String name = null;
while (t.hasMoreTokens()) {
name = t.nextToken();
HashedEntry e = current.map.get(name);
if (e.getType() == Type.DIR) {
if(!t.hasMoreTokens()) {
entry = e;
break;
}
else {
current = ((HashedDir) e);
}
} else {
entry = e;
break;
}
}
return new FindRecursiveResult(current, entry, name);
}
public HashedEntry getEntry(String name) {
return map.get(name);

View file

@ -8,6 +8,7 @@
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.optional.actions.OptionalAction;
import pro.gravit.launcher.request.Request;
import pro.gravit.launcher.request.RequestException;
import pro.gravit.launcher.request.auth.AuthRequest;
@ -115,6 +116,7 @@ public boolean loopAuth(int count, int sleeptime) {
public void run(String... args) throws Throwable {
initGson(modulesManager);
AuthRequest.registerProviders();
OptionalAction.registerProviders();
if (args.length > 0 && args[0].equals("setup") && !disableSetup) {
LogHelper.debug("Read ServerWrapperConfig.json");
loadConfig();