Make background transparent?
This commit is contained in:
@@ -28,11 +28,11 @@ public abstract class Account {
|
||||
|
||||
public abstract String getUsername();
|
||||
|
||||
public AuthInfo logIn() throws AuthenticationException {
|
||||
return logIn(Proxy.NO_PROXY);
|
||||
public AuthInfo logIn(MultiCharacterSelector selector) throws AuthenticationException {
|
||||
return logIn(selector, Proxy.NO_PROXY);
|
||||
}
|
||||
|
||||
public abstract AuthInfo logIn(Proxy proxy) throws AuthenticationException;
|
||||
public abstract AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException;
|
||||
|
||||
public abstract void logOut();
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This interface is for your application to open a GUI for user to choose the character
|
||||
* when a having-multi-character yggdrasil account is being logging in..
|
||||
*/
|
||||
public interface MultiCharacterSelector {
|
||||
|
||||
/**
|
||||
* Select one of {@code names} GameProfiles to login.
|
||||
* @param names available game profiles.
|
||||
* @throws NoSelectedCharacterException if cannot select any character may because user close the selection window or cancel the selection.
|
||||
* @return your choice of game profile.
|
||||
*/
|
||||
GameProfile select(Account account, List<GameProfile> names) throws NoSelectedCharacterException;
|
||||
|
||||
MultiCharacterSelector DEFAULT = (account, names) -> names.stream().findFirst().orElseThrow(() -> new NoSelectedCharacterException(account));
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
/**
|
||||
* This exception gets threw when authenticating a yggdrasil account and there is no valid character.
|
||||
* (A account may hold more than one characters.)
|
||||
*/
|
||||
public final class NoCharacterException extends AuthenticationException {
|
||||
private final Account account;
|
||||
|
||||
public NoCharacterException(Account account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
/**
|
||||
* This exception gets threw when a monitor of {@link MultiCharacterSelector} cannot select a
|
||||
* valid character.
|
||||
*
|
||||
* @see org.jackhuang.hmcl.auth.MultiCharacterSelector
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class NoSelectedCharacterException extends AuthenticationException {
|
||||
private final Account account;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param account the error yggdrasil account.
|
||||
*/
|
||||
public NoSelectedCharacterException(Account account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class OfflineAccount extends Account {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo logIn(Proxy proxy) throws AuthenticationException {
|
||||
public AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException {
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(uuid))
|
||||
throw new AuthenticationException("Username cannot be empty");
|
||||
|
||||
|
||||
@@ -24,13 +24,16 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class GameProfile {
|
||||
|
||||
private final UUID id;
|
||||
|
||||
@@ -23,14 +23,9 @@ import com.google.gson.JsonParseException;
|
||||
import java.io.IOException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
import org.jackhuang.hmcl.auth.UserType;
|
||||
import java.util.*;
|
||||
|
||||
import org.jackhuang.hmcl.auth.*;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||
@@ -111,7 +106,7 @@ public final class YggdrasilAccount extends Account {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo logIn(Proxy proxy) throws AuthenticationException {
|
||||
public AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException {
|
||||
if (canPlayOnline())
|
||||
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
|
||||
else {
|
||||
@@ -119,11 +114,13 @@ public final class YggdrasilAccount extends Account {
|
||||
if (!isLoggedIn())
|
||||
throw new AuthenticationException("Wrong password for account " + username);
|
||||
|
||||
if (selectedProfile == null)
|
||||
// TODO: multi-available-profiles support
|
||||
throw new UnsupportedOperationException("Do not support multi-available-profiles account yet.");
|
||||
else
|
||||
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
|
||||
if (selectedProfile == null) {
|
||||
if (profiles == null || profiles.length <= 0)
|
||||
throw new NoCharacterException(this);
|
||||
|
||||
selectedProfile = selector.select(this, Arrays.asList(profiles));
|
||||
}
|
||||
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.jackhuang.hmcl.util.Immutable;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class Install {
|
||||
public final class ForgeInstall {
|
||||
|
||||
private final String profileName;
|
||||
private final String target;
|
||||
@@ -36,11 +36,11 @@ public final class Install {
|
||||
private final String mirrorList;
|
||||
private final String logo;
|
||||
|
||||
public Install() {
|
||||
public ForgeInstall() {
|
||||
this(null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public Install(String profileName, String target, String path, String version, String filePath, String welcome, String minecraft, String mirrorList, String logo) {
|
||||
public ForgeInstall(String profileName, String target, String path, String version, String filePath, String welcome, String minecraft, String mirrorList, String logo) {
|
||||
this.profileName = profileName;
|
||||
this.target = target;
|
||||
this.path = path;
|
||||
@@ -28,20 +28,20 @@ import org.jackhuang.hmcl.util.Validation;
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class InstallProfile implements Validation {
|
||||
public final class ForgeInstallProfile implements Validation {
|
||||
|
||||
@SerializedName("install")
|
||||
private final Install install;
|
||||
private final ForgeInstall install;
|
||||
|
||||
@SerializedName("versionInfo")
|
||||
private final Version versionInfo;
|
||||
|
||||
public InstallProfile(Install install, Version versionInfo) {
|
||||
public ForgeInstallProfile(ForgeInstall install, Version versionInfo) {
|
||||
this.install = install;
|
||||
this.versionInfo = versionInfo;
|
||||
}
|
||||
|
||||
public Install getInstall() {
|
||||
public ForgeInstall getInstall() {
|
||||
return install;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public final class ForgeInstallTask extends TaskResult<Version> {
|
||||
if (stream == null)
|
||||
throw new IOException("Malformed forge installer file, install_profile.json does not exist.");
|
||||
String json = IOUtils.readFullyAsString(stream);
|
||||
InstallProfile installProfile = Constants.GSON.fromJson(json, InstallProfile.class);
|
||||
ForgeInstallProfile installProfile = Constants.GSON.fromJson(json, ForgeInstallProfile.class);
|
||||
if (installProfile == null)
|
||||
throw new IOException("Malformed forge installer file, install_profile.json does not exist.");
|
||||
|
||||
|
||||
@@ -57,14 +57,13 @@ public final class GameLibrariesTask extends Task {
|
||||
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
for (Library library : version.getLibraries())
|
||||
if (library.appliesToCurrentEnvironment()) {
|
||||
File file = dependencyManager.getGameRepository().getLibraryFile(version, library);
|
||||
if (!file.exists())
|
||||
dependencies.add(new FileDownloadTask(
|
||||
NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(library.getDownload().getUrl())),
|
||||
file, dependencyManager.getProxy(), library.getDownload().getSha1()));
|
||||
}
|
||||
version.getLibraries().stream().filter(Library::appliesToCurrentEnvironment).forEach(library -> {
|
||||
File file = dependencyManager.getGameRepository().getLibraryFile(version, library);
|
||||
if (!file.exists())
|
||||
dependencies.add(new FileDownloadTask(
|
||||
NetworkUtils.toURL(dependencyManager.getDownloadProvider().injectURL(library.getDownload().getUrl())),
|
||||
file, dependencyManager.getProxy(), library.getDownload().getSha1()));
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public final class GameRemoteVersions {
|
||||
private final GameRemoteLatestVersions latest;
|
||||
|
||||
public GameRemoteVersions() {
|
||||
this(Collections.EMPTY_LIST, null);
|
||||
this(Collections.emptyList(), null);
|
||||
}
|
||||
|
||||
public GameRemoteVersions(List<GameRemoteVersion> versions, GameRemoteLatestVersions latest) {
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class VersionJsonDownloadTask extends Task {
|
||||
@Override
|
||||
public void execute() throws Exception {
|
||||
RemoteVersion<?> remoteVersion = gameVersionList.getVersions(gameVersion).stream().findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot find specific version "+gameVersion+" in remote repository"));
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot find specific version " + gameVersion + " in remote repository"));
|
||||
String jsonURL = dependencyManager.getDownloadProvider().injectURL(remoteVersion.getUrl());
|
||||
dependencies.add(new GetTask(NetworkUtils.toURL(jsonURL), Proxy.NO_PROXY, ID));
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public final class LiteLoaderBranch {
|
||||
private final Map<String, LiteLoaderVersion> liteLoader;
|
||||
|
||||
public LiteLoaderBranch() {
|
||||
this(Collections.EMPTY_SET, Collections.EMPTY_MAP);
|
||||
this(Collections.emptySet(), Collections.emptyMap());
|
||||
}
|
||||
|
||||
public LiteLoaderBranch(Collection<Library> libraries, Map<String, LiteLoaderVersion> liteLoader) {
|
||||
|
||||
@@ -96,11 +96,11 @@ public final class LiteLoaderInstallTask extends TaskResult<Version> {
|
||||
new LibrariesDownloadInfo(new LibraryDownloadInfo(null, remote.getUrl()))
|
||||
);
|
||||
|
||||
Version tempVersion = version.setLibraries(Lang.merge(remote.getTag().getLibraries(), Arrays.asList(library)));
|
||||
Version tempVersion = version.setLibraries(Lang.merge(remote.getTag().getLibraries(), Collections.singleton(library)));
|
||||
setResult(version
|
||||
.setMainClass("net.minecraft.launchwrapper.Launch")
|
||||
.setLibraries(Lang.merge(tempVersion.getLibraries(), version.getLibraries()))
|
||||
.setLogging(Collections.EMPTY_MAP)
|
||||
.setLogging(Collections.emptyMap())
|
||||
.setMinecraftArguments(version.getMinecraftArguments().orElse("") + " --tweakClass " + remote.getTag().getTweakClass())
|
||||
//.setArguments(Arguments.addGameArguments(Lang.get(version.getArguments()), "--tweakClass", remote.getTag().getTweakClass()))
|
||||
);
|
||||
|
||||
@@ -113,7 +113,7 @@ public final class OptiFineInstallTask extends TaskResult<Version> {
|
||||
hasFMLTweaker = true;
|
||||
if (version.getArguments().isPresent()) {
|
||||
List<Argument> game = version.getArguments().get().getGame();
|
||||
if (game.stream().anyMatch(arg -> arg.toString(Collections.EMPTY_MAP, Collections.EMPTY_MAP).contains("FMLTweaker")))
|
||||
if (game.stream().anyMatch(arg -> arg.toString(Collections.emptyMap(), Collections.emptyMap()).contains("FMLTweaker")))
|
||||
hasFMLTweaker = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,10 +80,13 @@ public final class OptiFineVersionList extends VersionList<Void> {
|
||||
if (td.getAttribute("class") != null && td.getAttribute("class").startsWith("downloadLineFile"))
|
||||
version = td.getTextContent();
|
||||
}
|
||||
if (version == null || url == null)
|
||||
continue;
|
||||
|
||||
Matcher matcher = PATTERN.matcher(version);
|
||||
while (matcher.find())
|
||||
gameVersion = matcher.group(1);
|
||||
if (gameVersion == null || version == null || url == null)
|
||||
if (gameVersion == null)
|
||||
continue;
|
||||
versions.put(gameVersion, new RemoteVersion<>(gameVersion, version, url, null));
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ public class Event extends EventObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Result result;
|
||||
private Result result = Result.DEFAULT;
|
||||
|
||||
/**
|
||||
* Retutns the value set as the result of this event
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
import java.util.HashMap;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
|
||||
@@ -29,14 +28,14 @@ public final class EventBus {
|
||||
|
||||
private final HashMap<Class<?>, EventManager<?>> events = new HashMap<>();
|
||||
|
||||
public <T extends EventObject> EventManager<T> channel(Class<T> clazz) {
|
||||
public <T extends Event> EventManager<T> channel(Class<T> clazz) {
|
||||
if (!events.containsKey(clazz))
|
||||
events.put(clazz, new EventManager<>(Schedulers.computation()));
|
||||
events.put(clazz, new EventManager<>());
|
||||
return (EventManager<T>) events.get(clazz);
|
||||
}
|
||||
|
||||
public void fireEvent(EventObject obj) {
|
||||
channel((Class<EventObject>) obj.getClass()).fireEvent(obj);
|
||||
public Event.Result fireEvent(Event obj) {
|
||||
return channel((Class<Event>) obj.getClass()).fireEvent(obj);
|
||||
}
|
||||
|
||||
public static final EventBus EVENT_BUS = new EventBus();
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.EventObject;
|
||||
import java.util.HashSet;
|
||||
import java.util.function.Consumer;
|
||||
import org.jackhuang.hmcl.task.Scheduler;
|
||||
@@ -29,22 +28,13 @@ import org.jackhuang.hmcl.util.SimpleMultimap;
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class EventManager<T extends EventObject> {
|
||||
public final class EventManager<T extends Event> {
|
||||
|
||||
private final Scheduler scheduler;
|
||||
private final SimpleMultimap<EventPriority, Consumer<T>> handlers
|
||||
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new);
|
||||
private final SimpleMultimap<EventPriority, Runnable> handlers2
|
||||
= new SimpleMultimap<>(() -> new EnumMap<>(EventPriority.class), HashSet::new);
|
||||
|
||||
public EventManager() {
|
||||
this(Schedulers.immediate());
|
||||
}
|
||||
|
||||
public EventManager(Scheduler scheduler) {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
public void register(Consumer<T> consumer) {
|
||||
register(consumer, EventPriority.NORMAL);
|
||||
}
|
||||
@@ -71,15 +61,18 @@ public final class EventManager<T extends EventObject> {
|
||||
handlers2.removeValue(runnable);
|
||||
}
|
||||
|
||||
public void fireEvent(T event) {
|
||||
scheduler.schedule(() -> {
|
||||
for (EventPriority priority : EventPriority.values()) {
|
||||
for (Consumer<T> handler : handlers.get(priority))
|
||||
handler.accept(event);
|
||||
for (Runnable runnable : handlers2.get(priority))
|
||||
runnable.run();
|
||||
}
|
||||
});
|
||||
public Event.Result fireEvent(T event) {
|
||||
for (EventPriority priority : EventPriority.values()) {
|
||||
for (Consumer<T> handler : handlers.get(priority))
|
||||
handler.accept(event);
|
||||
for (Runnable runnable : handlers2.get(priority))
|
||||
runnable.run();
|
||||
}
|
||||
|
||||
if (event.hasResult())
|
||||
return event.getResult();
|
||||
else
|
||||
return Event.Result.DEFAULT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import java.util.EventObject;
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public class FailedEvent<T> extends EventObject {
|
||||
public class FailedEvent<T> extends Event {
|
||||
|
||||
private final int failedTime;
|
||||
private T newResult;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This event gets fired when json of a game version is malformed. You can do something here.
|
||||
* auto making up for the missing json, don't forget to set result to {@link Event.Result#ALLOW}.
|
||||
* and even asking for removing the redundant version folder.
|
||||
*
|
||||
* The result ALLOW means you have corrected the json.
|
||||
*/
|
||||
public final class GameJsonParseFailedEvent extends Event {
|
||||
private final String version;
|
||||
private final File jsonFile;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.DefaultGameRepository}
|
||||
* @param jsonFile the minecraft.json file.
|
||||
* @param version the version name
|
||||
*/
|
||||
public GameJsonParseFailedEvent(Object source, File jsonFile, String version) {
|
||||
super(source);
|
||||
this.version = version;
|
||||
this.jsonFile = jsonFile;
|
||||
}
|
||||
|
||||
public File getJsonFile() {
|
||||
return jsonFile;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,20 @@ import org.jackhuang.hmcl.util.ManagedProcess;
|
||||
/**
|
||||
* This event gets fired when we launch the JVM and it got crashed.
|
||||
* <br>
|
||||
* This event is fired on the [org.jackhuang.hmcl.event.EVENT_BUS]
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EventBus#EVENT_BUS}
|
||||
*
|
||||
* @param source [org.jackhuang.hmcl.launch.ExitWaiter]
|
||||
* @param value the crashed process.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class JVMLaunchFailedEvent extends EventObject {
|
||||
public class JVMLaunchFailedEvent extends Event {
|
||||
|
||||
private final ManagedProcess process;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param process the crashed process.
|
||||
*/
|
||||
public JVMLaunchFailedEvent(Object source, ManagedProcess process) {
|
||||
super(source);
|
||||
this.process = process;
|
||||
|
||||
@@ -17,28 +17,37 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.event;
|
||||
|
||||
import org.jackhuang.hmcl.game.Version;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* This event gets fired when a minecraft version has been loaded.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the version id.
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EventBus#EVENT_BUS}
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class LoadedOneVersionEvent extends EventObject {
|
||||
public final class LoadedOneVersionEvent extends Event {
|
||||
|
||||
private final String version;
|
||||
private final Version version;
|
||||
|
||||
public LoadedOneVersionEvent(Object source, String version) {
|
||||
/**
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* @param version the version id.
|
||||
*/
|
||||
public LoadedOneVersionEvent(Object source, Version version) {
|
||||
super(source);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
public Version getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasResult() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,16 +23,20 @@ import org.jackhuang.hmcl.util.ManagedProcess;
|
||||
/**
|
||||
* This event gets fired when a JavaProcess exited abnormally and the exit code is not zero.
|
||||
* <br></br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EventBus#EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param value The process that exited abnormally.
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class ProcessExitedAbnormallyEvent extends EventObject {
|
||||
public final class ProcessExitedAbnormallyEvent extends Event {
|
||||
|
||||
private final ManagedProcess process;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param process The process that exited abnormally.
|
||||
*/
|
||||
public ProcessExitedAbnormallyEvent(Object source, ManagedProcess process) {
|
||||
super(source);
|
||||
this.process = process;
|
||||
|
||||
@@ -23,16 +23,20 @@ import org.jackhuang.hmcl.util.ManagedProcess;
|
||||
/**
|
||||
* This event gets fired when minecraft process exited successfully and the exit code is 0.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EventBus#EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param value minecraft process
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public class ProcessStoppedEvent extends EventObject {
|
||||
public class ProcessStoppedEvent extends Event {
|
||||
|
||||
private final ManagedProcess process;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.launch.ExitWaiter}
|
||||
* @param process minecraft process
|
||||
*/
|
||||
public ProcessStoppedEvent(Object source, ManagedProcess process) {
|
||||
super(source);
|
||||
this.process = process;
|
||||
|
||||
@@ -22,14 +22,17 @@ import java.util.EventObject;
|
||||
/**
|
||||
* This event gets fired when all the versions in .minecraft folder are loaded.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.api.HMCLApi#EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository]
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EventBus#EVENT_BUS}
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class RefreshedVersionsEvent extends EventObject {
|
||||
public final class RefreshedVersionsEvent extends Event {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository]
|
||||
*/
|
||||
public RefreshedVersionsEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@@ -22,14 +22,17 @@ import java.util.EventObject;
|
||||
/**
|
||||
* This event gets fired when loading versions in a .minecraft folder.
|
||||
* <br>
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EVENT_BUS}
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
* This event is fired on the {@link org.jackhuang.hmcl.event.EventBus#EVENT_BUS}
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class RefreshingVersionsEvent extends EventObject {
|
||||
public final class RefreshingVersionsEvent extends Event {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source {@link org.jackhuang.hmcl.game.GameRepository}
|
||||
*/
|
||||
public RefreshingVersionsEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@@ -50,11 +50,11 @@ public final class Arguments {
|
||||
}
|
||||
|
||||
public List<Argument> getGame() {
|
||||
return game == null ? Collections.EMPTY_LIST : Collections.unmodifiableList(game);
|
||||
return game == null ? Collections.emptyList() : Collections.unmodifiableList(game);
|
||||
}
|
||||
|
||||
public List<Argument> getJvm() {
|
||||
return jvm == null ? Collections.EMPTY_LIST : Collections.unmodifiableList(jvm);
|
||||
return jvm == null ? Collections.emptyList() : Collections.unmodifiableList(jvm);
|
||||
}
|
||||
|
||||
public static Arguments addGameArguments(Arguments arguments, String... gameArguments) {
|
||||
@@ -83,7 +83,7 @@ public final class Arguments {
|
||||
}
|
||||
|
||||
public static List<String> parseArguments(List<Argument> arguments, Map<String, String> keys) {
|
||||
return parseArguments(arguments, keys, Collections.EMPTY_MAP);
|
||||
return parseArguments(arguments, keys, Collections.emptyMap());
|
||||
}
|
||||
|
||||
public static List<String> parseArguments(List<Argument> arguments, Map<String, String> keys, Map<String, Boolean> features) {
|
||||
|
||||
@@ -35,7 +35,7 @@ public final class AssetIndex {
|
||||
private final Map<String, AssetObject> objects;
|
||||
|
||||
public AssetIndex() {
|
||||
this(false, Collections.EMPTY_MAP);
|
||||
this(false, Collections.emptyMap());
|
||||
}
|
||||
|
||||
public AssetIndex(boolean virtual, Map<String, AssetObject> objects) {
|
||||
|
||||
@@ -21,16 +21,11 @@ import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import org.jackhuang.hmcl.event.EventBus;
|
||||
import org.jackhuang.hmcl.event.LoadedOneVersionEvent;
|
||||
import org.jackhuang.hmcl.event.RefreshedVersionsEvent;
|
||||
import org.jackhuang.hmcl.event.RefreshingVersionsEvent;
|
||||
|
||||
import org.jackhuang.hmcl.event.*;
|
||||
import org.jackhuang.hmcl.task.Schedulers;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
@@ -94,7 +89,7 @@ public class DefaultGameRepository implements GameRepository {
|
||||
@Override
|
||||
public File getVersionJar(Version version) {
|
||||
Version v = version.resolve(this);
|
||||
String id = Lang.nonNull(v.getJar(), v.getId());
|
||||
String id = Optional.ofNullable(v.getJar()).orElse(v.getId());
|
||||
return new File(getVersionRoot(id), id + ".jar");
|
||||
}
|
||||
|
||||
@@ -184,9 +179,15 @@ public class DefaultGameRepository implements GameRepository {
|
||||
version = Objects.requireNonNull(readVersionJson(json));
|
||||
} catch (Exception e) {
|
||||
// JsonSyntaxException or IOException or NullPointerException(!!)
|
||||
// TODO: auto making up for the missing json
|
||||
// TODO: and even asking for removing the redundant version folder.
|
||||
continue;
|
||||
if (EventBus.EVENT_BUS.fireEvent(new GameJsonParseFailedEvent(this, json, id)) != Event.Result.ALLOW)
|
||||
continue;
|
||||
|
||||
try {
|
||||
version = Objects.requireNonNull(readVersionJson(json));
|
||||
} catch (Exception e2) {
|
||||
Logging.LOG.log(Level.SEVERE, "User corrected version json is still malformed");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id.equals(version.getId())) {
|
||||
@@ -199,18 +200,20 @@ public class DefaultGameRepository implements GameRepository {
|
||||
}
|
||||
}
|
||||
|
||||
versions.put(id, version);
|
||||
EventBus.EVENT_BUS.fireEvent(new LoadedOneVersionEvent(this, id));
|
||||
if (EventBus.EVENT_BUS.fireEvent(new LoadedOneVersionEvent(this, version)) != Event.Result.DENY)
|
||||
versions.put(id, version);
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void refreshVersions() {
|
||||
public void refreshVersions() {
|
||||
EventBus.EVENT_BUS.fireEvent(new RefreshingVersionsEvent(this));
|
||||
refreshVersionsImpl();
|
||||
EventBus.EVENT_BUS.fireEvent(new RefreshedVersionsEvent(this));
|
||||
Schedulers.newThread().schedule(() -> {
|
||||
refreshVersionsImpl();
|
||||
EventBus.EVENT_BUS.fireEvent(new RefreshedVersionsEvent(this));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,8 @@ import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.OperatingSystem;
|
||||
@@ -99,7 +101,7 @@ public class Library {
|
||||
+ (this.classifier == null ? "" : "-" + this.classifier) + ".jar";
|
||||
|
||||
download = new LibraryDownloadInfo(path,
|
||||
Lang.nonNull(Lang.nonNull(temp != null ? temp.getUrl() : null), Lang.nonNull(url, Constants.DEFAULT_LIBRARY_URL) + path),
|
||||
Optional.ofNullable(temp).map(LibraryDownloadInfo::getUrl).orElse(Optional.ofNullable(url).orElse(Constants.DEFAULT_LIBRARY_URL) + path),
|
||||
temp != null ? temp.getSha1() : null,
|
||||
temp != null ? temp.getSize() : 0
|
||||
);
|
||||
|
||||
@@ -75,7 +75,7 @@ public class RuledArgument implements Argument {
|
||||
.map(StringArgument::new)
|
||||
.map(str -> str.toString(keys, features).get(0))
|
||||
.collect(Collectors.toList());
|
||||
return Collections.EMPTY_LIST;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static class Serializer implements JsonSerializer<RuledArgument>, JsonDeserializer<RuledArgument> {
|
||||
|
||||
@@ -155,8 +155,6 @@ public class Version implements Comparable<Version>, Validation {
|
||||
|
||||
/**
|
||||
* Resolve given version
|
||||
*
|
||||
* @throws CircleDependencyException
|
||||
*/
|
||||
public Version resolve(VersionProvider provider) {
|
||||
return resolve(provider, new HashSet<>());
|
||||
@@ -231,10 +229,7 @@ public class Version implements Comparable<Version>, Validation {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof Version)
|
||||
return Objects.equals(id, ((Version) obj).id);
|
||||
else
|
||||
return false;
|
||||
return obj instanceof Version && Objects.equals(id, ((Version) obj).id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -22,11 +22,7 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
@@ -207,7 +203,7 @@ public class DefaultLauncher extends Launcher {
|
||||
.filter(it -> !getForbiddens().containsKey(it) || !getForbiddens().get(it).get())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
//http://jenkins.liteloader.com/job/LiteLoader%201.12.2/lastSuccessfulBuild/artifact/build/libs/liteloader-1.12.2-SNAPSHOT-release.jar
|
||||
|
||||
public Map<String, Boolean> getFeatures() {
|
||||
return Collections.singletonMap(
|
||||
"has_custom_resolution",
|
||||
@@ -251,14 +247,14 @@ public class DefaultLauncher extends Launcher {
|
||||
false);
|
||||
}
|
||||
|
||||
public Map<String, String> getConfigurations() {
|
||||
protected Map<String, String> getConfigurations() {
|
||||
return Lang.mapOf(
|
||||
new Pair<>("${auth_player_name}", authInfo.getUsername()),
|
||||
new Pair<>("${auth_session}", authInfo.getAuthToken()),
|
||||
new Pair<>("${auth_access_token}", authInfo.getAuthToken()),
|
||||
new Pair<>("${auth_uuid}", authInfo.getUserId()),
|
||||
new Pair<>("${version_name}", Lang.nonNull(options.getVersionName(), version.getId())),
|
||||
new Pair<>("${profile_name}", Lang.nonNull(options.getProfileName(), "Minecraft")),
|
||||
new Pair<>("${version_name}", Optional.ofNullable(options.getVersionName()).orElse(version.getId())),
|
||||
new Pair<>("${profile_name}", Optional.ofNullable(options.getProfileName()).orElse("Minecraft")),
|
||||
new Pair<>("${version_type}", version.getType().getId()),
|
||||
new Pair<>("${game_directory}", repository.getRunDirectory(version.getId()).getAbsolutePath()),
|
||||
new Pair<>("${user_type}", authInfo.getUserType().toString().toLowerCase()),
|
||||
@@ -275,11 +271,8 @@ public class DefaultLauncher extends Launcher {
|
||||
|
||||
decompressNatives();
|
||||
|
||||
if (StringUtils.isNotBlank(options.getPrecalledCommand())) {
|
||||
Process process = Runtime.getRuntime().exec(options.getPrecalledCommand());
|
||||
if (process.isAlive())
|
||||
process.waitFor();
|
||||
}
|
||||
if (StringUtils.isNotBlank(options.getPrecalledCommand()))
|
||||
Runtime.getRuntime().exec(options.getPrecalledCommand()).waitFor();
|
||||
|
||||
builder.directory(repository.getRunDirectory(version.getId()))
|
||||
.environment().put("APPDATA", options.getGameDir().getAbsoluteFile().getParent());
|
||||
@@ -372,7 +365,7 @@ public class DefaultLauncher extends Launcher {
|
||||
private void startMonitorsWithoutLoggingInfo(ManagedProcess managedProcess, ProcessListener processListener, boolean isDaemon) {
|
||||
processListener.setProcess(managedProcess);
|
||||
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> {
|
||||
processListener.onLog(it + OperatingSystem.LINE_SEPARATOR, Lang.nonNull(Log4jLevel.guessLevel(it), Log4jLevel.INFO));
|
||||
processListener.onLog(it + OperatingSystem.LINE_SEPARATOR, Optional.ofNullable(Log4jLevel.guessLevel(it)).orElse(Log4jLevel.INFO));
|
||||
managedProcess.addLine(it);
|
||||
}), "stdout-pump", isDaemon);
|
||||
managedProcess.addRelatedThread(stdout);
|
||||
|
||||
@@ -17,11 +17,9 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.launch;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -55,6 +53,7 @@ final class Log4jHandler extends Thread {
|
||||
|
||||
public Log4jHandler(BiConsumer<String, Log4jLevel> callback) {
|
||||
this.callback = callback;
|
||||
newLine("<output>");
|
||||
|
||||
reader = Lang.invoke(() -> XMLReaderFactory.createXMLReader());
|
||||
reader.setContentHandler(new Log4jHandlerImpl());
|
||||
@@ -63,7 +62,6 @@ final class Log4jHandler extends Thread {
|
||||
@Override
|
||||
public void run() {
|
||||
setName("log4j-handler");
|
||||
newLine("<output>");
|
||||
|
||||
try {
|
||||
reader.parse(new InputSource(inputStream));
|
||||
@@ -88,17 +86,14 @@ final class Log4jHandler extends Thread {
|
||||
}).get());
|
||||
}
|
||||
|
||||
public Future<?> newLine(String content) {
|
||||
public Future<?> newLine(String log) {
|
||||
return Schedulers.computation().schedule(() -> {
|
||||
String log = content;
|
||||
if (!log.trim().startsWith("<"))
|
||||
log = "<![CDATA[" + log.replace("]]>", "") + "]]>";
|
||||
outputStream.write((log + OperatingSystem.LINE_SEPARATOR)
|
||||
byte[] bytes = (log + OperatingSystem.LINE_SEPARATOR)
|
||||
.replace("log4j:Event", "log4j_Event")
|
||||
.replace("log4j:Message", "log4j_Message")
|
||||
.replace("log4j:Throwable", "log4j_Throwable")
|
||||
.getBytes()
|
||||
);
|
||||
.getBytes();
|
||||
outputStream.write(bytes);
|
||||
outputStream.flush();
|
||||
});
|
||||
}
|
||||
@@ -155,7 +150,7 @@ final class Log4jHandler extends Thread {
|
||||
if (readingMessage)
|
||||
message.append(line).append(OperatingSystem.LINE_SEPARATOR);
|
||||
else
|
||||
callback.accept(line, Lang.nonNull(Log4jLevel.guessLevel(line), Log4jLevel.INFO));
|
||||
callback.accept(line, Optional.ofNullable(Log4jLevel.guessLevel(line)).orElse(Log4jLevel.INFO));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public final class CurseInstallTask extends Task {
|
||||
* @param zipFile the CurseForge modpack file.
|
||||
* @param manifest The manifest content of given CurseForge modpack.
|
||||
* @param name the new version name
|
||||
* @see readCurseForgeModpackManifest
|
||||
* @see CurseManifest#readCurseForgeModpackManifest
|
||||
*/
|
||||
public CurseInstallTask(DefaultDependencyManager dependencyManager, File zipFile, CurseManifest manifest, String name) {
|
||||
this.dependencyManager = dependencyManager;
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jackhuang.hmcl.util.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
@@ -122,7 +124,7 @@ public final class CurseManifest {
|
||||
if (manifest == null)
|
||||
throw new JsonParseException("`manifest.json` not found. Not a valid Curse modpack.");
|
||||
return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), manifest.getMinecraft().getGameVersion(),
|
||||
Lang.nonNull(CompressingUtils.readTextZipEntryQuietly(f, "modlist.html"), "No description"), manifest);
|
||||
Optional.ofNullable(CompressingUtils.readTextZipEntryQuietly(f, "modlist.html")).orElse( "No description"), manifest);
|
||||
}
|
||||
|
||||
public static final String MINECRAFT_MODPACK = "minecraftModpack";
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.jackhuang.hmcl.mod;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
@@ -83,7 +84,7 @@ public final class MultiMCInstanceConfiguration {
|
||||
showConsoleOnError = Boolean.parseBoolean(p.getProperty("ShowConsoleOnError"));
|
||||
wrapperCommand = p.getProperty("WrapperCommand");
|
||||
name = defaultName;
|
||||
notes = Lang.nonNull(p.getProperty("notes"), "");
|
||||
notes = Optional.ofNullable(p.getProperty("notes")).orElse("");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.task;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.util.ExceptionalConsumer;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -26,16 +27,18 @@ import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
*/
|
||||
class SimpleTask extends Task {
|
||||
|
||||
private final Consumer<AutoTypingMap<String>> consumer;
|
||||
private final ExceptionalConsumer<AutoTypingMap<String>, ?> consumer;
|
||||
private final Scheduler scheduler;
|
||||
|
||||
public SimpleTask(Consumer<AutoTypingMap<String>> consumer) {
|
||||
public SimpleTask(ExceptionalConsumer<AutoTypingMap<String>, ?> consumer) {
|
||||
this(consumer, Schedulers.defaultScheduler());
|
||||
}
|
||||
|
||||
public SimpleTask(Consumer<AutoTypingMap<String>> consumer, Scheduler scheduler) {
|
||||
public SimpleTask(ExceptionalConsumer<AutoTypingMap<String>, ?> consumer, Scheduler scheduler) {
|
||||
this.consumer = consumer;
|
||||
this.scheduler = scheduler;
|
||||
|
||||
setName(consumer.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -29,6 +29,8 @@ import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||
import org.jackhuang.hmcl.util.AutoTypingMap;
|
||||
import org.jackhuang.hmcl.event.EventManager;
|
||||
import org.jackhuang.hmcl.util.ExceptionalConsumer;
|
||||
import org.jackhuang.hmcl.util.ExceptionalRunnable;
|
||||
import org.jackhuang.hmcl.util.Properties;
|
||||
|
||||
/**
|
||||
@@ -204,11 +206,11 @@ public abstract class Task {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public final TaskExecutor subscribe(Scheduler scheduler, Consumer<AutoTypingMap<String>> closure) {
|
||||
public final TaskExecutor subscribe(Scheduler scheduler, ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
|
||||
return subscribe(of(closure, scheduler));
|
||||
}
|
||||
|
||||
public final TaskExecutor subscribe(Consumer<AutoTypingMap<String>> closure) {
|
||||
public final TaskExecutor subscribe(ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
|
||||
return subscribe(of(closure));
|
||||
}
|
||||
|
||||
@@ -228,15 +230,15 @@ public abstract class Task {
|
||||
return new CoupleTask<>(this, b, false);
|
||||
}
|
||||
|
||||
public static Task of(Runnable runnable) {
|
||||
public static Task of(ExceptionalRunnable<?> runnable) {
|
||||
return of(s -> runnable.run());
|
||||
}
|
||||
|
||||
public static Task of(Consumer<AutoTypingMap<String>> closure) {
|
||||
public static Task of(ExceptionalConsumer<AutoTypingMap<String>, ?> closure) {
|
||||
return of(closure, Schedulers.defaultScheduler());
|
||||
}
|
||||
|
||||
public static Task of(Consumer<AutoTypingMap<String>> closure, Scheduler scheduler) {
|
||||
public static Task of(ExceptionalConsumer<AutoTypingMap<String>, ?> closure, Scheduler scheduler) {
|
||||
return new SimpleTask(closure, scheduler);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.task;
|
||||
|
||||
import java.util.EventObject;
|
||||
import org.jackhuang.hmcl.event.Event;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public class TaskEvent extends EventObject {
|
||||
public class TaskEvent extends Event {
|
||||
|
||||
private final Task task;
|
||||
private final boolean failed;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher.
|
||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
/**
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public interface ExceptionalConsumer<T, E extends Exception> {
|
||||
void accept(T t) throws E;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public final class Lang {
|
||||
*
|
||||
* @param <T> type of argument.
|
||||
* @param <R> type of result.
|
||||
* @param supplier your method.
|
||||
* @param function your method.
|
||||
* @return the result of the method to invoke.
|
||||
*/
|
||||
public static <T, R, E extends Exception> R invoke(ExceptionalFunction<T, R, E> function, T t) {
|
||||
@@ -190,19 +190,19 @@ public final class Lang {
|
||||
return convert(map.get(key), clazz, defaultValue);
|
||||
}
|
||||
|
||||
public static <T> List<T> merge(Collection<T>... collections) {
|
||||
public static <T> List<T> merge(Collection<T> a, Collection<T> b) {
|
||||
LinkedList<T> result = new LinkedList<>();
|
||||
for (Collection<T> collection : collections)
|
||||
if (collection != null)
|
||||
result.addAll(collection);
|
||||
result.addAll(a);
|
||||
result.addAll(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> T nonNull(T... t) {
|
||||
for (T a : t)
|
||||
if (a != null)
|
||||
return a;
|
||||
return null;
|
||||
public static <T> List<T> merge(Collection<T> a, Collection<T> b, Collection<T> c) {
|
||||
LinkedList<T> result = new LinkedList<>();
|
||||
result.addAll(a);
|
||||
result.addAll(b);
|
||||
result.addAll(c);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Thread thread(Runnable runnable) {
|
||||
@@ -223,10 +223,6 @@ public final class Lang {
|
||||
return thread;
|
||||
}
|
||||
|
||||
public static <T> T get(Optional<T> optional) {
|
||||
return optional.isPresent() ? optional.get() : null;
|
||||
}
|
||||
|
||||
public static <T> Iterator<T> asIterator(Enumeration<T> enumeration) {
|
||||
return new Iterator<T>() {
|
||||
@Override
|
||||
@@ -244,4 +240,12 @@ public final class Lang {
|
||||
public static <T> Iterable<T> asIterable(Enumeration<T> enumeration) {
|
||||
return () -> asIterator(enumeration);
|
||||
}
|
||||
|
||||
public static int parseInt(String string, int defaultValue) {
|
||||
try {
|
||||
return Integer.parseInt(string);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,12 +65,12 @@ public enum OperatingSystem {
|
||||
/**
|
||||
* The total memory/MB this computer have.
|
||||
*/
|
||||
public static final long TOTAL_MEMORY;
|
||||
public static final int TOTAL_MEMORY;
|
||||
|
||||
/**
|
||||
* The suggested memory size/MB for Minecraft to allocate.
|
||||
*/
|
||||
public static final long SUGGESTED_MEMORY;
|
||||
public static final int SUGGESTED_MEMORY;
|
||||
|
||||
public static final String PATH_SEPARATOR = File.pathSeparator;
|
||||
public static final String FILE_SEPARATOR = File.separator;
|
||||
@@ -104,11 +104,11 @@ public enum OperatingSystem {
|
||||
|
||||
Object bytes = ReflectionHelper.call(ManagementFactory.getOperatingSystemMXBean(), "getTotalPhysicalMemorySize");
|
||||
if (bytes instanceof Long)
|
||||
TOTAL_MEMORY = ((Long) bytes) / 1024 / 1024;
|
||||
TOTAL_MEMORY = (int) (((Long) bytes) / 1024 / 1024);
|
||||
else
|
||||
TOTAL_MEMORY = 1024;
|
||||
|
||||
SUGGESTED_MEMORY = Math.round(1.0 * TOTAL_MEMORY / 4.0 / 128.0) * 128;
|
||||
SUGGESTED_MEMORY = (int) (Math.round(1.0 * TOTAL_MEMORY / 4.0 / 128.0) * 128);
|
||||
|
||||
String arch = System.getProperty("sun.arch.data.model");
|
||||
if (arch == null)
|
||||
|
||||
@@ -29,7 +29,7 @@ public abstract class VersionNumber implements Comparable<VersionNumber> {
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if there are some characters excluding digits and dots.
|
||||
* @param version
|
||||
* @param version version string in form x.x.x
|
||||
* @return the int version number
|
||||
*/
|
||||
public static IntVersionNumber asIntVersionNumber(String version) {
|
||||
|
||||
Reference in New Issue
Block a user