fix game part

This commit is contained in:
Tungstend 2022-10-19 22:07:03 +08:00
parent 25d154f83f
commit d32baadf27
17 changed files with 148 additions and 188 deletions

View File

@ -28,6 +28,7 @@ android {
dependencies {
implementation 'org.nanohttpd:nanohttpd:2.3.1'
implementation 'com.github.steveice10:opennbt:1.4'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.jenkins-ci:constant-pool-scanner:1.2'
implementation 'com.google.code.gson:gson:2.9.0'

View File

@ -47,10 +47,7 @@ public final class Arguments {
}
public Arguments addGameArguments(List<String> gameArguments) {
List<Argument> list = new ArrayList<>();
for (String arg : gameArguments) {
list.add(new StringArgument(arg));
}
List<Argument> list = gameArguments.stream().map(StringArgument::new).collect(Collectors.toList());
return new Arguments(Lang.merge(getGame(), list), getJvm());
}
@ -59,10 +56,7 @@ public final class Arguments {
}
public Arguments addJVMArguments(List<String> jvmArguments) {
List<Argument> list = new ArrayList<>();
for (String arg : jvmArguments) {
list.add(new StringArgument(arg));
}
List<Argument> list = jvmArguments.stream().map(StringArgument::new).collect(Collectors.toList());
return new Arguments(getGame(), Lang.merge(getJvm(), list));
}
@ -78,11 +72,7 @@ public final class Arguments {
}
public static List<String> parseStringArguments(List<String> arguments, Map<String, String> keys) {
List<String> list = new ArrayList<>();
for (String arg : arguments) {
list.addAll(new StringArgument(arg).toString(keys, Collections.emptyMap()));
}
return list;
return arguments.stream().filter(Objects::nonNull).flatMap(str -> new StringArgument(str).toString(keys, Collections.emptyMap()).stream()).collect(Collectors.toList());
}
public static List<String> parseArguments(List<Argument> arguments, Map<String, String> keys) {
@ -90,11 +80,7 @@ public final class Arguments {
}
public static List<String> parseArguments(List<Argument> arguments, Map<String, String> keys, Map<String, Boolean> features) {
List<String> list = new ArrayList<>();
for (Argument arg : arguments) {
list.addAll(arg.toString(keys, Collections.emptyMap()));
}
return list;
return arguments.stream().filter(Objects::nonNull).flatMap(arg -> arg.toString(keys, features).stream()).collect(Collectors.toList());
}
public static final List<Argument> DEFAULT_JVM_ARGUMENTS;

View File

@ -11,6 +11,7 @@ import com.google.gson.JsonSerializer;
import com.google.gson.annotations.JsonAdapter;
import java.lang.reflect.Type;
import java.nio.file.Path;
@JsonAdapter(Artifact.Serializer.class)
public final class Artifact {
@ -100,8 +101,8 @@ public final class Artifact {
public String getPath() { return path; }
public String getPath(String root) {
return root + "/" + path;
public Path getPath(Path root) {
return root.resolve(path);
}
@Override

View File

@ -22,16 +22,16 @@ public final class CompatibilityRule {
this.features = features;
}
public Action getAppliedAction(Map<String, Boolean> supportedFeatures) {
public Optional<Action> getAppliedAction(Map<String, Boolean> supportedFeatures) {
if (os != null && !os.allow())
return null;
return Optional.empty();
if (features != null)
for (Map.Entry<String, Boolean> entry : features.entrySet())
if (!Objects.equals(supportedFeatures.get(entry.getKey()), entry.getValue()))
return null;
return Optional.empty();
return action;
return Optional.ofNullable(action);
}
public static boolean appliesToCurrentEnvironment(Collection<CompatibilityRule> rules) {
@ -44,9 +44,9 @@ public final class CompatibilityRule {
Action action = Action.DISALLOW;
for (CompatibilityRule rule : rules) {
Action thisAction = rule.getAppliedAction(features);
if (thisAction != null)
action = thisAction;
Optional<Action> thisAction = rule.getAppliedAction(features);
if (thisAction.isPresent())
action = thisAction.get();
}
return action == Action.ALLOW;

View File

@ -6,11 +6,11 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// Todo : fix
public final class CrashReportAnalyzer {
private CrashReportAnalyzer() {
@ -142,7 +142,7 @@ public final class CrashReportAnalyzer {
public static String findCrashReport(String log) throws IOException, InvalidPathException {
Matcher matcher = CRASH_REPORT_LOCATION_PATTERN.matcher(log);
if (matcher.find()) {
return FileUtils.readText(matcher.group("location"));
return FileUtils.readText(Paths.get(matcher.group("location")));
} else {
return null;
}

View File

@ -4,6 +4,8 @@ import static com.tungsten.fclcore.util.Logging.LOG;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.MaintainTask;
import com.tungsten.fclcore.download.game.VersionJsonSaveTask;
import com.tungsten.fclcore.event.Event;
import com.tungsten.fclcore.event.EventBus;
import com.tungsten.fclcore.event.GameJsonParseFailedEvent;
@ -15,6 +17,7 @@ import com.tungsten.fclcore.event.RenameVersionEvent;
import com.tungsten.fclcore.game.tlauncher.TLauncherVersion;
import com.tungsten.fclcore.mod.ModManager;
import com.tungsten.fclcore.mod.ModpackConfiguration;
import com.tungsten.fclcore.task.Task;
import com.tungsten.fclcore.util.Lang;
import com.tungsten.fclcore.util.ToStringBuilder;
import com.tungsten.fclcore.util.gson.JsonUtils;
@ -26,6 +29,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@ -40,12 +44,11 @@ import java.util.stream.Stream;
/**
* An implementation of classic Minecraft game repository.
*/
// Todo : fix
public class DefaultGameRepository implements GameRepository {
private File baseDirectory;
protected Map<String, Version> versions;
private ConcurrentHashMap<File, String> gameVersions = new ConcurrentHashMap<>();
private ConcurrentHashMap<File, Optional<String>> gameVersions = new ConcurrentHashMap<>();
public DefaultGameRepository(File baseDirectory) {
this.baseDirectory = baseDirectory;
@ -94,8 +97,8 @@ public class DefaultGameRepository implements GameRepository {
return new File(getLibrariesDirectory(version), lib.getPath());
}
public String getArtifactFile(Version version, Artifact artifact) {
return artifact.getPath(getBaseDirectory() + "/libraries");
public Path getArtifactFile(Version version, Artifact artifact) {
return artifact.getPath(getBaseDirectory().toPath().resolve("libraries"));
}
public GameDirectoryType getGameDirectoryType(String id) {
@ -119,7 +122,7 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public String getGameVersion(Version version) {
public Optional<String> getGameVersion(Version version) {
// This implementation may cause multiple flows against the same version entering
// this function, which is accepted because GameVersion::minecraftVersion should
// be consistent.
@ -127,9 +130,9 @@ public class DefaultGameRepository implements GameRepository {
if (gameVersions.containsKey(versionJar)) {
return gameVersions.get(versionJar);
} else {
String gameVersion = GameVersion.minecraftVersion(versionJar);
Optional<String> gameVersion = GameVersion.minecraftVersion(versionJar);
if (gameVersion == null) {
if (!gameVersion.isPresent()) {
LOG.warning("Cannot find out game version of " + version.getId() + ", primary jar: " + versionJar.toString() + ", jar exists: " + versionJar.exists());
}
@ -220,7 +223,7 @@ public class DefaultGameRepository implements GameRepository {
if (EventBus.EVENT_BUS.fireEvent(new RemoveVersionEvent(this, id)) == Event.Result.DENY)
return false;
if (!versions.containsKey(id))
return FileUtils.deleteDirectoryQuietly(getVersionRoot(id).getAbsolutePath());
return FileUtils.deleteDirectoryQuietly(getVersionRoot(id));
File file = getVersionRoot(id);
if (!file.exists())
return true;
@ -232,15 +235,15 @@ public class DefaultGameRepository implements GameRepository {
try {
versions.remove(id);
// remove json files first to ensure FCL will not recognize this folder as a valid version.
List<File> jsons = FileUtils.listFilesByExtension(removedFile.getAbsolutePath(), "json");
for (File json : jsons) {
if (!json.delete())
LOG.warning("Unable to delete file " + json);
}
// remove json files first to ensure HMCL will not recognize this folder as a valid version.
List<File> jsons = FileUtils.listFilesByExtension(removedFile, "json");
jsons.forEach(f -> {
if (!f.delete())
LOG.warning("Unable to delete file " + f);
});
// remove the version from version list regardless of whether the directory was removed successfully or not.
try {
FileUtils.deleteDirectory(removedFile.getAbsolutePath());
FileUtils.deleteDirectory(removedFile);
} catch (IOException e) {
LOG.log(Level.WARNING, "Unable to remove version folder: " + file, e);
}
@ -306,20 +309,33 @@ public class DefaultGameRepository implements GameRepository {
}
if (!id.equals(version.getId())) {
String from = id;
String to = version.getId();
String fromDir = getVersionRoot(from).getAbsolutePath();
String toDir = getVersionRoot(to).getAbsolutePath();
FileUtils.rename(fromDir, to);
try {
String from = id;
String to = version.getId();
Path fromDir = getVersionRoot(from).toPath();
Path toDir = getVersionRoot(to).toPath();
Files.move(fromDir, toDir);
String fromJson = toDir + "/" + from + ".json";
String fromJar = toDir + "/" + from + ".jar";
String toJsonName = to + ".json";
String toJarName = to + ".jar";
Path fromJson = toDir.resolve(from + ".json");
Path fromJar = toDir.resolve(from + ".jar");
Path toJson = toDir.resolve(to + ".json");
Path toJar = toDir.resolve(to + ".jar");
FileUtils.rename(fromJson, toJsonName);
if (new File(fromJar).exists())
FileUtils.rename(fromJar, toJarName);
try {
Files.move(fromJson, toJson);
if (Files.exists(fromJar))
Files.move(fromJar, toJar);
} catch (IOException e) {
// recovery
Lang.ignoringException(() -> Files.move(toJson, fromJson));
Lang.ignoringException(() -> Files.move(toJar, fromJar));
Lang.ignoringException(() -> Files.move(toDir, fromDir));
throw e;
}
} catch (IOException e) {
LOG.log(Level.WARNING, "Ignoring version " + version.getId() + " because version id does not match folder name " + id + ", and we cannot correct it.", e);
return Stream.empty();
}
}
return Stream.of(version);
@ -360,7 +376,7 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public String getActualAssetDirectory(String version, String assetId) {
public Path getActualAssetDirectory(String version, String assetId) {
try {
return reconstructAssets(version, assetId);
} catch (IOException | JsonParseException e) {
@ -370,16 +386,16 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public String getAssetDirectory(String version, String assetId) {
return getBaseDirectory() + "/assets";
public Path getAssetDirectory(String version, String assetId) {
return getBaseDirectory().toPath().resolve("assets");
}
@Override
public String getAssetObject(String version, String assetId, String name) throws IOException {
public Optional<Path> getAssetObject(String version, String assetId, String name) throws IOException {
try {
AssetObject assetObject = getAssetIndex(version, assetId).getObjects().get(name);
if (assetObject == null) return null;
return getAssetObject(version, assetId, assetObject);
if (assetObject == null) return Optional.empty();
return Optional.of(getAssetObject(version, assetId, assetObject));
} catch (IOException e) {
throw e;
} catch (Exception e) {
@ -388,21 +404,25 @@ public class DefaultGameRepository implements GameRepository {
}
@Override
public String getAssetObject(String version, String assetId, AssetObject obj) {
return getAssetDirectory(version, assetId) + "/objects/" + obj.getLocation();
public Path getAssetObject(String version, String assetId, AssetObject obj) {
return getAssetObject(version, getAssetDirectory(version, assetId), obj);
}
public Path getAssetObject(String version, Path assetDir, AssetObject obj) {
return assetDir.resolve("objects").resolve(obj.getLocation());
}
@Override
public String getIndexFile(String version, String assetId) {
return getAssetDirectory(version, assetId) + "/indexes/" + assetId + ".json";
public Path getIndexFile(String version, String assetId) {
return getAssetDirectory(version, assetId).resolve("indexes").resolve(assetId + ".json");
}
@Override
public String getLoggingObject(String version, String assetId, LoggingInfo loggingInfo) {
return getAssetDirectory(version, assetId) + "/log_configs/" + loggingInfo.getFile().getId();
public Path getLoggingObject(String version, String assetId, LoggingInfo loggingInfo) {
return getAssetDirectory(version, assetId).resolve("log_configs").resolve(loggingInfo.getFile().getId());
}
protected String reconstructAssets(String version, String assetId) throws IOException, JsonParseException {
protected Path reconstructAssets(String version, String assetId) throws IOException, JsonParseException {
Path assetsDir = getAssetDirectory(version, assetId);
Path indexFile = getIndexFile(version, assetId);
Path virtualRoot = assetsDir.resolve("virtual").resolve(assetId);
@ -439,6 +459,15 @@ public class DefaultGameRepository implements GameRepository {
return assetsDir;
}
public Task<Version> saveAsync(Version version) {
this.gameVersions.remove(getVersionJar(version));
if (version.isResolvedPreservingPatches()) {
return new VersionJsonSaveTask(this, MaintainTask.maintainPreservingPatches(this, version));
} else {
return new VersionJsonSaveTask(this, version);
}
}
public boolean isLoaded() {
return versions != null;
}

View File

@ -23,12 +23,7 @@ public final class ExtractRules {
}
public boolean shouldExtract(String path) {
for (String s : exclude) {
if (path.startsWith(s)) {
return false;
}
}
return true;
return exclude.stream().noneMatch(path::startsWith);
}
}

View File

@ -1,5 +1,8 @@
package com.tungsten.fclcore.game;
/**
* Determines where game runs in and game files such as mods.
*/
public enum GameDirectoryType {
/**
* .minecraft

View File

@ -4,10 +4,18 @@ import com.tungsten.fclcore.task.Task;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
/**
* Supports operations on versioning.
*
* Note that game repository will not do any operations which need connection with Internet, if do,
* see {@link com.tungsten.fclcore.download.DependencyManager}
*/
public interface GameRepository extends VersionProvider {
/**
@ -105,7 +113,7 @@ public interface GameRepository extends VersionProvider {
* @param version version
* @return game version, or empty if an error occurred in detection.
*/
String getGameVersion(Version version);
Optional<String> getGameVersion(Version version);
/**
* Detect game version.
@ -116,7 +124,7 @@ public interface GameRepository extends VersionProvider {
* @param versionId id of version
* @return game version, or empty if an error occurred in detection.
*/
default String getGameVersion(String versionId) throws VersionNotFoundException {
default Optional<String> getGameVersion(String versionId) throws VersionNotFoundException {
return getGameVersion(getVersion(versionId));
}
@ -149,7 +157,7 @@ public interface GameRepository extends VersionProvider {
* @param assetId the asset id, you can find it in {@link AssetIndexInfo#getId()} {@link Version#getAssetIndex()}
* @return the actual asset directory
*/
String getActualAssetDirectory(String version, String assetId);
Path getActualAssetDirectory(String version, String assetId);
/**
* Get the asset directory according to the asset id.
@ -158,7 +166,7 @@ public interface GameRepository extends VersionProvider {
* @param assetId the asset id, you can find it in {@link AssetIndexInfo#getId()} {@link Version#getAssetIndex()}
* @return the asset directory
*/
String getAssetDirectory(String version, String assetId);
Path getAssetDirectory(String version, String assetId);
/**
* Get the file that given asset object refers to
@ -169,7 +177,7 @@ public interface GameRepository extends VersionProvider {
* @throws IOException if I/O operation fails.
* @return the file that given asset object refers to
*/
String getAssetObject(String version, String assetId, String name) throws IOException;
Optional<Path> getAssetObject(String version, String assetId, String name) throws IOException;
/**
* Get the file that given asset object refers to
@ -179,7 +187,7 @@ public interface GameRepository extends VersionProvider {
* @param obj the asset object, you can find it in {@link AssetIndex#getObjects()}
* @return the file that given asset object refers to
*/
String getAssetObject(String version, String assetId, AssetObject obj);
Path getAssetObject(String version, String assetId, AssetObject obj);
/**
* Get asset index that assetId represents
@ -196,7 +204,7 @@ public interface GameRepository extends VersionProvider {
* @param version the id of specific version that is relevant to {@code assetId}
* @param assetId the asset id, you can find it in {@link AssetIndexInfo#getId()} {@link Version#getAssetIndex()}
*/
String getIndexFile(String version, String assetId);
Path getIndexFile(String version, String assetId);
/**
* Get logging object
@ -206,7 +214,7 @@ public interface GameRepository extends VersionProvider {
* @param loggingInfo the logging info
* @return the file that loggingInfo refers to
*/
String getLoggingObject(String version, String assetId, LoggingInfo loggingInfo);
Path getLoggingObject(String version, String assetId, LoggingInfo loggingInfo);
default List<String> getClasspath(Version version) {
List<String> classpath = new ArrayList<>();

View File

@ -1,5 +1,6 @@
package com.tungsten.fclcore.game;
import static com.tungsten.fclcore.util.Lang.tryCast;
import static com.tungsten.fclcore.util.Logging.LOG;
import com.google.gson.JsonParseException;
@ -23,18 +24,17 @@ import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
// Todo : fix
public final class GameVersion {
private GameVersion() {
}
private static String getVersionFromJson(File versionJson) {
private static Optional<String> getVersionFromJson(Path versionJson) {
try {
Map<?, ?> version = JsonUtils.fromNonNullJson(FileUtils.readText(versionJson), Map.class);
return (String) version.get("name");
return tryCast(version.get("name"), String.class);
} catch (IOException | JsonParseException e) {
LOG.log(Level.WARNING, "Failed to parse version.json", e);
return null;
return Optional.empty();
}
}
@ -70,9 +70,9 @@ public final class GameVersion {
return Optional.empty();
}
public static String minecraftVersion(File file) {
public static Optional<String> minecraftVersion(File file) {
if (file == null || !file.exists() || !file.isFile() || !file.canRead())
return null;
return Optional.empty();
try (FileSystem gameJar = CompressingUtils.createReadOnlyZipFileSystem(file.toPath())) {
Path versionJson = gameJar.getPath("version.json");

View File

@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// Todo : add and delete some options
public class LaunchOptions implements Serializable {
private File gameDir;
@ -34,7 +33,7 @@ public class LaunchOptions implements Serializable {
private boolean noGeneratedJVMArgs;
private String preLaunchCommand;
private String postExitCommand;
private ProcessPriority processPriority = ProcessPriority.HIGH;
private ProcessPriority processPriority = ProcessPriority.NORMAL;
private boolean daemon;
/**

View File

@ -13,7 +13,11 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
* A class that describes a Minecraft dependency.
*/
public class Library implements Comparable<Library>, Validation {
@SerializedName("name")
@ -108,15 +112,8 @@ public class Library implements Comparable<Library>, Validation {
public LibraryDownloadInfo getDownload() {
LibraryDownloadInfo temp = getRawDownloadInfo();
String path = getPath();
String finalUrl = UrlConstants.DEFAULT_LIBRARY_URL + path;
if (temp != null) {
finalUrl = temp.getUrl();
}
else if (url != null) {
finalUrl = url + path;
}
return new LibraryDownloadInfo(path,
finalUrl,
Optional.ofNullable(temp).map(LibraryDownloadInfo::getUrl).orElse(Optional.ofNullable(url).orElse(UrlConstants.DEFAULT_LIBRARY_URL) + path),
temp != null ? temp.getSha1() : null,
temp != null ? temp.getSize() : 0
);

View File

@ -41,14 +41,12 @@ public class RuledArgument implements Argument {
@Override
public List<String> toString(Map<String, String> keys, Map<String, Boolean> features) {
if (CompatibilityRule.appliesToCurrentEnvironment(rules, features) && value != null) {
List<String> list = new ArrayList<>();
for (String v : value) {
StringArgument stringArgument = new StringArgument(v);
list.add(stringArgument.toString(keys, features).get(0));
}
return list;
}
if (CompatibilityRule.appliesToCurrentEnvironment(rules, features) && value != null)
return value.stream()
.filter(Objects::nonNull)
.map(StringArgument::new)
.map(str -> str.toString(keys, features).get(0))
.collect(Collectors.toList());
return Collections.emptyList();
}

View File

@ -10,7 +10,6 @@ import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -34,7 +33,7 @@ public final class StringArgument implements Argument {
Matcher m = pattern.matcher(argument);
while (m.find()) {
String entry = m.group();
res = res.replace(entry, keys.get(entry) == null ? entry : Objects.requireNonNull(keys.get(entry)));
res = res.replace(entry, keys.getOrDefault(entry, entry));
}
return Collections.singletonList(res);
}

View File

@ -11,7 +11,6 @@ import com.tungsten.fclcore.util.gson.Validation;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@ -20,6 +19,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
@ -98,12 +98,12 @@ public class Version implements Comparable<Version>, Validation {
this.patches = Lang.copyList(patches);
}
public String getMinecraftArguments() {
return minecraftArguments;
public Optional<String> getMinecraftArguments() {
return Optional.ofNullable(minecraftArguments);
}
public Arguments getArguments() {
return arguments;
public Optional<Arguments> getArguments() {
return Optional.ofNullable(arguments);
}
public String getMainClass() {
@ -161,11 +161,11 @@ public class Version implements Comparable<Version>, Validation {
}
public boolean isHidden() {
return hidden;
return hidden == null ? false : hidden;
}
public boolean isRoot() {
return root;
return root == null ? false : root;
}
public boolean isResolved() {
@ -246,7 +246,7 @@ public class Version implements Comparable<Version>, Validation {
type == null ? parent.type : type,
time == null ? parent.time : time,
releaseTime == null ? parent.releaseTime : releaseTime,
Math.max(minimumLauncherVersion, parent.minimumLauncherVersion),
Lang.merge(minimumLauncherVersion, parent.minimumLauncherVersion, Math::max),
hidden,
true,
isPatch ? parent.patches : Lang.merge(Lang.merge(parent.patches, Collections.singleton(toPatch())), patches));
@ -381,22 +381,8 @@ public class Version implements Comparable<Version>, Validation {
}
public Version addPatches(@Nullable List<Version> additional) {
Set<String> patchIds = new HashSet<>();
if (additional != null) {
for (Version v : additional) {
patchIds.add(v.getId());
}
}
List<Version> oldPatches = null;
if (this.patches != null) {
oldPatches = new ArrayList<>();
for (Version v : this.patches) {
if (!patchIds.contains(v.getId())) {
oldPatches.add(v);
}
}
}
List<Version> patches = Lang.merge(oldPatches, additional);
Set<String> patchIds = additional == null ? Collections.emptySet() : additional.stream().map(Version::getId).collect(Collectors.toSet());
List<Version> patches = Lang.merge(this.patches == null ? null : this.patches.stream().filter(patch -> !patchIds.contains(patch.getId())).collect(Collectors.toList()), additional);
return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, complianceLevel, javaVersion, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, patches);
}
@ -405,29 +391,12 @@ public class Version implements Comparable<Version>, Validation {
}
public Version removePatchById(String patchId) {
List<Version> newPatches = null;
if (patches != null) {
newPatches = new ArrayList<>();
for (Version p : patches) {
if (!patchId.equals(p.getId())) {
newPatches.add(p);
}
}
}
return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, complianceLevel, javaVersion, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root, newPatches);
return new Version(resolved, id, version, priority, minecraftArguments, arguments, mainClass, inheritsFrom, jar, assetIndex, assets, complianceLevel, javaVersion, libraries, compatibilityRules, downloads, logging, type, time, releaseTime, minimumLauncherVersion, hidden, root,
patches == null ? null : patches.stream().filter(patch -> !patchId.equals(patch.getId())).collect(Collectors.toList()));
}
public boolean hasPatch(String patchId) {
boolean has = false;
if (patches != null) {
for (Version patch : patches) {
if (patch.getId().equals(patchId)) {
has = true;
break;
}
}
}
return has;
return patches != null && patches.stream().anyMatch(patch -> patchId.equals(patch.getId()));
}
@Override

View File

@ -4,8 +4,10 @@ import com.tungsten.fclcore.util.StringUtils;
import com.tungsten.fclcore.util.platform.CommandBuilder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public final class VersionLibraryBuilder {
private final Version version;
@ -19,9 +21,9 @@ public final class VersionLibraryBuilder {
public VersionLibraryBuilder(Version version) {
this.version = version;
this.libraries = new ArrayList<>(version.getLibraries());
this.mcArgs = version.getMinecraftArguments() != null ? StringUtils.tokenize(version.getMinecraftArguments()) : null;
this.game = new ArrayList<>(version.getArguments().getGame() != null ? version.getArguments().getGame() : Arguments.DEFAULT_GAME_ARGUMENTS);
this.jvm = new ArrayList<>(version.getArguments().getJvm() != null ? version.getArguments().getJvm() : Arguments.DEFAULT_JVM_ARGUMENTS);
this.mcArgs = version.getMinecraftArguments().map(StringUtils::tokenize).map(ArrayList::new).orElse(null);
this.game = version.getArguments().map(Arguments::getGame).map(ArrayList::new).orElseGet(ArrayList::new);
this.jvm = new ArrayList<>(version.getArguments().map(Arguments::getJvm).orElse(Arguments.DEFAULT_JVM_ARGUMENTS));
this.useMcArgs = mcArgs != null;
}
@ -30,38 +32,22 @@ public final class VersionLibraryBuilder {
if (useMcArgs) {
// The official launcher will not parse the "arguments" property when it detects the presence of "mcArgs".
// The "arguments" property with the "rule" is simply ignored here.
for (Argument arg : this.game) {
List<String> argStr = arg.toString(new HashMap<>(), new HashMap<>());
this.mcArgs.addAll(argStr);
}
this.mcArgs.addAll(this.game.stream().map(arg -> arg.toString(new HashMap<>(), new HashMap<>())).flatMap(Collection::stream).collect(Collectors.toList()));
ret = ret.setArguments(null);
// Since $ will be escaped in linux, and our maintain of minecraftArgument will not cause escaping,
// so we regenerate the minecraftArgument without escaping.
ret = ret.setMinecraftArguments(new CommandBuilder().addAllWithoutParsing(mcArgs).toString());
} else {
if (ret.getArguments() != null) {
ret = ret.setArguments(ret.getArguments().withGame(game));
if (jvmChanged) {
ret = ret.setArguments(ret.getArguments().withJvm(jvm));
}
}
else {
ret = ret.setArguments(new Arguments(game, jvmChanged ? jvm : null));
}
ret = ret.setArguments(ret.getArguments()
.map(args -> args.withGame(game))
.map(args -> jvmChanged ? args.withJvm(jvm) : args).orElse(new Arguments(game, jvmChanged ? jvm : null)));
}
return ret.setLibraries(libraries);
}
public boolean hasTweakClass(String tweakClass) {
boolean match = false;
for (Argument argument : game) {
if (argument.toString().equals(tweakClass)) {
match = true;
break;
}
}
return useMcArgs && mcArgs.contains(tweakClass) || match;
return useMcArgs && mcArgs.contains(tweakClass) || game.stream().anyMatch(arg -> arg.toString().equals(tweakClass));
}
public void removeTweakClass(String target) {

View File

@ -1,18 +1,7 @@
package com.tungsten.fclcore.game;
import com.github.steveice10.opennbt.NBTIO;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.LongTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.tungsten.fclcore.util.io.FileUtils;
import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.Unzipper;
import org.jackhuang.hmcl.util.io.Zipper;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;