Try to fix ConcurrentModificationException

This commit is contained in:
huanghongxun 2019-08-25 15:35:17 +08:00
parent 93837a28fa
commit a9feb65fc8
16 changed files with 40 additions and 26 deletions

View File

@ -25,6 +25,7 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.Zipper; import org.jackhuang.hmcl.util.io.Zipper;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -75,7 +76,7 @@ public class HMCLModpackExportTask extends Task<Void> {
Version mv = repository.getResolvedVersion(version); Version mv = repository.getResolvedVersion(version);
String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version)) String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(version))
.orElseThrow(() -> new IllegalStateException("Cannot parse the version of " + version)); .orElseThrow(() -> new IOException("Cannot parse the version of " + version));
zip.putTextFile(JsonUtils.GSON.toJson(mv.setJar(gameVersion)), "minecraft/pack.json"); // Making "jar" to gameVersion is to be compatible with old HMCL. zip.putTextFile(JsonUtils.GSON.toJson(mv.setJar(gameVersion)), "minecraft/pack.json"); // Making "jar" to gameVersion is to be compatible with old HMCL.
zip.putTextFile(JsonUtils.GSON.toJson(modpack.setGameVersion(gameVersion)), "modpack.json"); // Newer HMCL only reads 'gameVersion' field. zip.putTextFile(JsonUtils.GSON.toJson(modpack.setGameVersion(gameVersion)), "modpack.json"); // Newer HMCL only reads 'gameVersion' field.
} }

View File

