@@ -45,6 +45,8 @@ import java.util.*;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
|
|
||||||
public class Settings {
|
public class Settings {
|
||||||
public static final Gson GSON = new GsonBuilder()
|
public static final Gson GSON = new GsonBuilder()
|
||||||
.registerTypeAdapter(VersionSetting.class, VersionSetting.Serializer.INSTANCE)
|
.registerTypeAdapter(VersionSetting.class, VersionSetting.Serializer.INSTANCE)
|
||||||
@@ -71,7 +73,7 @@ public class Settings {
|
|||||||
|
|
||||||
for (Iterator<Map<Object, Object>> iterator = SETTINGS.getAccounts().iterator(); iterator.hasNext(); ) {
|
for (Iterator<Map<Object, Object>> iterator = SETTINGS.getAccounts().iterator(); iterator.hasNext(); ) {
|
||||||
Map<Object, Object> settings = iterator.next();
|
Map<Object, Object> settings = iterator.next();
|
||||||
AccountFactory<?> factory = Accounts.ACCOUNT_FACTORY.get(Lang.get(settings, "type", String.class).orElse(""));
|
AccountFactory<?> factory = Accounts.ACCOUNT_FACTORY.get(tryCast(settings.get("type"), String.class).orElse(""));
|
||||||
if (factory == null) {
|
if (factory == null) {
|
||||||
// unrecognized account type, so remove it.
|
// unrecognized account type, so remove it.
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui;
|
|||||||
|
|
||||||
import com.jfoenix.adapters.ReflectionHelper;
|
import com.jfoenix.adapters.ReflectionHelper;
|
||||||
import com.jfoenix.controls.*;
|
import com.jfoenix.controls.*;
|
||||||
|
|
||||||
import javafx.animation.Animation;
|
import javafx.animation.Animation;
|
||||||
import javafx.animation.Interpolator;
|
import javafx.animation.Interpolator;
|
||||||
import javafx.animation.KeyFrame;
|
import javafx.animation.KeyFrame;
|
||||||
@@ -42,11 +43,14 @@ import javafx.scene.input.ScrollEvent;
|
|||||||
import javafx.scene.layout.Region;
|
import javafx.scene.layout.Region;
|
||||||
import javafx.scene.shape.Rectangle;
|
import javafx.scene.shape.Rectangle;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.Launcher;
|
import org.jackhuang.hmcl.Launcher;
|
||||||
import org.jackhuang.hmcl.util.*;
|
import org.jackhuang.hmcl.util.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@@ -55,8 +59,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.ReflectionHelper.call;
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
import static org.jackhuang.hmcl.util.ReflectionHelper.construct;
|
|
||||||
|
|
||||||
public final class FXUtils {
|
public final class FXUtils {
|
||||||
private FXUtils() {
|
private FXUtils() {
|
||||||
@@ -125,7 +128,7 @@ public final class FXUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void removeListener(Node node, String key) {
|
public static void removeListener(Node node, String key) {
|
||||||
Lang.cast(node.getProperties().get(key), ListenerPair.class)
|
tryCast(node.getProperties().get(key), ListenerPair.class)
|
||||||
.ifPresent(info -> {
|
.ifPresent(info -> {
|
||||||
info.unbind();
|
info.unbind();
|
||||||
node.getProperties().remove(key);
|
node.getProperties().remove(key);
|
||||||
@@ -214,17 +217,22 @@ public final class FXUtils {
|
|||||||
public static void installTooltip(Node node, double openDelay, double visibleDelay, double closeDelay, Tooltip tooltip) {
|
public static void installTooltip(Node node, double openDelay, double visibleDelay, double closeDelay, Tooltip tooltip) {
|
||||||
try {
|
try {
|
||||||
// Java 8
|
// Java 8
|
||||||
call(construct(Class.forName("javafx.scene.control.Tooltip$TooltipBehavior"), new Duration(openDelay), new Duration(visibleDelay), new Duration(closeDelay), false),
|
Class<?> behaviorClass = Class.forName("javafx.scene.control.Tooltip$TooltipBehavior");
|
||||||
"install", node, tooltip);
|
Constructor<?> behaviorConstructor = behaviorClass.getDeclaredConstructor(Duration.class, Duration.class, Duration.class, boolean.class);
|
||||||
} catch (Throwable e) {
|
behaviorConstructor.setAccessible(true);
|
||||||
|
Object behavior = behaviorConstructor.newInstance(new Duration(openDelay), new Duration(visibleDelay), new Duration(closeDelay), false);
|
||||||
|
Method installMethod = behaviorClass.getDeclaredMethod("install", Node.class, Tooltip.class);
|
||||||
|
installMethod.setAccessible(true);
|
||||||
|
installMethod.invoke(behavior, node, tooltip);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
try {
|
try {
|
||||||
// Java 9
|
// Java 9
|
||||||
call(tooltip, "setShowDelay", new Duration(openDelay));
|
Tooltip.class.getMethod("setShowDelay", Duration.class).invoke(tooltip, new Duration(openDelay));
|
||||||
call(tooltip, "setShowDuration", new Duration(visibleDelay));
|
Tooltip.class.getMethod("setShowDuration", Duration.class).invoke(tooltip, new Duration(visibleDelay));
|
||||||
call(tooltip, "setHideDelay", new Duration(closeDelay));
|
Tooltip.class.getMethod("setHideDelay", Duration.class).invoke(tooltip, new Duration(closeDelay));
|
||||||
} catch (Throwable e2) {
|
} catch (ReflectiveOperationException e2) {
|
||||||
e.addSuppressed(e2);
|
e.addSuppressed(e2);
|
||||||
Logging.LOG.log(Level.SEVERE, "Cannot install tooltip by reflection", e);
|
Logging.LOG.log(Level.SEVERE, "Cannot install tooltip", e);
|
||||||
}
|
}
|
||||||
Tooltip.install(node, tooltip);
|
Tooltip.install(node, tooltip);
|
||||||
}
|
}
|
||||||
@@ -333,7 +341,7 @@ public final class FXUtils {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static void unbindEnum(JFXComboBox<?> comboBox) {
|
public static void unbindEnum(JFXComboBox<?> comboBox) {
|
||||||
ChangeListener listener = Lang.get(comboBox.getProperties(), "FXUtils.bindEnum.listener", ChangeListener.class).orElse(null);
|
ChangeListener listener = tryCast(comboBox.getProperties().get("FXUtils.bindEnum.listener"), ChangeListener.class).orElse(null);
|
||||||
if (listener == null) return;
|
if (listener == null) return;
|
||||||
comboBox.getSelectionModel().selectedIndexProperty().removeListener(listener);
|
comboBox.getSelectionModel().selectedIndexProperty().removeListener(listener);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import java.io.File;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.Launcher.i18n;
|
import static org.jackhuang.hmcl.Launcher.i18n;
|
||||||
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
|
|
||||||
public final class DownloadWizardProvider implements WizardProvider {
|
public final class DownloadWizardProvider implements WizardProvider {
|
||||||
private Profile profile;
|
private Profile profile;
|
||||||
@@ -67,9 +68,9 @@ public final class DownloadWizardProvider implements WizardProvider {
|
|||||||
if (!settings.containsKey(ModpackPage.MODPACK_FILE))
|
if (!settings.containsKey(ModpackPage.MODPACK_FILE))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
File selected = Lang.get(settings, ModpackPage.MODPACK_FILE, File.class).orElse(null);
|
File selected = tryCast(settings.get(ModpackPage.MODPACK_FILE), File.class).orElse(null);
|
||||||
Modpack modpack = Lang.get(settings, ModpackPage.MODPACK_CURSEFORGE_MANIFEST, Modpack.class).orElse(null);
|
Modpack modpack = tryCast(settings.get(ModpackPage.MODPACK_CURSEFORGE_MANIFEST), Modpack.class).orElse(null);
|
||||||
String name = Lang.get(settings, ModpackPage.MODPACK_NAME, String.class).orElse(null);
|
String name = tryCast(settings.get(ModpackPage.MODPACK_NAME), String.class).orElse(null);
|
||||||
if (selected == null || modpack == null || name == null) return null;
|
if (selected == null || modpack == null || name == null) return null;
|
||||||
|
|
||||||
return ModpackHelper.getInstallTask(profile, selected, name, modpack);
|
return ModpackHelper.getInstallTask(profile, selected, name, modpack);
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import org.jackhuang.hmcl.auth.CharacterSelector;
|
|||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilSession;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilSession;
|
||||||
import org.jackhuang.hmcl.util.ExceptionalSupplier;
|
import org.jackhuang.hmcl.util.ExceptionalSupplier;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
|
||||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||||
|
|
||||||
@@ -15,6 +14,8 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
|
|
||||||
public class AuthlibInjectorAccountFactory extends AccountFactory<AuthlibInjectorAccount> {
|
public class AuthlibInjectorAccountFactory extends AccountFactory<AuthlibInjectorAccount> {
|
||||||
private final ExceptionalSupplier<String, ?> injectorJarPathSupplier;
|
private final ExceptionalSupplier<String, ?> injectorJarPathSupplier;
|
||||||
|
|
||||||
@@ -43,13 +44,13 @@ public class AuthlibInjectorAccountFactory extends AccountFactory<AuthlibInjecto
|
|||||||
Objects.requireNonNull(storage);
|
Objects.requireNonNull(storage);
|
||||||
Objects.requireNonNull(proxy);
|
Objects.requireNonNull(proxy);
|
||||||
|
|
||||||
String username = Lang.get(storage, "username", String.class)
|
String username = tryCast(storage.get("username"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have username"));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have username"));
|
||||||
String clientToken = Lang.get(storage, "clientToken", String.class)
|
String clientToken = tryCast(storage.get("clientToken"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have client token."));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have client token."));
|
||||||
String character = Lang.get(storage, "clientToken", String.class)
|
String character = tryCast(storage.get("clientToken"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have selected character name."));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have selected character name."));
|
||||||
String apiRoot = Lang.get(storage, "serverBaseURL", String.class)
|
String apiRoot = tryCast(storage.get("serverBaseURL"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have API root."));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have API root."));
|
||||||
|
|
||||||
return new AuthlibInjectorAccount(new YggdrasilService(new AuthlibInjectorProvider(apiRoot), proxy),
|
return new AuthlibInjectorAccount(new YggdrasilService(new AuthlibInjectorProvider(apiRoot), proxy),
|
||||||
|
|||||||
@@ -20,14 +20,12 @@ package org.jackhuang.hmcl.auth.offline;
|
|||||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||||
import org.jackhuang.hmcl.auth.CharacterSelector;
|
import org.jackhuang.hmcl.auth.CharacterSelector;
|
||||||
import org.jackhuang.hmcl.util.DigestUtils;
|
import org.jackhuang.hmcl.util.DigestUtils;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
|
||||||
import org.jackhuang.hmcl.util.Logging;
|
|
||||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||||
|
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.logging.Level;
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -46,9 +44,9 @@ public class OfflineAccountFactory extends AccountFactory<OfflineAccount> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OfflineAccount fromStorage(Map<Object, Object> storage, Proxy proxy) {
|
public OfflineAccount fromStorage(Map<Object, Object> storage, Proxy proxy) {
|
||||||
String username = Lang.get(storage, "username", String.class)
|
String username = tryCast(storage.get("username"), String.class)
|
||||||
.orElseThrow(() -> new IllegalStateException("Offline account configuration malformed."));
|
.orElseThrow(() -> new IllegalStateException("Offline account configuration malformed."));
|
||||||
String uuid = Lang.get(storage, "uuid", String.class)
|
String uuid = tryCast(storage.get("uuid"), String.class)
|
||||||
.orElse(getUUIDFromUserName(username));
|
.orElse(getUUIDFromUserName(username));
|
||||||
|
|
||||||
// Check if the uuid is vaild
|
// Check if the uuid is vaild
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ package org.jackhuang.hmcl.auth.yggdrasil;
|
|||||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||||
import org.jackhuang.hmcl.auth.CharacterSelector;
|
import org.jackhuang.hmcl.auth.CharacterSelector;
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
|
||||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||||
|
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
@@ -28,6 +27,8 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
@@ -57,11 +58,11 @@ public class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccount> {
|
|||||||
Objects.requireNonNull(storage);
|
Objects.requireNonNull(storage);
|
||||||
Objects.requireNonNull(proxy);
|
Objects.requireNonNull(proxy);
|
||||||
|
|
||||||
String username = Lang.get(storage, "username", String.class)
|
String username = tryCast(storage.get("username"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have username"));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have username"));
|
||||||
String clientToken = Lang.get(storage, "clientToken", String.class)
|
String clientToken = tryCast(storage.get("clientToken"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have client token."));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have client token."));
|
||||||
String character = Lang.get(storage, "clientToken", String.class)
|
String character = tryCast(storage.get("clientToken"), String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have selected character name."));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have selected character name."));
|
||||||
|
|
||||||
return new YggdrasilAccount(new YggdrasilService(provider, proxy), username, clientToken, character, YggdrasilSession.fromStorage(storage));
|
return new YggdrasilAccount(new YggdrasilService(provider, proxy), username, clientToken, character, YggdrasilSession.fromStorage(storage));
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.util.Lang;
|
|
||||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||||
|
|
||||||
public class YggdrasilSession {
|
public class YggdrasilSession {
|
||||||
|
|
||||||
private final String accessToken;
|
private final String accessToken;
|
||||||
@@ -54,20 +55,20 @@ public class YggdrasilSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static YggdrasilSession fromStorage(Map<?, ?> storage) {
|
public static YggdrasilSession fromStorage(Map<?, ?> storage) {
|
||||||
Optional<String> profileId = Lang.get(storage, "uuid", String.class);
|
Optional<String> profileId = tryCast(storage.get("uuid"), String.class);
|
||||||
Optional<String> profileName = Lang.get(storage, "displayName", String.class);
|
Optional<String> profileName = tryCast(storage.get("displayName"), String.class);
|
||||||
GameProfile profile = null;
|
GameProfile profile = null;
|
||||||
if (profileId.isPresent() && profileName.isPresent()) {
|
if (profileId.isPresent() && profileName.isPresent()) {
|
||||||
profile = new GameProfile(UUIDTypeAdapter.fromString(profileId.get()), profileName.get(),
|
profile = new GameProfile(UUIDTypeAdapter.fromString(profileId.get()), profileName.get(),
|
||||||
Lang.get(storage, "profileProperties", Map.class).map(PropertyMap::fromMap).orElseGet(PropertyMap::new));
|
tryCast(storage.get("profileProperties"), Map.class).map(PropertyMap::fromMap).orElseGet(PropertyMap::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new YggdrasilSession(
|
return new YggdrasilSession(
|
||||||
Lang.get(storage, "accessToken", String.class).orElse(null),
|
tryCast(storage.get("accessToken"), String.class).orElse(null),
|
||||||
profile,
|
profile,
|
||||||
null,
|
null,
|
||||||
Lang.get(storage, "userid", String.class)
|
tryCast(storage.get("userid"), String.class)
|
||||||
.map(userId -> new User(userId, Lang.get(storage, "userProperties", Map.class).map(PropertyMap::fromMap).orElse(null)))
|
.map(userId -> new User(userId, tryCast(storage.get("userProperties"), Map.class).map(PropertyMap::fromMap).orElse(null)))
|
||||||
.orElse(null)
|
.orElse(null)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,12 +218,12 @@ public final class Lang {
|
|||||||
* @param <V> the type that {@code obj} is being cast to.
|
* @param <V> the type that {@code obj} is being cast to.
|
||||||
* @return {@code obj} in the type of {@code V}.
|
* @return {@code obj} in the type of {@code V}.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
public static <V> Optional<V> tryCast(Object obj, Class<V> clazz) {
|
||||||
public static <V> Optional<V> cast(Object obj, Class<V> clazz) {
|
if (clazz.isInstance(obj)) {
|
||||||
if (obj == null || !ReflectionHelper.isInstance(clazz, obj))
|
return Optional.of(clazz.cast(obj));
|
||||||
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
else
|
}
|
||||||
return Optional.of((V) obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,20 +240,6 @@ public final class Lang {
|
|||||||
return Optional.ofNullable(list.get(index));
|
return Optional.ofNullable(list.get(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value to which the specific key is mapped,
|
|
||||||
* or {@code null} if {@code map} has no mapping for the key
|
|
||||||
* or the value is not in the type of {@code clazz}.
|
|
||||||
*
|
|
||||||
* @param map the map
|
|
||||||
* @param key the key for finding the associate value.
|
|
||||||
* @param <V> the type of values in {@code map}
|
|
||||||
* @return the value to which the specific key is mapped, or {@code null} if {@code map} has no mapping for the key or the type is not correct.
|
|
||||||
*/
|
|
||||||
public static <V> Optional<V> get(Map<?, ?> map, Object key, Class<V> clazz) {
|
|
||||||
return cast(map.get(key), clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join two collections into one list.
|
* Join two collections into one list.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ import java.io.File;
|
|||||||
import java.lang.management.ManagementFactory;
|
import java.lang.management.ManagementFactory;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import javax.management.JMException;
|
||||||
|
import javax.management.MBeanServer;
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the operating system.
|
* Represents the operating system.
|
||||||
@@ -103,11 +108,9 @@ public enum OperatingSystem {
|
|||||||
else
|
else
|
||||||
CURRENT_OS = UNKNOWN;
|
CURRENT_OS = UNKNOWN;
|
||||||
|
|
||||||
Object bytes = ReflectionHelper.call(ManagementFactory.getOperatingSystemMXBean(), "getTotalPhysicalMemorySize");
|
TOTAL_MEMORY = getTotalPhysicalMemorySize()
|
||||||
if (bytes instanceof Long)
|
.map(bytes -> (int) (bytes / 1024 / 1024))
|
||||||
TOTAL_MEMORY = (int) (((Long) bytes) / 1024 / 1024);
|
.orElse(1024);
|
||||||
else
|
|
||||||
TOTAL_MEMORY = 1024;
|
|
||||||
|
|
||||||
SUGGESTED_MEMORY = (int) (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);
|
||||||
|
|
||||||
@@ -117,6 +120,19 @@ public enum OperatingSystem {
|
|||||||
SYSTEM_ARCHITECTURE = arch;
|
SYSTEM_ARCHITECTURE = arch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Optional<Long> getTotalPhysicalMemorySize() {
|
||||||
|
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||||
|
try {
|
||||||
|
Object attribute = mBeanServer.getAttribute(new ObjectName("java.lang", "type", "OperatingSystem"), "TotalPhysicalMemorySize");
|
||||||
|
if (attribute instanceof Long) {
|
||||||
|
return Optional.of((Long) attribute);
|
||||||
|
}
|
||||||
|
} catch (JMException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
public static void setClipboard(String string) {
|
public static void setClipboard(String string) {
|
||||||
ClipboardContent c = new ClipboardContent();
|
ClipboardContent c = new ClipboardContent();
|
||||||
c.putString(string);
|
c.putString(string);
|
||||||
|
|||||||
@@ -17,136 +17,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util;
|
package org.jackhuang.hmcl.util;
|
||||||
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import java.lang.reflect.*;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedActionException;
|
|
||||||
import java.security.PrivilegedExceptionAction;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public final class ReflectionHelper {
|
public final class ReflectionHelper {
|
||||||
|
|
||||||
private static final Unsafe UNSAFE;
|
|
||||||
private static final long OBJECT_FIELD_OFFSET;
|
|
||||||
private static final Map<String, Class<?>> PRIMITIVES;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
UNSAFE = (Unsafe) AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
|
|
||||||
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
|
||||||
theUnsafe.setAccessible(true);
|
|
||||||
return theUnsafe.get(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
OBJECT_FIELD_OFFSET = UNSAFE.objectFieldOffset(getField(AccessibleObject.class, "override"));
|
|
||||||
|
|
||||||
} catch (PrivilegedActionException ex) {
|
|
||||||
throw new AssertionError(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
PRIMITIVES = Lang.mapOf(
|
|
||||||
new Pair<>("byte", Byte.class),
|
|
||||||
new Pair<>("short", Short.class),
|
|
||||||
new Pair<>("int", Integer.class),
|
|
||||||
new Pair<>("long", Long.class),
|
|
||||||
new Pair<>("char", Character.class),
|
|
||||||
new Pair<>("float", Float.class),
|
|
||||||
new Pair<>("double", Double.class),
|
|
||||||
new Pair<>("boolean", Boolean.class)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setAccessibleForcibly(AccessibleObject object) {
|
|
||||||
UNSAFE.putBoolean(object, OBJECT_FIELD_OFFSET, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Method getMethod(Object object, String name) {
|
|
||||||
return getMethod(object.getClass(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Method getMethod(Class<?> clazz, String name) {
|
|
||||||
try {
|
|
||||||
Method m = clazz.getDeclaredMethod(name);
|
|
||||||
setAccessibleForcibly(m);
|
|
||||||
return m;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Field getField(Object object, String name) {
|
|
||||||
return getField(object.getClass(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Field getField(Class<?> clazz, String name) {
|
|
||||||
try {
|
|
||||||
Field f = clazz.getDeclaredField(name);
|
|
||||||
setAccessibleForcibly(f);
|
|
||||||
return f;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object call(Class<?> cls, String name, Object object, Object... args) {
|
|
||||||
try {
|
|
||||||
if (args.length == 0)
|
|
||||||
try {
|
|
||||||
return cls.getDeclaredField(name).get(object);
|
|
||||||
} catch (NoSuchFieldException ignored) {
|
|
||||||
}
|
|
||||||
if ("new".equals(name)) {
|
|
||||||
for (Constructor<?> c : cls.getDeclaredConstructors())
|
|
||||||
if (checkParameter(c, args))
|
|
||||||
return c.newInstance(args);
|
|
||||||
} else
|
|
||||||
return forMethod(cls, name, args).get().invoke(object, args);
|
|
||||||
throw new RuntimeException();
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IllegalArgumentException("Cannot find '" + name + "' in class '" + cls.getName() + "'", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object construct(Class<?> clazz, Object... args) {
|
|
||||||
return call(clazz, "new", null, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object call(Object obj, String name, Object... args) {
|
|
||||||
return call(obj.getClass(), name, obj, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean checkParameter(Executable exec, Object... args) {
|
|
||||||
Class<?>[] cArgs = exec.getParameterTypes();
|
|
||||||
if (args.length == cArgs.length) {
|
|
||||||
for (int i = 0; i < args.length; ++i) {
|
|
||||||
Object arg = args[i];
|
|
||||||
if (arg != null ? !isInstance(cArgs[i], arg) : cArgs[i].isPrimitive())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
setAccessibleForcibly(exec);
|
|
||||||
return true;
|
|
||||||
} else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isInstance(Class<?> superClass, Object obj) {
|
|
||||||
return superClass.isInstance(obj) || PRIMITIVES.get(superClass.getName()) == obj.getClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Optional<Method> forMethod(Class<?> cls, String name, Object... args) {
|
|
||||||
return Arrays.stream(cls.getDeclaredMethods())
|
|
||||||
.filter(s -> name.equals(s.getName()))
|
|
||||||
.filter(s -> checkParameter(s, args))
|
|
||||||
.findFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StackTraceElement getCaller() {
|
public static StackTraceElement getCaller() {
|
||||||
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
||||||
StackTraceElement caller = elements[2];
|
StackTraceElement caller = elements[2];
|
||||||
|
|||||||
Reference in New Issue
Block a user