1
0
mirror of https://github.com/SKCraft/Launcher.git synced 2025-01-07 19:29:03 +01:00

Update launcher/runner component to new models

- Fix game arguments being missing from version manifest due to new format
- Update Runner to use more substitutions & support new argument model
- Move loader/installer libraries to their own section to avoid runtime conflicts
- Implement some basic feature matching for arguments
This commit is contained in:
Henry Le Grys 2020-12-01 23:41:55 +00:00
parent 410031a86f
commit 86247c98a9
20 changed files with 330 additions and 108 deletions

View File

@ -11,6 +11,7 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.server.handler.gzip.GzipHandler;
@ -72,6 +73,8 @@ public class TestServerBuilder {
server.setHandler(gzip); server.setHandler(gzip);
gzip.setHandler(contexts); gzip.setHandler(contexts);
server.addBean(new ErrorHandler());
return new TestServer(server); return new TestServer(server);
} }

View File

@ -12,8 +12,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.ObjectWriter;
import com.google.common.base.Joiner; import com.google.common.collect.Iterables;
import com.google.common.base.Strings;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams; import com.google.common.io.CharStreams;
@ -25,10 +24,7 @@ import com.skcraft.launcher.model.loader.InstallProfile;
import com.skcraft.launcher.model.loader.LoaderManifest; import com.skcraft.launcher.model.loader.LoaderManifest;
import com.skcraft.launcher.model.loader.SidedData; import com.skcraft.launcher.model.loader.SidedData;
import com.skcraft.launcher.model.loader.VersionInfo; import com.skcraft.launcher.model.loader.VersionInfo;
import com.skcraft.launcher.model.minecraft.Library; import com.skcraft.launcher.model.minecraft.*;
import com.skcraft.launcher.model.minecraft.ReleaseList;
import com.skcraft.launcher.model.minecraft.Version;
import com.skcraft.launcher.model.minecraft.VersionManifest;
import com.skcraft.launcher.model.modpack.DownloadableFile; import com.skcraft.launcher.model.modpack.DownloadableFile;
import com.skcraft.launcher.model.modpack.Manifest; import com.skcraft.launcher.model.modpack.Manifest;
import com.skcraft.launcher.util.Environment; import com.skcraft.launcher.util.Environment;
@ -75,6 +71,7 @@ public class PackageBuilder {
private File baseDir; private File baseDir;
private List<Library> loaderLibraries = Lists.newArrayList(); private List<Library> loaderLibraries = Lists.newArrayList();
private List<Library> installerLibraries = Lists.newArrayList();
private List<String> mavenRepos; private List<String> mavenRepos;
private List<URL> jarMavens = Lists.newArrayList(); private List<URL> jarMavens = Lists.newArrayList();
@ -176,12 +173,9 @@ public class PackageBuilder {
} }
// Copy tweak class arguments // Copy tweak class arguments
List<String> gameArguments = info.getMinecraftArguments().getGameArguments(); List<GameArgument> gameArguments = info.getMinecraftArguments().getGameArguments();
if (gameArguments != null) { if (gameArguments != null) {
String args = Joiner.on(' ').join(gameArguments); version.getArguments().getGameArguments().addAll(gameArguments);
String existingArgs = Strings.nullToEmpty(version.getMinecraftArguments());
version.setMinecraftArguments(Joiner.on(' ').join(existingArgs, args));
} }
// Add libraries // Add libraries
@ -213,7 +207,7 @@ public class PackageBuilder {
InstallProfile profile = mapper.readValue(data, InstallProfile.class); InstallProfile profile = mapper.readValue(data, InstallProfile.class);
// Import the libraries for the installer // Import the libraries for the installer
loaderLibraries.addAll(profile.getLibraries()); installerLibraries.addAll(profile.getLibraries());
// Extract the data files // Extract the data files
List<DownloadableFile> extraFiles = Lists.newArrayList(); List<DownloadableFile> extraFiles = Lists.newArrayList();
@ -243,7 +237,7 @@ public class PackageBuilder {
profile.getData().put("SIDE", SidedData.create("client", "server")); profile.getData().put("SIDE", SidedData.create("client", "server"));
// Add loader manifest to the map // Add loader manifest to the map
manifest.getLoaders().put(loaderName, new LoaderManifest(profile.getData(), extraFiles)); manifest.getLoaders().put(loaderName, new LoaderManifest(profile.getLibraries(), profile.getData(), extraFiles));
// Add processors // Add processors
manifest.getTasks().addAll(profile.toProcessorEntries(loaderName)); manifest.getTasks().addAll(profile.toProcessorEntries(loaderName));
@ -266,7 +260,7 @@ public class PackageBuilder {
// TODO: Download libraries for different environments -- As of writing, this is not an issue // TODO: Download libraries for different environments -- As of writing, this is not an issue
Environment env = Environment.getInstance(); Environment env = Environment.getInstance();
for (Library library : loaderLibraries) { for (Library library : Iterables.concat(loaderLibraries, installerLibraries)) {
Library.Artifact artifact = library.getArtifact(env); Library.Artifact artifact = library.getArtifact(env);
File outputPath = new File(librariesDir, artifact.getPath()); File outputPath = new File(librariesDir, artifact.getPath());

View File

@ -137,6 +137,15 @@ public final class Launcher {
} }
} }
/**
* Get the launcher title.
*
* @return The launcher title.
*/
public String getTitle() {
return tr("launcher.appTitle");
}
/** /**
* Get the launcher version. * Get the launcher version.
* *

View File

@ -52,7 +52,7 @@ public class ProcessorTask implements InstallTask {
Map<String, String> outputs = processor.resolveOutputs(resolver); Map<String, String> outputs = processor.resolveOutputs(resolver);
message = "Finding libraries"; message = "Finding libraries";
Library execFile = versionManifest.findLibrary(processor.getJar()); Library execFile = loaderManifest.findLibrary(processor.getJar());
File jar = launcher.getLibraryFile(execFile); File jar = launcher.getLibraryFile(execFile);
JarFile jarFile = new JarFile(jar); JarFile jarFile = new JarFile(jar);
@ -68,7 +68,7 @@ public class ProcessorTask implements InstallTask {
int total = processor.getClasspath().size(); int total = processor.getClasspath().size();
for (String libraryName : processor.getClasspath()) { for (String libraryName : processor.getClasspath()) {
message = "Adding library " + libraryName; message = "Adding library " + libraryName;
File libraryFile = launcher.getLibraryFile(versionManifest.findLibrary(libraryName)); File libraryFile = launcher.getLibraryFile(loaderManifest.findLibrary(libraryName));
if (!libraryFile.exists()) { if (!libraryFile.exists()) {
throw new RuntimeException(String.format("Missing library '%s' for processor '%s'", throw new RuntimeException(String.format("Missing library '%s' for processor '%s'",
libraryName, processor.getJar())); libraryName, processor.getJar()));

View File

@ -106,9 +106,6 @@ public class JavaProcessBuilder {
command.add("-XX:MaxPermSize=" + String.valueOf(permGen) + "M"); command.add("-XX:MaxPermSize=" + String.valueOf(permGen) + "M");
} }
command.add("-cp");
command.add(buildClassPath());
command.add(mainClass); command.add(mainClass);
for (String arg : args) { for (String arg : args) {

View File

@ -15,9 +15,7 @@ import com.skcraft.concurrency.ProgressObservable;
import com.skcraft.launcher.*; import com.skcraft.launcher.*;
import com.skcraft.launcher.auth.Session; import com.skcraft.launcher.auth.Session;
import com.skcraft.launcher.install.ZipExtract; import com.skcraft.launcher.install.ZipExtract;
import com.skcraft.launcher.model.minecraft.AssetsIndex; import com.skcraft.launcher.model.minecraft.*;
import com.skcraft.launcher.model.minecraft.Library;
import com.skcraft.launcher.model.minecraft.VersionManifest;
import com.skcraft.launcher.persistence.Persistence; import com.skcraft.launcher.persistence.Persistence;
import com.skcraft.launcher.util.Environment; import com.skcraft.launcher.util.Environment;
import com.skcraft.launcher.util.Platform; import com.skcraft.launcher.util.Platform;
@ -60,6 +58,7 @@ public class Runner implements Callable<Process>, ProgressObservable {
private Configuration config; private Configuration config;
private JavaProcessBuilder builder; private JavaProcessBuilder builder;
private AssetsRoot assetsRoot; private AssetsRoot assetsRoot;
private FeatureList.Mutable featureList;
/** /**
* Create a new instance launcher. * Create a new instance launcher.
@ -75,6 +74,7 @@ public class Runner implements Callable<Process>, ProgressObservable {
this.instance = instance; this.instance = instance;
this.session = session; this.session = session;
this.extractDir = extractDir; this.extractDir = extractDir;
this.featureList = new FeatureList.Mutable();
} }
/** /**
@ -132,12 +132,12 @@ public class Runner implements Callable<Process>, ProgressObservable {
progress = new DefaultProgress(0.9, SharedLocale.tr("runner.collectingArgs")); progress = new DefaultProgress(0.9, SharedLocale.tr("runner.collectingArgs"));
addJvmArgs(); addWindowArgs();
addLibraries(); addLibraries();
addJvmArgs();
addJarArgs(); addJarArgs();
addProxyArgs(); addProxyArgs();
addServerArgs(); addServerArgs();
addWindowArgs();
addPlatformArgs(); addPlatformArgs();
addLegacyArgs(); addLegacyArgs();
@ -175,11 +175,6 @@ public class Runner implements Callable<Process>, ProgressObservable {
builder.getFlags().add("-Xdock:name=Minecraft"); builder.getFlags().add("-Xdock:name=Minecraft");
} }
} }
// Windows arguments
if (getEnvironment().getPlatform() == Platform.WINDOWS) {
builder.getFlags().add("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump");
}
} }
/** /**
@ -210,8 +205,6 @@ public class Runner implements Callable<Process>, ProgressObservable {
tr("runner.missingLibrary", instance.getTitle(), library.getName())); tr("runner.missingLibrary", instance.getTitle(), library.getName()));
} }
} }
builder.getFlags().add("-Djava.library.path=" + extractDir.getAbsoluteFile());
} }
/** /**
@ -253,14 +246,22 @@ public class Runner implements Callable<Process>, ProgressObservable {
builder.tryJvmPath(new File(rawJvmPath)); builder.tryJvmPath(new File(rawJvmPath));
} }
List<String> flags = builder.getFlags();
String rawJvmArgs = config.getJvmArgs(); String rawJvmArgs = config.getJvmArgs();
if (!Strings.isNullOrEmpty(rawJvmArgs)) { if (!Strings.isNullOrEmpty(rawJvmArgs)) {
List<String> flags = builder.getFlags();
for (String arg : JavaProcessBuilder.splitArgs(rawJvmArgs)) { for (String arg : JavaProcessBuilder.splitArgs(rawJvmArgs)) {
flags.add(arg); flags.add(arg);
} }
} }
List<GameArgument> javaArguments = versionManifest.getArguments().getJvmArguments();
StrSubstitutor substitutor = new StrSubstitutor(getCommandSubstitutions());
for (GameArgument arg : javaArguments) {
if (arg.resolveRules(environment, featureList)) {
flags.add(substitutor.replace(arg.getJoinedValue()));
}
}
} }
/** /**
@ -271,10 +272,12 @@ public class Runner implements Callable<Process>, ProgressObservable {
private void addJarArgs() throws JsonProcessingException { private void addJarArgs() throws JsonProcessingException {
List<String> args = builder.getArgs(); List<String> args = builder.getArgs();
String[] rawArgs = versionManifest.getMinecraftArguments().split(" +"); List<GameArgument> rawArgs = versionManifest.getArguments().getGameArguments();
StrSubstitutor substitutor = new StrSubstitutor(getCommandSubstitutions()); StrSubstitutor substitutor = new StrSubstitutor(getCommandSubstitutions());
for (String arg : rawArgs) { for (GameArgument arg : rawArgs) {
args.add(substitutor.replace(arg)); if (arg.resolveRules(environment, featureList)) {
args.add(substitutor.replace(arg.getJoinedValue()));
}
} }
} }
@ -329,15 +332,10 @@ public class Runner implements Callable<Process>, ProgressObservable {
* Add window arguments. * Add window arguments.
*/ */
private void addWindowArgs() { private void addWindowArgs() {
List<String> args = builder.getArgs();
int width = config.getWindowWidth(); int width = config.getWindowWidth();
int height = config.getWidowHeight();
if (width >= 10) { if (width >= 10) {
args.add("--width"); featureList.addFeature("has_custom_resolution", true);
args.add(String.valueOf(width));
args.add("--height");
args.add(String.valueOf(height));
} }
} }
@ -373,6 +371,14 @@ public class Runner implements Callable<Process>, ProgressObservable {
map.put("assets_root", launcher.getAssets().getDir().getAbsolutePath()); map.put("assets_root", launcher.getAssets().getDir().getAbsolutePath());
map.put("assets_index_name", versionManifest.getAssetId()); map.put("assets_index_name", versionManifest.getAssetId());
map.put("resolution_width", String.valueOf(config.getWindowWidth()));
map.put("resolution_height", String.valueOf(config.getWidowHeight()));
map.put("launcher_name", launcher.getTitle());
map.put("launcher_version", launcher.getVersion());
map.put("classpath", builder.buildClassPath());
map.put("natives_directory", extractDir.getAbsolutePath());
return map; return map;
} }

View File

@ -1,5 +1,6 @@
package com.skcraft.launcher.model.loader; package com.skcraft.launcher.model.loader;
import com.skcraft.launcher.model.minecraft.Library;
import com.skcraft.launcher.model.modpack.DownloadableFile; import com.skcraft.launcher.model.modpack.DownloadableFile;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@ -12,6 +13,17 @@ import java.util.Map;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public class LoaderManifest { public class LoaderManifest {
private List<Library> libraries;
private Map<String, SidedData> sidedData; private Map<String, SidedData> sidedData;
private List<DownloadableFile> downloadableFiles; private List<DownloadableFile> downloadableFiles;
public Library findLibrary(String name) {
for (Library library : getLibraries()) {
if (library.getName().equals(name)) {
return library;
}
}
return null;
}
} }

View File

@ -2,7 +2,6 @@ package com.skcraft.launcher.model.loader;
import com.skcraft.launcher.model.minecraft.Library; import com.skcraft.launcher.model.minecraft.Library;
import com.skcraft.launcher.model.minecraft.Side; import com.skcraft.launcher.model.minecraft.Side;
import com.skcraft.launcher.model.minecraft.VersionManifest;
import com.skcraft.launcher.model.modpack.DownloadableFile; import com.skcraft.launcher.model.modpack.DownloadableFile;
import com.skcraft.launcher.model.modpack.Manifest; import com.skcraft.launcher.model.modpack.Manifest;
import com.skcraft.launcher.util.Environment; import com.skcraft.launcher.util.Environment;
@ -30,8 +29,6 @@ public class LoaderSubResolver {
} }
public String transform(String arg) { public String transform(String arg) {
VersionManifest version = manifest.getVersionManifest();
while (true) { while (true) {
char start = arg.charAt(0); char start = arg.charAt(0);
int bound = arg.length() - 1; int bound = arg.length() - 1;
@ -44,7 +41,7 @@ public class LoaderSubResolver {
} }
} else if (start == '[' && end == ']') { } else if (start == '[' && end == ']') {
String libraryName = arg.substring(1, bound); String libraryName = arg.substring(1, bound);
Library library = version.findLibrary(libraryName); Library library = loader.findLibrary(libraryName);
if (library != null) { if (library != null) {
arg = getPathOf(manifest.getLibrariesLocation(), library.getPath(env)); arg = getPathOf(manifest.getLibrariesLocation(), library.getPath(env));
} else { } else {

View File

@ -0,0 +1,32 @@
package com.skcraft.launcher.model.minecraft;
import com.google.common.collect.Maps;
import lombok.NoArgsConstructor;
import java.util.Map;
/**
* List of enabled features for Minecraft feature rules.
*/
@NoArgsConstructor
public class FeatureList {
protected Map<String, Boolean> features = Maps.newHashMap();
public boolean doesMatch(Map<String, Boolean> features) {
for (Map.Entry<String, Boolean> entry : features.entrySet()) {
if (!entry.getValue().equals(this.features.get(entry.getKey()))) {
return false;
}
}
return true;
}
public static class Mutable extends FeatureList {
public void addFeature(String key, boolean value) {
features.put(key, value);
}
}
public static final FeatureList EMPTY = new FeatureList();
}

View File

@ -0,0 +1,51 @@
package com.skcraft.launcher.model.minecraft;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.skcraft.launcher.model.minecraft.mapper.ArgumentValueDeserializer;
import com.skcraft.launcher.util.Environment;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
@NoArgsConstructor
public class GameArgument {
@JsonProperty("value")
@JsonDeserialize(using = ArgumentValueDeserializer.class)
private List<String> values;
private List<Rule> rules;
public GameArgument(List<String> values) {
this.values = values;
}
public GameArgument(String value) {
this.values = Lists.newArrayList(value);
}
@JsonIgnore
public String getJoinedValue() {
return Joiner.on(' ').join(values);
}
public boolean resolveRules(Environment environment, FeatureList featureList) {
if (getRules() == null) return true;
boolean result = false;
for (Rule rule : rules) {
if (rule.matches(environment, featureList)) {
result = rule.isAllowed();
}
}
return result;
}
}

View File

@ -6,12 +6,7 @@
package com.skcraft.launcher.model.minecraft; package com.skcraft.launcher.model.minecraft;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.skcraft.launcher.util.Environment; import com.skcraft.launcher.util.Environment;
@ -20,7 +15,6 @@ import lombok.Data;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Pattern;
@Data @Data
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
@ -43,8 +37,8 @@ public class Library {
if (getRules() != null) { if (getRules() != null) {
for (Rule rule : getRules()) { for (Rule rule : getRules()) {
if (rule.matches(environment)) { if (rule.matches(environment, FeatureList.EMPTY)) {
allow = rule.getAction() == Action.ALLOW; allow = rule.isAllowed();
} }
} }
} else { } else {
@ -95,6 +89,10 @@ public class Library {
if (name != null ? !name.equals(library.name) : library.name != null) if (name != null ? !name.equals(library.name) : library.name != null)
return false; return false;
// If libraries have different natives lists, they should be separate.
if (natives != null ? !natives.equals(library.natives) : library.natives != null)
return false;
return true; return true;
} }
@ -103,38 +101,6 @@ public class Library {
return name != null ? name.hashCode() : 0; return name != null ? name.hashCode() : 0;
} }
@Data
public static class Rule {
private Action action;
private OS os;
public boolean matches(Environment environment) {
if (getOs() == null) {
return true;
} else {
return getOs().matches(environment);
}
}
}
@Data
public static class OS {
private Platform platform;
private Pattern version;
@JsonProperty("name")
@JsonDeserialize(using = PlatformDeserializer.class)
@JsonSerialize(using = PlatformSerializer.class)
public Platform getPlatform() {
return platform;
}
public boolean matches(Environment environment) {
return (getPlatform() == null || getPlatform().equals(environment.getPlatform())) &&
(getVersion() == null || getVersion().matcher(environment.getPlatformVersion()).matches());
}
}
@Data @Data
public static class Extract { public static class Extract {
private List<String> exclude; private List<String> exclude;
@ -155,21 +121,6 @@ public class Library {
private Map<String, Artifact> classifiers; private Map<String, Artifact> classifiers;
} }
private enum Action {
ALLOW,
DISALLOW;
@JsonCreator
public static Action fromJson(String text) {
return valueOf(text.toUpperCase());
}
@JsonValue
public String toJson() {
return name().toLowerCase();
}
}
public static String mavenNameToPath(String mavenName) { public static String mavenNameToPath(String mavenName) {
List<String> split = Splitter.on(':').splitToList(mavenName); List<String> split = Splitter.on(':').splitToList(mavenName);
int size = split.size(); int size = split.size();

View File

@ -2,6 +2,9 @@ package com.skcraft.launcher.model.minecraft;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.skcraft.launcher.model.minecraft.mapper.MinecraftArgumentsDeserializer;
import lombok.Data; import lombok.Data;
import java.util.List; import java.util.List;
@ -10,6 +13,13 @@ import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class MinecraftArguments { public class MinecraftArguments {
@JsonProperty("game") @JsonProperty("game")
private List<String> gameArguments; @JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonDeserialize(contentUsing = MinecraftArgumentsDeserializer.class)
private List<GameArgument> gameArguments;
@JsonProperty("jvm")
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
@JsonDeserialize(contentUsing = MinecraftArgumentsDeserializer.class)
private List<GameArgument> jvmArguments;
} }

View File

@ -0,0 +1,77 @@
package com.skcraft.launcher.model.minecraft;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.skcraft.launcher.model.minecraft.mapper.PlatformDeserializer;
import com.skcraft.launcher.model.minecraft.mapper.PlatformSerializer;
import com.skcraft.launcher.util.Environment;
import com.skcraft.launcher.util.Platform;
import lombok.Data;
import java.util.Map;
import java.util.regex.Pattern;
@Data
public class Rule {
private Action action;
private OS os;
private Map<String, Boolean> features;
private boolean doesOsMatch(Environment environment) {
if (getOs() == null) {
return true;
} else {
return getOs().matches(environment);
}
}
private boolean doFeaturesMatch(FeatureList match) {
if (getFeatures() == null) return true;
return match.doesMatch(features);
}
public boolean matches(Environment environment, FeatureList match) {
return doesOsMatch(environment) && doFeaturesMatch(match);
}
@JsonIgnore
public boolean isAllowed() {
return action == Action.ALLOW;
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public static class OS {
private Platform platform;
private Pattern version;
@JsonProperty("name")
@JsonDeserialize(using = PlatformDeserializer.class)
@JsonSerialize(using = PlatformSerializer.class)
public Platform getPlatform() {
return platform;
}
public boolean matches(Environment environment) {
return (getPlatform() == null || getPlatform().equals(environment.getPlatform())) &&
(getVersion() == null || getVersion().matcher(environment.getPlatformVersion()).matches());
}
}
public enum Action {
ALLOW,
DISALLOW;
@JsonCreator
public static Action fromJson(String text) {
return valueOf(text.toUpperCase());
}
@JsonValue
public String toJson() {
return name().toLowerCase();
}
}
}

View File

@ -8,6 +8,7 @@ package com.skcraft.launcher.model.minecraft;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Splitter;
import lombok.Data; import lombok.Data;
import java.util.Date; import java.util.Date;
@ -25,8 +26,7 @@ public class VersionManifest {
private String assets; private String assets;
private AssetIndex assetIndex; private AssetIndex assetIndex;
private String type; private String type;
private String processArguments; private MinecraftArguments arguments;
private String minecraftArguments;
private String mainClass; private String mainClass;
private int minimumLauncherVersion; private int minimumLauncherVersion;
private LinkedHashSet<Library> libraries; private LinkedHashSet<Library> libraries;
@ -48,6 +48,15 @@ public class VersionManifest {
return null; return null;
} }
public void setMinecraftArguments(String minecraftArguments) {
for (String arg : Splitter.on(' ').split(minecraftArguments)) {
this.arguments.getGameArguments().add(new GameArgument(arg));
}
// TODO: Possibly do some cheaty side-effects here to add parameters missing from early game versions.
// Either that or use a proper version adapter.
}
@Data @Data
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public static class Artifact { public static class Artifact {

View File

@ -0,0 +1,35 @@
package com.skcraft.launcher.model.minecraft.mapper;
import com.beust.jcommander.internal.Lists;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.type.TypeFactory;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class ArgumentValueDeserializer extends StdDeserializer<List<String>> {
protected ArgumentValueDeserializer() {
super(TypeFactory.defaultInstance().constructCollectionType(List.class, String.class));
}
@Override
public List<String> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
if (!jp.hasCurrentToken()) jp.nextToken();
if (jp.getCurrentToken() == JsonToken.START_ARRAY) {
String[] allValues = jp.readValueAs(String[].class);
return Arrays.asList(allValues);
} else if (jp.getCurrentToken() == JsonToken.VALUE_STRING) {
String value = jp.readValueAs(String.class);
return Lists.newArrayList(value);
}
throw new InvalidFormatException("Invalid JSON type for deserializer (not string or array)", null, List.class);
}
}

View File

@ -0,0 +1,31 @@
package com.skcraft.launcher.model.minecraft.mapper;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.skcraft.launcher.model.minecraft.GameArgument;
import java.io.IOException;
public class MinecraftArgumentsDeserializer extends StdDeserializer<GameArgument> {
protected MinecraftArgumentsDeserializer() {
super(GameArgument.class);
}
@Override
public GameArgument deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
if (!jp.hasCurrentToken()) jp.nextToken();
if (jp.getCurrentToken() == JsonToken.START_OBJECT) {
return jp.readValueAs(GameArgument.class);
} else if (jp.getCurrentToken() == JsonToken.VALUE_STRING) {
String argument = jp.getValueAsString();
return new GameArgument(argument);
}
throw new InvalidFormatException("Invalid JSON type for deserializer (not string or object)", null, GameArgument.class);
}
}

View File

@ -4,7 +4,7 @@
* Please see LICENSE.txt for license information. * Please see LICENSE.txt for license information.
*/ */
package com.skcraft.launcher.model.minecraft; package com.skcraft.launcher.model.minecraft.mapper;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationContext;

View File

@ -4,7 +4,7 @@
* Please see LICENSE.txt for license information. * Please see LICENSE.txt for license information.
*/ */
package com.skcraft.launcher.model.minecraft; package com.skcraft.launcher.model.minecraft.mapper;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;

View File

@ -7,6 +7,7 @@
package com.skcraft.launcher.update; package com.skcraft.launcher.update;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.skcraft.launcher.AssetsRoot; import com.skcraft.launcher.AssetsRoot;
import com.skcraft.launcher.Instance; import com.skcraft.launcher.Instance;
import com.skcraft.launcher.Launcher; import com.skcraft.launcher.Launcher;
@ -14,6 +15,7 @@ import com.skcraft.launcher.LauncherException;
import com.skcraft.launcher.dialog.FeatureSelectionDialog; import com.skcraft.launcher.dialog.FeatureSelectionDialog;
import com.skcraft.launcher.dialog.ProgressDialog; import com.skcraft.launcher.dialog.ProgressDialog;
import com.skcraft.launcher.install.*; import com.skcraft.launcher.install.*;
import com.skcraft.launcher.model.loader.LoaderManifest;
import com.skcraft.launcher.model.minecraft.Asset; import com.skcraft.launcher.model.minecraft.Asset;
import com.skcraft.launcher.model.minecraft.AssetsIndex; import com.skcraft.launcher.model.minecraft.AssetsIndex;
import com.skcraft.launcher.model.minecraft.Library; import com.skcraft.launcher.model.minecraft.Library;
@ -201,11 +203,17 @@ public abstract class BaseUpdater {
} }
protected void installLibraries(@NonNull Installer installer, protected void installLibraries(@NonNull Installer installer,
@NonNull VersionManifest versionManifest, @NonNull Manifest manifest,
@NonNull File librariesDir, @NonNull File librariesDir,
@NonNull List<URL> sources) throws InterruptedException { @NonNull List<URL> sources) throws InterruptedException {
VersionManifest versionManifest = manifest.getVersionManifest();
for (Library library : versionManifest.getLibraries()) { Iterable<Library> allLibraries = versionManifest.getLibraries();
for (LoaderManifest loader : manifest.getLoaders().values()) {
allLibraries = Iterables.concat(allLibraries, loader.getLibraries());
}
for (Library library : allLibraries) {
if (library.matches(environment)) { if (library.matches(environment)) {
checkInterrupted(); checkInterrupted();

View File

@ -166,7 +166,7 @@ public class Updater extends BaseUpdater implements Callable<Instance>, Progress
} }
progress = new DefaultProgress(-1, SharedLocale.tr("instanceUpdater.collectingLibraries")); progress = new DefaultProgress(-1, SharedLocale.tr("instanceUpdater.collectingLibraries"));
installLibraries(installer, version, launcher.getLibrariesDir(), librarySources); installLibraries(installer, manifest, launcher.getLibrariesDir(), librarySources);
// Download assets // Download assets
log.info("Enumerating assets to download..."); log.info("Enumerating assets to download...");