@ -123,7 +123,7 @@ public final class ModpackHelper {
return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, modpack, ((MultiMCInstanceConfiguration) modpack.getManifest()), name) return new MultiMCModpackInstallTask(profile.getDependency(), zipFile, modpack, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)
.whenComplete(Schedulers.defaultScheduler(), success, failure) .whenComplete(Schedulers.defaultScheduler(), success, failure)
.thenComposeAsync(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name)); .thenComposeAsync(new MultiMCInstallVersionSettingTask(profile, ((MultiMCInstanceConfiguration) modpack.getManifest()), name));
else throw new IllegalStateException("Unrecognized modpack: " + modpack); else throw new IllegalArgumentException("Unrecognized modpack: " + modpack);
} }
public static Task<Void> getUpdateTask(Profile profile, File zipFile, Charset charset, String name, ModpackConfiguration<?> configuration) throws UnsupportedModpackException, MismatchedModpackTypeException { public static Task<Void> getUpdateTask(Profile profile, File zipFile, Charset charset, String name, ModpackConfiguration<?> configuration) throws UnsupportedModpackException, MismatchedModpackTypeException {

View File

@ -18,9 +18,11 @@
package org.jackhuang.hmcl.ui.download; package org.jackhuang.hmcl.ui.download;
import javafx.scene.Node; import javafx.scene.Node;
import org.jackhuang.hmcl.download.DefaultDependencyManager;
import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.DownloadProvider;
import org.jackhuang.hmcl.download.RemoteVersion; import org.jackhuang.hmcl.download.RemoteVersion;
import org.jackhuang.hmcl.download.VersionMismatchException; import org.jackhuang.hmcl.download.VersionMismatchException;
import org.jackhuang.hmcl.download.fabric.FabricInstallTask;
import org.jackhuang.hmcl.download.game.LibraryDownloadException; import org.jackhuang.hmcl.download.game.LibraryDownloadException;
import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask; import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask;
import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.game.Version;
@ -114,9 +116,10 @@ public final class InstallerWizardProvider implements WizardProvider {
} else { } else {
Controllers.dialog(i18n("install.failed.downloading.detail", ((DownloadException) exception).getUrl()) + "\n" + StringUtils.getStackTrace(exception.getCause()), i18n("install.failed.downloading"), MessageType.ERROR, next); Controllers.dialog(i18n("install.failed.downloading.detail", ((DownloadException) exception).getUrl()) + "\n" + StringUtils.getStackTrace(exception.getCause()), i18n("install.failed.downloading"), MessageType.ERROR, next);
} }
} else if (exception instanceof OptiFineInstallTask.UnsupportedOptiFineInstallationException) { } else if (exception instanceof OptiFineInstallTask.UnsupportedOptiFineInstallationException ||
exception instanceof FabricInstallTask.UnsupportedFabricInstallationException) {
Controllers.dialog(i18n("install.failed.optifine_conflict"), i18n("install.failed"), MessageType.ERROR, next); Controllers.dialog(i18n("install.failed.optifine_conflict"), i18n("install.failed"), MessageType.ERROR, next);
} else if (exception instanceof UnsupportedOperationException) { } else if (exception instanceof DefaultDependencyManager.UnsupportedLibraryInstallerException) {
Controllers.dialog(i18n("install.failed.install_online"), i18n("install.failed"), MessageType.ERROR, next); Controllers.dialog(i18n("install.failed.install_online"), i18n("install.failed"), MessageType.ERROR, next);
} else if (exception instanceof VersionMismatchException) { } else if (exception instanceof VersionMismatchException) {
VersionMismatchException e = ((VersionMismatchException) exception); VersionMismatchException e = ((VersionMismatchException) exception);

View File

@ -132,7 +132,7 @@ install.failed.downloading=Failed to install due to some files not downloaded su
install.failed.downloading.detail=Failed to download file: %s install.failed.downloading.detail=Failed to download file: %s
install.failed.downloading.timeout=Download timed out: %s install.failed.downloading.timeout=Download timed out: %s
install.failed.install_online=Unable to recognize what you provided installer file is install.failed.install_online=Unable to recognize what you provided installer file is
install.failed.optifine_conflict=OptiFine and Forge are both installed simultaneously on Minecraft 1.13 install.failed.optifine_conflict=Fabric, OptiFine and Forge are both installed simultaneously on Minecraft 1.13
install.failed.version_mismatch=The library requires game version %s, but actual version is %s. install.failed.version_mismatch=The library requires game version %s, but actual version is %s.
install.installer.choose=Choose a %s version install.installer.choose=Choose a %s version
install.installer.fabric=Fabric install.installer.fabric=Fabric

View File

@ -94,7 +94,7 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
VersionList<?> versionList = getVersionList(libraryId); VersionList<?> versionList = getVersionList(libraryId);
return versionList.loadAsync(gameVersion, getDownloadProvider()) return versionList.loadAsync(gameVersion, getDownloadProvider())
.thenComposeAsync(() -> installLibraryAsync(baseVersion, versionList.getVersion(gameVersion, libraryVersion) .thenComposeAsync(() -> installLibraryAsync(baseVersion, versionList.getVersion(gameVersion, libraryVersion)
.orElseThrow(() -> new IllegalStateException("Remote library " + libraryId + " has no version " + libraryVersion)))); .orElseThrow(() -> new IOException("Remote library " + libraryId + " has no version " + libraryVersion))));
} }
@Override @Override
@ -126,12 +126,15 @@ public class DefaultDependencyManager extends AbstractDependencyManager {
} catch (IOException ignore) { } catch (IOException ignore) {
} }
throw new UnsupportedOperationException("Library cannot be recognized"); throw new UnsupportedLibraryInstallerException();
}) })
.thenApplyAsync(oldVersion::addPatch) .thenApplyAsync(oldVersion::addPatch)
.thenComposeAsync(repository::save); .thenComposeAsync(repository::save);
} }
public static class UnsupportedLibraryInstallerException extends Exception {
}
/** /**
* Remove installed library. * Remove installed library.
* Will try to remove libraries and patches. * Will try to remove libraries and patches.

View File

@ -65,7 +65,7 @@ public final class FabricInstallTask extends Task<Version> {
} }
@Override @Override
public void preExecute() { public void preExecute() throws Exception {
if (!Objects.equals("net.minecraft.client.main.Main", version.resolve(dependencyManager.getGameRepository()).getMainClass())) if (!Objects.equals("net.minecraft.client.main.Main", version.resolve(dependencyManager.getGameRepository()).getMainClass()))
throw new UnsupportedFabricInstallationException(); throw new UnsupportedFabricInstallationException();
} }
@ -128,6 +128,6 @@ public final class FabricInstallTask extends Task<Version> {
return new Version("net.fabricmc", loaderVersion, 30000, arguments, mainClass, libraries); return new Version("net.fabricmc", loaderVersion, 30000, arguments, mainClass, libraries);
} }
public static class UnsupportedFabricInstallationException extends UnsupportedOperationException { public static class UnsupportedFabricInstallationException extends Exception {
} }
} }

View File

@ -38,6 +38,7 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.SystemUtils; import org.jackhuang.hmcl.util.platform.SystemUtils;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.FileSystem; import java.nio.file.FileSystem;
import java.nio.file.Files; import java.nio.file.Files;
@ -233,7 +234,7 @@ public class ForgeNewInstallTask extends Task<Version> {
List<String> args = processor.getArgs().stream().map(arg -> { List<String> args = processor.getArgs().stream().map(arg -> {
String parsed = parseLiteral(arg, data, ExceptionalFunction.identity()); String parsed = parseLiteral(arg, data, ExceptionalFunction.identity());
if (parsed == null) if (parsed == null)
throw new IllegalStateException("Invalid forge installation configuration"); throw new IOException("Invalid forge installation configuration");
return parsed; return parsed;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@ -242,7 +243,7 @@ public class ForgeNewInstallTask extends Task<Version> {
LOG.info("Executing external processor " + processor.getJar().toString() + ", command line: " + new CommandBuilder().addAll(command).toString()); LOG.info("Executing external processor " + processor.getJar().toString() + ", command line: " + new CommandBuilder().addAll(command).toString());
int exitCode = SystemUtils.callExternalProcess(command); int exitCode = SystemUtils.callExternalProcess(command);
if (exitCode != 0) if (exitCode != 0)
throw new IllegalStateException("Game processor exited abnormally"); throw new IOException("Game processor exited abnormally");
for (Map.Entry<String, String> entry : outputs.entrySet()) { for (Map.Entry<String, String> entry : outputs.entrySet()) {
Path artifact = Paths.get(entry.getKey()); Path artifact = Paths.get(entry.getKey());

View File

@ -24,6 +24,7 @@ import org.jackhuang.hmcl.task.GetTask;
import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -61,9 +62,9 @@ public final class VersionJsonDownloadTask extends Task<String> {
} }
@Override @Override
public void execute() { public void execute() throws IOException {
RemoteVersion remoteVersion = gameVersionList.getVersion(gameVersion, gameVersion) RemoteVersion remoteVersion = gameVersionList.getVersion(gameVersion, gameVersion)
.orElseThrow(() -> new IllegalStateException("Cannot find specific version " + gameVersion + " in remote repository")); .orElseThrow(() -> new IOException("Cannot find specific version " + gameVersion + " in remote repository"));
String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl()); String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl());
dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL)).storeTo(this::setResult)); dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL)).storeTo(this::setResult));
} }

View File

@ -149,7 +149,7 @@ public final class OptiFineInstallTask extends Task<Version> {
gameRepository.getLibraryFile(version, optiFineLibrary).toString() gameRepository.getLibraryFile(version, optiFineLibrary).toString()
); );
if (exitCode != 0) if (exitCode != 0)
throw new IllegalStateException("OptiFine patcher failed"); throw new IOException("OptiFine patcher failed");
} else { } else {
FileUtils.copyFile(dest, gameRepository.getLibraryFile(version, optiFineLibrary).toPath()); FileUtils.copyFile(dest, gameRepository.getLibraryFile(version, optiFineLibrary).toPath());
} }
@ -188,7 +188,7 @@ public final class OptiFineInstallTask extends Task<Version> {
dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult())); dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult()));
} }
public static class UnsupportedOptiFineInstallationException extends UnsupportedOperationException { public static class UnsupportedOptiFineInstallationException extends Exception {
} }
/** /**

View File

@ -20,6 +20,7 @@ package org.jackhuang.hmcl.event;
import org.jackhuang.hmcl.util.Logging; import org.jackhuang.hmcl.util.Logging;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* *
@ -27,12 +28,11 @@ import java.util.HashMap;
*/ */
public final class EventBus { public final class EventBus {
private final HashMap<Class<?>, EventManager<?>> events = new HashMap<>(); private final ConcurrentHashMap<Class<?>, EventManager<?>> events = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T extends Event> EventManager<T> channel(Class<T> clazz) { public <T extends Event> EventManager<T> channel(Class<T> clazz) {
if (!events.containsKey(clazz)) events.putIfAbsent(clazz, new EventManager<>());
events.put(clazz, new EventManager<>());
return (EventManager<T>) events.get(clazz); return (EventManager<T>) events.get(clazz);
} }

View File

@ -22,6 +22,7 @@ import org.jackhuang.hmcl.util.SimpleMultimap;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
@ -31,7 +32,7 @@ import java.util.function.Consumer;
public final class EventManager<T extends Event> { public final class EventManager<T extends Event> {
private final SimpleMultimap<EventPriority, Consumer<T>> handlers private final SimpleMultimap<EventPriority, Consumer<T>> handlers
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new); = new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), CopyOnWriteArraySet::new);
public Consumer<T> registerWeak(Consumer<T> consumer) { public Consumer<T> registerWeak(Consumer<T> consumer) {
register(new WeakListener(consumer)); register(new WeakListener(consumer));

View File

@ -54,6 +54,6 @@ public final class AssetObject implements Validation {
@Override @Override
public void validate() throws JsonParseException { public void validate() throws JsonParseException {
if (StringUtils.isBlank(hash) || hash.length() < 2) if (StringUtils.isBlank(hash) || hash.length() < 2)
throw new IllegalStateException("AssetObject hash cannot be blank."); throw new JsonParseException("AssetObject hash cannot be blank.");
} }
} }

View File

@ -91,7 +91,7 @@ public class World {
private void loadFromZipImpl(Path root) throws IOException { private void loadFromZipImpl(Path root) throws IOException {
Path levelDat = root.resolve("level.dat"); Path levelDat = root.resolve("level.dat");
if (!Files.exists(levelDat)) if (!Files.exists(levelDat))
throw new IllegalArgumentException("Not a valid world zip file since level.dat cannot be found."); throw new IOException("Not a valid world zip file since level.dat cannot be found.");
getWorldName(levelDat); getWorldName(levelDat);
} }
@ -116,6 +116,9 @@ public class World {
CompoundTag nbt = parseLevelDat(levelDat); CompoundTag nbt = parseLevelDat(levelDat);
CompoundTag data = nbt.get("Data"); CompoundTag data = nbt.get("Data");
if (data == null)
throw new IOException("level.dat missing Data");
if (data.get("LevelName") instanceof StringTag) if (data.get("LevelName") instanceof StringTag)
worldName = data.<StringTag>get("LevelName").getValue(); worldName = data.<StringTag>get("LevelName").getValue();
else else
@ -209,7 +212,7 @@ public class World {
return Files.list(savesDir).flatMap(world -> { return Files.list(savesDir).flatMap(world -> {
try { try {
return Stream.of(new World(world)); return Stream.of(new World(world));
} catch (IOException | IllegalArgumentException e) { } catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Failed to read world " + world, e); Logging.LOG.log(Level.WARNING, "Failed to read world " + world, e);
return Stream.empty(); return Stream.empty();
} }

View File

@ -27,6 +27,7 @@ import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.Zipper; import org.jackhuang.hmcl.util.io.Zipper;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -80,7 +81,7 @@ public class MultiMCModpackExportTask extends Task<Void> {
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(versionId)); LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(repository.getResolvedPreservingPatchesVersion(versionId));
String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(versionId)) String gameVersion = GameVersion.minecraftVersion(repository.getVersionJar(versionId))
.orElseThrow(() -> new IllegalStateException("Cannot parse the version of " + versionId)); .orElseThrow(() -> new IOException("Cannot parse the version of " + versionId));
List<MultiMCManifest.MultiMCManifestComponent> components = new ArrayList<>(); List<MultiMCManifest.MultiMCManifestComponent> components = new ArrayList<>();
components.add(new MultiMCManifest.MultiMCManifestComponent(true, false, "net.minecraft", gameVersion)); components.add(new MultiMCManifest.MultiMCManifestComponent(true, false, "net.minecraft", gameVersion));
analyzer.getVersion(FORGE).ifPresent(forgeVersion -> analyzer.getVersion(FORGE).ifPresent(forgeVersion ->

View File

@ -292,7 +292,7 @@ public class FileDownloadTask extends Task<Void> {
} }
if (downloaded != contentLength) if (downloaded != contentLength)
throw new IllegalStateException("Unexpected file size: " + downloaded + ", expected: " + contentLength); throw new IOException("Unexpected file size: " + downloaded + ", expected: " + contentLength);
// Integrity check // Integrity check
if (integrityCheck != null) { if (integrityCheck != null) {
@ -312,7 +312,7 @@ public class FileDownloadTask extends Task<Void> {
} }
return; return;
} catch (IOException | IllegalStateException e) { } catch (IOException e) {
if (temp != null) if (temp != null)
temp.toFile().delete(); temp.toFile().delete();
exception = e; exception = e;

View File

@ -64,7 +64,7 @@ public final class TaskExecutor {
Logging.LOG.log(Level.WARNING, "An exception occurred in task execution", exception); Logging.LOG.log(Level.WARNING, "An exception occurred in task execution", exception);
Throwable resolvedException = resolveException(exception); Throwable resolvedException = resolveException(exception);
if (resolvedException instanceof RuntimeException) { if (resolvedException instanceof RuntimeException && !(resolvedException instanceof CancellationException)) {
// Track uncaught RuntimeException which are thrown mostly by our mistake // Track uncaught RuntimeException which are thrown mostly by our mistake
if (uncaughtExceptionHandler != null) if (uncaughtExceptionHandler != null)
uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), resolvedException); uncaughtExceptionHandler.uncaughtException(Thread.currentThread(), resolvedException);