character selection
This commit is contained in:
@@ -22,6 +22,7 @@ import javafx.scene.image.Image;
|
|||||||
import org.jackhuang.hmcl.Main;
|
import org.jackhuang.hmcl.Main;
|
||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
||||||
|
import org.jackhuang.hmcl.auth.yggdrasil.ProfileTexture;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||||
@@ -33,6 +34,7 @@ import org.jackhuang.hmcl.ui.FXUtils;
|
|||||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -49,12 +51,13 @@ public final class AccountHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void loadSkins(Proxy proxy) {
|
public static void loadSkins(Proxy proxy) {
|
||||||
for (Account account : Settings.INSTANCE.getAccounts().values()) {
|
for (Account account : Settings.INSTANCE.getAccounts()) {
|
||||||
if (account instanceof YggdrasilAccount) {
|
if (account instanceof YggdrasilAccount) {
|
||||||
new SkinLoadTask((YggdrasilAccount) account, proxy, false).start();
|
new SkinLoadTask((YggdrasilAccount) account, proxy, false).start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task loadSkinAsync(YggdrasilAccount account) {
|
public static Task loadSkinAsync(YggdrasilAccount account) {
|
||||||
return loadSkinAsync(account, Settings.INSTANCE.getProxy());
|
return loadSkinAsync(account, Settings.INSTANCE.getProxy());
|
||||||
}
|
}
|
||||||
@@ -94,6 +97,20 @@ public final class AccountHelper {
|
|||||||
return FXUtils.DEFAULT_ICON;
|
return FXUtils.DEFAULT_ICON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Image getSkinImmediately(YggdrasilAccount account, GameProfile profile, double scaleRatio, Proxy proxy) throws Exception {
|
||||||
|
String name = profile.getName();
|
||||||
|
File file = getSkinFile(name);
|
||||||
|
downloadSkin(account, profile, true, proxy);
|
||||||
|
if (!file.exists())
|
||||||
|
return FXUtils.DEFAULT_ICON;
|
||||||
|
|
||||||
|
Image original = new Image("file:" + file.getAbsolutePath());
|
||||||
|
return new Image("file:" + file.getAbsolutePath(),
|
||||||
|
original.getWidth() * scaleRatio,
|
||||||
|
original.getHeight() * scaleRatio,
|
||||||
|
false, false);
|
||||||
|
}
|
||||||
|
|
||||||
public static Rectangle2D getViewport(double scaleRatio) {
|
public static Rectangle2D getViewport(double scaleRatio) {
|
||||||
double size = 8.0 * scaleRatio;
|
double size = 8.0 * scaleRatio;
|
||||||
return new Rectangle2D(size, size, size, size);
|
return new Rectangle2D(size, size, size, size);
|
||||||
@@ -130,15 +147,20 @@ public final class AccountHelper {
|
|||||||
if (account.canLogIn() && (account.getSelectedProfile() == null || refresh))
|
if (account.canLogIn() && (account.getSelectedProfile() == null || refresh))
|
||||||
DialogController.logIn(account);
|
DialogController.logIn(account);
|
||||||
|
|
||||||
GameProfile profile = account.getSelectedProfile();
|
downloadSkin(account, account.getSelectedProfile(), refresh, proxy);
|
||||||
if (profile == null) return;
|
|
||||||
String name = profile.getName();
|
|
||||||
if (name == null) return;
|
|
||||||
String url = "http://skins.minecraft.net/MinecraftSkins/" + name + ".png";
|
|
||||||
File file = getSkinFile(name);
|
|
||||||
if (!refresh && file.exists())
|
|
||||||
return;
|
|
||||||
dependencies.add(new FileDownloadTask(NetworkUtils.toURL(url), file, proxy));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void downloadSkin(YggdrasilAccount account, GameProfile profile, boolean refresh, Proxy proxy) throws Exception {
|
||||||
|
if (profile == null) return;
|
||||||
|
String name = profile.getName();
|
||||||
|
if (name == null) return;
|
||||||
|
ProfileTexture texture = account.getSkin(profile);
|
||||||
|
if (texture == null) return;
|
||||||
|
String url = texture.getUrl();
|
||||||
|
File file = getSkinFile(name);
|
||||||
|
if (!refresh && file.exists())
|
||||||
|
return;
|
||||||
|
new FileDownloadTask(NetworkUtils.toURL(url), file, proxy).run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,11 @@ import org.jackhuang.hmcl.Main;
|
|||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||||
|
import org.jackhuang.hmcl.auth.SpecificCharacterSelector;
|
||||||
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
import org.jackhuang.hmcl.download.DefaultDependencyManager;
|
||||||
import org.jackhuang.hmcl.launch.*;
|
import org.jackhuang.hmcl.launch.*;
|
||||||
import org.jackhuang.hmcl.mod.CurseCompletionTask;
|
import org.jackhuang.hmcl.mod.CurseCompletionTask;
|
||||||
import org.jackhuang.hmcl.setting.LauncherVisibility;
|
import org.jackhuang.hmcl.setting.*;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
|
||||||
import org.jackhuang.hmcl.setting.VersionSetting;
|
|
||||||
import org.jackhuang.hmcl.task.*;
|
import org.jackhuang.hmcl.task.*;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.DialogController;
|
import org.jackhuang.hmcl.ui.DialogController;
|
||||||
@@ -86,7 +84,7 @@ public final class LauncherHelper {
|
|||||||
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN)))
|
.then(Task.of(Schedulers.javafx(), () -> emitStatus(LoadingState.LOGGING_IN)))
|
||||||
.then(Task.of(Main.i18n("account.methods"), variables -> {
|
.then(Task.of(Main.i18n("account.methods"), variables -> {
|
||||||
try {
|
try {
|
||||||
variables.set("account", account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.INSTANCE.getProxy()));
|
variables.set("account", account.logIn(new SpecificCharacterSelector(Accounts.getCurrentCharacter(account)), Settings.INSTANCE.getProxy()));
|
||||||
} catch (AuthenticationException e) {
|
} catch (AuthenticationException e) {
|
||||||
variables.set("account", DialogController.logIn(account));
|
variables.set("account", DialogController.logIn(account));
|
||||||
JFXUtilities.runInFX(() -> Controllers.dialog(launchingStepsPane));
|
JFXUtilities.runInFX(() -> Controllers.dialog(launchingStepsPane));
|
||||||
|
|||||||
@@ -48,4 +48,25 @@ public final class Accounts {
|
|||||||
else return YGGDRASIL_ACCOUNT_KEY;
|
else return YGGDRASIL_ACCOUNT_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setCurrentCharacter(Account account, String character) {
|
||||||
|
account.getProperties().put("character", character);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCurrentCharacter(Account account) {
|
||||||
|
return Lang.get(account.getProperties(), "character", String.class, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCurrentCharacter(Map<Object, Object> storage) {
|
||||||
|
Map properties = Lang.get(storage, "properties", Map.class, null);
|
||||||
|
if (properties == null) return null;
|
||||||
|
return Lang.get(properties, "character", String.class, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getAccountId(Account account) {
|
||||||
|
return getAccountId(account.getUsername(), getCurrentCharacter(account));
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getAccountId(String username, String character) {
|
||||||
|
return username + ":" + character;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.google.gson.annotations.SerializedName;
|
|||||||
import org.jackhuang.hmcl.Main;
|
import org.jackhuang.hmcl.Main;
|
||||||
import org.jackhuang.hmcl.util.JavaVersion;
|
import org.jackhuang.hmcl.util.JavaVersion;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@@ -67,7 +68,7 @@ public final class Config {
|
|||||||
private Map<String, Profile> configurations = new TreeMap<>();
|
private Map<String, Profile> configurations = new TreeMap<>();
|
||||||
|
|
||||||
@SerializedName("accounts")
|
@SerializedName("accounts")
|
||||||
private Map<String, Map<Object, Object>> accounts = new TreeMap<>();
|
private List<Map<Object, Object>> accounts = new LinkedList<>();
|
||||||
|
|
||||||
@SerializedName("selectedAccount")
|
@SerializedName("selectedAccount")
|
||||||
private String selectedAccount = "";
|
private String selectedAccount = "";
|
||||||
@@ -198,11 +199,11 @@ public final class Config {
|
|||||||
Settings.INSTANCE.save();
|
Settings.INSTANCE.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Map<Object, Object>> getAccounts() {
|
public List<Map<Object, Object>> getAccounts() {
|
||||||
return accounts;
|
return accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAccounts(Map<String, Map<Object, Object>> accounts) {
|
public void setAccounts(List<Map<Object, Object>> accounts) {
|
||||||
this.accounts = accounts;
|
this.accounts = accounts;
|
||||||
Settings.INSTANCE.save();
|
Settings.INSTANCE.save();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.setting;
|
package org.jackhuang.hmcl.setting;
|
||||||
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
@@ -66,12 +65,12 @@ public class Settings {
|
|||||||
private Map<String, Account> accounts = new HashMap<>();
|
private Map<String, Account> accounts = new HashMap<>();
|
||||||
|
|
||||||
{
|
{
|
||||||
for (Map.Entry<String, Map<Object, Object>> entry : SETTINGS.getAccounts().entrySet()) {
|
for (Map<Object, Object> settings : SETTINGS.getAccounts()) {
|
||||||
String name = entry.getKey();
|
String characterName = Accounts.getCurrentCharacter(settings);
|
||||||
Map<Object, Object> settings = entry.getValue();
|
|
||||||
AccountFactory factory = Accounts.ACCOUNT_FACTORY.get(Lang.get(settings, "type", String.class, ""));
|
AccountFactory factory = Accounts.ACCOUNT_FACTORY.get(Lang.get(settings, "type", String.class, ""));
|
||||||
if (factory == null) {
|
if (factory == null || characterName == null) {
|
||||||
SETTINGS.getAccounts().remove(name);
|
// unrecognized account type, so remove it.
|
||||||
|
SETTINGS.getAccounts().remove(settings);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,17 +78,12 @@ public class Settings {
|
|||||||
try {
|
try {
|
||||||
account = factory.fromStorage(settings);
|
account = factory.fromStorage(settings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SETTINGS.getAccounts().remove(name);
|
SETTINGS.getAccounts().remove(settings);
|
||||||
// storage is malformed, delete.
|
// storage is malformed, delete.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Objects.equals(account.getUsername(), name)) {
|
accounts.put(Accounts.getAccountId(account), account);
|
||||||
SETTINGS.getAccounts().remove(name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts.put(name, account);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save();
|
save();
|
||||||
@@ -138,12 +132,10 @@ public class Settings {
|
|||||||
public void save() {
|
public void save() {
|
||||||
try {
|
try {
|
||||||
SETTINGS.getAccounts().clear();
|
SETTINGS.getAccounts().clear();
|
||||||
for (Map.Entry<String, Account> entry : accounts.entrySet()) {
|
for (Account account : accounts.values()) {
|
||||||
String name = entry.getKey();
|
|
||||||
Account account = entry.getValue();
|
|
||||||
Map<Object, Object> storage = account.toStorage();
|
Map<Object, Object> storage = account.toStorage();
|
||||||
storage.put("type", Accounts.getAccountType(account));
|
storage.put("type", Accounts.getAccountType(account));
|
||||||
SETTINGS.getAccounts().put(name, storage);
|
SETTINGS.getAccounts().add(storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileUtils.writeText(SETTINGS_FILE, GSON.toJson(SETTINGS));
|
FileUtils.writeText(SETTINGS_FILE, GSON.toJson(SETTINGS));
|
||||||
@@ -304,11 +296,11 @@ public class Settings {
|
|||||||
* ACCOUNTS *
|
* ACCOUNTS *
|
||||||
****************************************/
|
****************************************/
|
||||||
|
|
||||||
private final ImmediateObjectProperty<Account> selectedAccount = new ImmediateObjectProperty<Account>(this, "selectedAccount", getAccount(SETTINGS.getSelectedAccount())) {
|
private final ImmediateObjectProperty<Account> selectedAccount = new ImmediateObjectProperty<Account>(this, "selectedAccount", accounts.get(SETTINGS.getSelectedAccount())) {
|
||||||
@Override
|
@Override
|
||||||
public Account get() {
|
public Account get() {
|
||||||
Account a = super.get();
|
Account a = super.get();
|
||||||
if (a == null || !accounts.containsKey(a.getUsername())) {
|
if (a == null || !accounts.containsKey(Accounts.getAccountId(a))) {
|
||||||
Account acc = accounts.values().stream().findAny().orElse(null);
|
Account acc = accounts.values().stream().findAny().orElse(null);
|
||||||
set(acc);
|
set(acc);
|
||||||
return acc;
|
return acc;
|
||||||
@@ -317,7 +309,7 @@ public class Settings {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(Account newValue) {
|
public void set(Account newValue) {
|
||||||
if (newValue == null || accounts.containsKey(newValue.getUsername())) {
|
if (newValue == null || accounts.containsKey(Accounts.getAccountId(newValue))) {
|
||||||
super.set(newValue);
|
super.set(newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,7 +318,7 @@ public class Settings {
|
|||||||
public void invalidated() {
|
public void invalidated() {
|
||||||
super.invalidated();
|
super.invalidated();
|
||||||
|
|
||||||
SETTINGS.setSelectedAccount(getValue() == null ? "" : getValue().getUsername());
|
SETTINGS.setSelectedAccount(getValue() == null ? "" : Accounts.getAccountId(getValue()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -343,19 +335,25 @@ public class Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addAccount(Account account) {
|
public void addAccount(Account account) {
|
||||||
accounts.put(account.getUsername(), account);
|
accounts.put(Accounts.getAccountId(account), account);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Account getAccount(String name) {
|
public Account getAccount(String name, String character) {
|
||||||
return accounts.get(name);
|
return accounts.get(Accounts.getAccountId(name, character));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Account> getAccounts() {
|
public Collection<Account> getAccounts() {
|
||||||
return Collections.unmodifiableMap(accounts);
|
return Collections.unmodifiableCollection(accounts.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteAccount(String name) {
|
public void deleteAccount(String name, String character) {
|
||||||
accounts.remove(name);
|
accounts.remove(Accounts.getAccountId(name, character));
|
||||||
|
|
||||||
|
selectedAccount.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteAccount(Account account) {
|
||||||
|
accounts.remove(Accounts.getAccountId(account));
|
||||||
|
|
||||||
selectedAccount.get();
|
selectedAccount.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import org.jackhuang.hmcl.auth.Account;
|
|||||||
import org.jackhuang.hmcl.auth.OfflineAccount;
|
import org.jackhuang.hmcl.auth.OfflineAccount;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.game.AccountHelper;
|
import org.jackhuang.hmcl.game.AccountHelper;
|
||||||
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
|
|
||||||
@@ -53,8 +54,9 @@ public final class AccountItem extends StackPane {
|
|||||||
@FXML private JFXButton btnDelete;
|
@FXML private JFXButton btnDelete;
|
||||||
@FXML private JFXButton btnRefresh;
|
@FXML private JFXButton btnRefresh;
|
||||||
@FXML private Label lblUser;
|
@FXML private Label lblUser;
|
||||||
@FXML private JFXRadioButton chkSelected;
|
|
||||||
@FXML private Label lblType;
|
@FXML private Label lblType;
|
||||||
|
@FXML private Label lblEmail;
|
||||||
|
@FXML private JFXRadioButton chkSelected;
|
||||||
@FXML private JFXProgressBar pgsSkin;
|
@FXML private JFXProgressBar pgsSkin;
|
||||||
@FXML private ImageView portraitView;
|
@FXML private ImageView portraitView;
|
||||||
@FXML private HBox buttonPane;
|
@FXML private HBox buttonPane;
|
||||||
@@ -82,8 +84,9 @@ public final class AccountItem extends StackPane {
|
|||||||
|
|
||||||
chkSelected.getProperties().put("account", account);
|
chkSelected.getProperties().put("account", account);
|
||||||
chkSelected.setSelected(Settings.INSTANCE.getSelectedAccount() == account);
|
chkSelected.setSelected(Settings.INSTANCE.getSelectedAccount() == account);
|
||||||
lblUser.setText(account.getUsername());
|
lblUser.setText(Accounts.getCurrentCharacter(account));
|
||||||
lblType.setText(AccountsPage.accountType(account));
|
lblType.setText(AccountsPage.accountType(account));
|
||||||
|
lblEmail.setText(account.getUsername());
|
||||||
|
|
||||||
if (account instanceof YggdrasilAccount) {
|
if (account instanceof YggdrasilAccount) {
|
||||||
btnRefresh.setOnMouseClicked(e -> {
|
btnRefresh.setOnMouseClicked(e -> {
|
||||||
|
|||||||
@@ -17,33 +17,40 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui;
|
package org.jackhuang.hmcl.ui;
|
||||||
|
|
||||||
|
import com.jfoenix.concurrency.JFXUtilities;
|
||||||
import com.jfoenix.controls.*;
|
import com.jfoenix.controls.*;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.ScrollPane;
|
import javafx.scene.control.ScrollPane;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
|
import javafx.scene.image.ImageView;
|
||||||
|
import javafx.scene.layout.BorderPane;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import org.jackhuang.hmcl.Main;
|
import org.jackhuang.hmcl.Main;
|
||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.*;
|
||||||
import org.jackhuang.hmcl.auth.OfflineAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
||||||
import org.jackhuang.hmcl.auth.OfflineAccountFactory;
|
import org.jackhuang.hmcl.auth.InvalidCredentialsException;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.InvalidCredentialsException;
|
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
|
||||||
import org.jackhuang.hmcl.game.HMCLMultiCharacterSelector;
|
import org.jackhuang.hmcl.game.AccountHelper;
|
||||||
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
|
import org.jackhuang.hmcl.ui.construct.IconedItem;
|
||||||
import org.jackhuang.hmcl.ui.construct.Validator;
|
import org.jackhuang.hmcl.ui.construct.Validator;
|
||||||
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
|
import org.jackhuang.hmcl.ui.wizard.DecoratorPage;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
public final class AccountsPage extends StackPane implements DecoratorPage {
|
public final class AccountsPage extends StackPane implements DecoratorPage {
|
||||||
private final StringProperty title = new SimpleStringProperty(this, "title", Main.i18n("account"));
|
private final StringProperty title = new SimpleStringProperty(this, "title", Main.i18n("account"));
|
||||||
@@ -94,8 +101,8 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
|||||||
List<Node> children = new LinkedList<>();
|
List<Node> children = new LinkedList<>();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ToggleGroup group = new ToggleGroup();
|
ToggleGroup group = new ToggleGroup();
|
||||||
for (Map.Entry<String, Account> entry : Settings.INSTANCE.getAccounts().entrySet()) {
|
for (Account account : Settings.INSTANCE.getAccounts()) {
|
||||||
children.add(buildNode(++i, entry.getValue(), group));
|
children.add(buildNode(++i, account, group));
|
||||||
}
|
}
|
||||||
group.selectedToggleProperty().addListener((a, b, newValue) -> {
|
group.selectedToggleProperty().addListener((a, b, newValue) -> {
|
||||||
if (newValue != null)
|
if (newValue != null)
|
||||||
@@ -111,7 +118,7 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
|||||||
private Node buildNode(int i, Account account, ToggleGroup group) {
|
private Node buildNode(int i, Account account, ToggleGroup group) {
|
||||||
AccountItem item = new AccountItem(i, account, group);
|
AccountItem item = new AccountItem(i, account, group);
|
||||||
item.setOnDeleteButtonMouseClicked(e -> {
|
item.setOnDeleteButtonMouseClicked(e -> {
|
||||||
Settings.INSTANCE.deleteAccount(account.getUsername());
|
Settings.INSTANCE.deleteAccount(account);
|
||||||
Platform.runLater(this::loadAccounts);
|
Platform.runLater(this::loadAccounts);
|
||||||
});
|
});
|
||||||
return item;
|
return item;
|
||||||
@@ -140,7 +147,8 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
|||||||
default: throw new Error();
|
default: throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.INSTANCE.getProxy());
|
AuthInfo info = account.logIn(new CharacterSelector(), Settings.INSTANCE.getProxy());
|
||||||
|
Accounts.setCurrentCharacter(account, info.getUsername());
|
||||||
return account;
|
return account;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return e;
|
return e;
|
||||||
@@ -153,8 +161,18 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
|||||||
loadAccounts();
|
loadAccounts();
|
||||||
} else if (account instanceof InvalidCredentialsException) {
|
} else if (account instanceof InvalidCredentialsException) {
|
||||||
lblCreationWarning.setText(Main.i18n("account.failed.wrong_password"));
|
lblCreationWarning.setText(Main.i18n("account.failed.wrong_password"));
|
||||||
|
} else if (account instanceof NoCharacterException) {
|
||||||
|
lblCreationWarning.setText(Main.i18n("account.failed.no_charactor"));
|
||||||
|
} else if (account instanceof ServerDisconnectException) {
|
||||||
|
lblCreationWarning.setText(Main.i18n("account.failed.connect_authentication_server"));
|
||||||
|
} else if (account instanceof InvalidTokenException) {
|
||||||
|
lblCreationWarning.setText(Main.i18n("account.failed.invalid_token"));
|
||||||
|
} else if (account instanceof InvalidPasswordException) {
|
||||||
|
lblCreationWarning.setText(Main.i18n("account.failed.invalid_password"));
|
||||||
|
} else if (account instanceof NoSelectedCharacterException) {
|
||||||
|
dialog.close();
|
||||||
} else if (account instanceof Exception) {
|
} else if (account instanceof Exception) {
|
||||||
lblCreationWarning.setText(((Exception) account).getLocalizedMessage());
|
lblCreationWarning.setText(account.getClass() + ": " + ((Exception) account).getLocalizedMessage());
|
||||||
}
|
}
|
||||||
progressBar.setVisible(false);
|
progressBar.setVisible(false);
|
||||||
});
|
});
|
||||||
@@ -183,4 +201,76 @@ public final class AccountsPage extends StackPane implements DecoratorPage {
|
|||||||
else if (account instanceof YggdrasilAccount) return Main.i18n("account.methods.yggdrasil");
|
else if (account instanceof YggdrasilAccount) return Main.i18n("account.methods.yggdrasil");
|
||||||
else throw new Error(Main.i18n("account.methods.no_method") + ": " + account);
|
else throw new Error(Main.i18n("account.methods.no_method") + ": " + account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CharacterSelector extends BorderPane implements MultiCharacterSelector {
|
||||||
|
private AdvancedListBox listBox = new AdvancedListBox();
|
||||||
|
private JFXButton cancel = new JFXButton();
|
||||||
|
|
||||||
|
private CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
private GameProfile selectedProfile = null;
|
||||||
|
|
||||||
|
{
|
||||||
|
setStyle("-fx-padding: 8px;");
|
||||||
|
|
||||||
|
cancel.setText(Main.i18n("button.cancel"));
|
||||||
|
StackPane.setAlignment(cancel, Pos.BOTTOM_RIGHT);
|
||||||
|
cancel.setOnMouseClicked(e -> latch.countDown());
|
||||||
|
|
||||||
|
listBox.startCategory(Main.i18n("account.choose"));
|
||||||
|
|
||||||
|
setCenter(listBox);
|
||||||
|
|
||||||
|
HBox hbox = new HBox();
|
||||||
|
hbox.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
hbox.getChildren().add(cancel);
|
||||||
|
setBottom(hbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameProfile select(Account account, List<GameProfile> names) throws NoSelectedCharacterException {
|
||||||
|
if (!(account instanceof YggdrasilAccount))
|
||||||
|
return MultiCharacterSelector.DEFAULT.select(account, names);
|
||||||
|
YggdrasilAccount yggdrasilAccount = (YggdrasilAccount) account;
|
||||||
|
|
||||||
|
for (GameProfile profile : names) {
|
||||||
|
Image image;
|
||||||
|
try {
|
||||||
|
image = AccountHelper.getSkinImmediately(yggdrasilAccount, profile, 4, Settings.INSTANCE.getProxy());
|
||||||
|
} catch (Exception e) {
|
||||||
|
image = FXUtils.DEFAULT_ICON;
|
||||||
|
}
|
||||||
|
ImageView portraitView = new ImageView();
|
||||||
|
portraitView.setSmooth(false);
|
||||||
|
if (image == FXUtils.DEFAULT_ICON)
|
||||||
|
portraitView.setImage(FXUtils.DEFAULT_ICON);
|
||||||
|
else {
|
||||||
|
portraitView.setImage(image);
|
||||||
|
portraitView.setViewport(AccountHelper.getViewport(4));
|
||||||
|
}
|
||||||
|
FXUtils.limitSize(portraitView, 32, 32);
|
||||||
|
|
||||||
|
IconedItem accountItem = new IconedItem(portraitView, profile.getName());
|
||||||
|
accountItem.setOnMouseClicked(e -> {
|
||||||
|
selectedProfile = profile;
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
listBox.add(accountItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
JFXUtilities.runInFX(() -> Controllers.dialog(this));
|
||||||
|
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
|
||||||
|
JFXUtilities.runInFX(Controllers::closeDialog);
|
||||||
|
|
||||||
|
if (selectedProfile == null)
|
||||||
|
throw new NoSelectedCharacterException(account);
|
||||||
|
|
||||||
|
return selectedProfile;
|
||||||
|
} catch (InterruptedException ignore) {
|
||||||
|
throw new NoSelectedCharacterException(account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ package org.jackhuang.hmcl.ui;
|
|||||||
import com.jfoenix.concurrency.JFXUtilities;
|
import com.jfoenix.concurrency.JFXUtilities;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.image.Image;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.paint.Paint;
|
import javafx.scene.paint.Paint;
|
||||||
import org.jackhuang.hmcl.Main;
|
import org.jackhuang.hmcl.Main;
|
||||||
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.event.EventBus;
|
import org.jackhuang.hmcl.event.EventBus;
|
||||||
import org.jackhuang.hmcl.event.ProfileChangedEvent;
|
import org.jackhuang.hmcl.event.ProfileChangedEvent;
|
||||||
@@ -33,6 +35,7 @@ import org.jackhuang.hmcl.game.HMCLGameRepository;
|
|||||||
import org.jackhuang.hmcl.game.ModpackHelper;
|
import org.jackhuang.hmcl.game.ModpackHelper;
|
||||||
import org.jackhuang.hmcl.mod.Modpack;
|
import org.jackhuang.hmcl.mod.Modpack;
|
||||||
import org.jackhuang.hmcl.mod.UnsupportedModpackException;
|
import org.jackhuang.hmcl.mod.UnsupportedModpackException;
|
||||||
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
@@ -81,13 +84,17 @@ public final class LeftPaneController {
|
|||||||
accountItem.setVersionName(Main.i18n("account.missing"));
|
accountItem.setVersionName(Main.i18n("account.missing"));
|
||||||
accountItem.setGameVersion(Main.i18n("message.unknown"));
|
accountItem.setGameVersion(Main.i18n("message.unknown"));
|
||||||
} else {
|
} else {
|
||||||
accountItem.setVersionName(it.getUsername());
|
accountItem.setVersionName(Accounts.getCurrentCharacter(it));
|
||||||
accountItem.setGameVersion(AccountsPage.accountType(it));
|
accountItem.setGameVersion(AccountsPage.accountType(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it instanceof YggdrasilAccount)
|
if (it instanceof YggdrasilAccount) {
|
||||||
accountItem.setImage(AccountHelper.getSkin((YggdrasilAccount) it, 4), AccountHelper.getViewport(4));
|
Image image = AccountHelper.getSkin((YggdrasilAccount) it, 4);
|
||||||
else
|
if (image == FXUtils.DEFAULT_ICON)
|
||||||
|
accountItem.setImage(FXUtils.DEFAULT_ICON, null);
|
||||||
|
else
|
||||||
|
accountItem.setImage(image, AccountHelper.getViewport(4));
|
||||||
|
} else
|
||||||
accountItem.setImage(FXUtils.DEFAULT_ICON, null);
|
accountItem.setImage(FXUtils.DEFAULT_ICON, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ import javafx.scene.layout.StackPane;
|
|||||||
import org.jackhuang.hmcl.Main;
|
import org.jackhuang.hmcl.Main;
|
||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.InvalidCredentialsException;
|
import org.jackhuang.hmcl.auth.SpecificCharacterSelector;
|
||||||
|
import org.jackhuang.hmcl.auth.InvalidCredentialsException;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
|
||||||
import org.jackhuang.hmcl.game.HMCLMultiCharacterSelector;
|
import org.jackhuang.hmcl.setting.Accounts;
|
||||||
import org.jackhuang.hmcl.setting.Settings;
|
import org.jackhuang.hmcl.setting.Settings;
|
||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
@@ -68,7 +69,7 @@ public class YggdrasilAccountLoginPane extends StackPane {
|
|||||||
Task.ofResult("login", () -> {
|
Task.ofResult("login", () -> {
|
||||||
try {
|
try {
|
||||||
Account account = YggdrasilAccountFactory.INSTANCE.fromUsername(username, password);
|
Account account = YggdrasilAccountFactory.INSTANCE.fromUsername(username, password);
|
||||||
return account.logIn(HMCLMultiCharacterSelector.INSTANCE, Settings.INSTANCE.getProxy());
|
return account.logIn(new SpecificCharacterSelector(Accounts.getCurrentCharacter(oldAccount)), Settings.INSTANCE.getProxy());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
<center>
|
<center>
|
||||||
<VBox style="-fx-padding: 20 20 0 20;">
|
<VBox style="-fx-padding: 20 20 0 20;">
|
||||||
<Label fx:id="lblUser" style="-fx-font-size: 20;" wrapText="true" textAlignment="JUSTIFY" />
|
<Label fx:id="lblUser" style="-fx-font-size: 20;" wrapText="true" textAlignment="JUSTIFY" />
|
||||||
<Label fx:id="lblType" style="-fx-font-size: 10;" />
|
<Label fx:id="lblEmail" style="-fx-font-size: 12;" />
|
||||||
|
<Label fx:id="lblType" style="-fx-font-size: 12;" />
|
||||||
</VBox>
|
</VBox>
|
||||||
</center>
|
</center>
|
||||||
</BorderPane>
|
</BorderPane>
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
#
|
#
|
||||||
#author: huangyuhui, dxNeil
|
#author: huangyuhui, dxNeil
|
||||||
account=Accounts
|
account=Accounts
|
||||||
|
account.choose=Choose a character
|
||||||
account.create=Create a new account
|
account.create=Create a new account
|
||||||
account.email=Email
|
account.email=Email
|
||||||
account.failed.connect_authentication_server=Cannot connect the authentication server. Check your network.
|
account.failed.connect_authentication_server=Cannot connect the authentication server. Check your network.
|
||||||
account.failed.invalid_access_token=Invalid Access Token
|
|
||||||
account.failed.invalid_password=Invalid password
|
account.failed.invalid_password=Invalid password
|
||||||
account.failed.invalid_token=Please log out and re-input your password to log in.
|
account.failed.invalid_token=Please log out and re-input your password to log in.
|
||||||
account.failed.no_charactor=No character in this account.
|
account.failed.no_charactor=No character in this account.
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
#
|
#
|
||||||
#author: huangyuhui
|
#author: huangyuhui
|
||||||
account=账户
|
account=账户
|
||||||
|
account.choose=选择一个角色
|
||||||
account.create=新建账户
|
account.create=新建账户
|
||||||
account.email=邮箱
|
account.email=邮箱
|
||||||
account.failed.connect_authentication_server=无法连接认证服务器,可能是网络问题
|
account.failed.connect_authentication_server=无法连接认证服务器,可能是网络问题
|
||||||
account.failed.invalid_access_token=无效的访问令牌
|
|
||||||
account.failed.invalid_password=无效的密码
|
account.failed.invalid_password=无效的密码
|
||||||
account.failed.invalid_token=请尝试登出并重新输入密码登录
|
account.failed.invalid_token=请尝试登出并重新输入密码登录
|
||||||
account.failed.no_charactor=该帐号没有角色
|
account.failed.no_charactor=该帐号没有角色
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package org.jackhuang.hmcl.auth;
|
package org.jackhuang.hmcl.auth;
|
||||||
|
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,15 +27,48 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public abstract class Account {
|
public abstract class Account {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the account name (mostly email)
|
||||||
|
*/
|
||||||
public abstract String getUsername();
|
public abstract String getUsername();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* log in.
|
||||||
|
* @param selector selects a character
|
||||||
|
* @return the specific player's info.
|
||||||
|
* @throws AuthenticationException if server error occurred.
|
||||||
|
*/
|
||||||
public AuthInfo logIn(MultiCharacterSelector selector) throws AuthenticationException {
|
public AuthInfo logIn(MultiCharacterSelector selector) throws AuthenticationException {
|
||||||
return logIn(selector, Proxy.NO_PROXY);
|
return logIn(selector, Proxy.NO_PROXY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* log in.
|
||||||
|
* @param selector selects a character
|
||||||
|
* @param proxy by which connect to the server
|
||||||
|
* @return the specific player's info.
|
||||||
|
* @throws AuthenticationException if server error occurred.
|
||||||
|
*/
|
||||||
public abstract AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException;
|
public abstract AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException;
|
||||||
|
|
||||||
public abstract void logOut();
|
public abstract void logOut();
|
||||||
|
|
||||||
public abstract Map<Object, Object> toStorage();
|
protected abstract Map<Object, Object> toStorageImpl();
|
||||||
|
|
||||||
|
public final Map<Object, Object> toStorage() {
|
||||||
|
Map<Object, Object> storage = toStorageImpl();
|
||||||
|
if (!getProperties().isEmpty())
|
||||||
|
storage.put("properties", getProperties());
|
||||||
|
return storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Object, Object> properties = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To save some necessary extra information here.
|
||||||
|
* @return the property map.
|
||||||
|
*/
|
||||||
|
public final Map<Object, Object> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.auth;
|
package org.jackhuang.hmcl.auth;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,5 +33,13 @@ public abstract class AccountFactory<T extends Account> {
|
|||||||
|
|
||||||
public abstract T fromUsername(String username, String password);
|
public abstract T fromUsername(String username, String password);
|
||||||
|
|
||||||
public abstract T fromStorage(Map<Object, Object> storage);
|
protected abstract T fromStorageImpl(Map<Object, Object> storage);
|
||||||
|
|
||||||
|
public final T fromStorage(Map<Object, Object> storage) {
|
||||||
|
T account = fromStorageImpl(storage);
|
||||||
|
Map<?, ?> properties = Lang.get(storage, "properties", Map.class, null);
|
||||||
|
if (properties == null) return account;
|
||||||
|
account.getProperties().putAll(properties);
|
||||||
|
return account;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ package org.jackhuang.hmcl.auth;
|
|||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public class AuthenticationException extends Exception {
|
public class AuthenticationException extends Exception {
|
||||||
|
|
||||||
public AuthenticationException() {
|
public AuthenticationException() {
|
||||||
super();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AuthenticationException(String message) {
|
public AuthenticationException(String message) {
|
||||||
@@ -34,4 +32,8 @@ public class AuthenticationException extends Exception {
|
|||||||
public AuthenticationException(String message, Throwable cause) {
|
public AuthenticationException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AuthenticationException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,23 +15,21 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
package org.jackhuang.hmcl.auth;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* throws if wrong password or logging fails for too many times.
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public final class InvalidCredentialsException extends AuthenticationException {
|
public final class InvalidCredentialsException extends AuthenticationException {
|
||||||
|
|
||||||
private final YggdrasilAccount account;
|
private final Account account;
|
||||||
|
|
||||||
public InvalidCredentialsException(YggdrasilAccount account) {
|
public InvalidCredentialsException(Account account) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public YggdrasilAccount getAccount() {
|
public Account getAccount() {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* throws if wrong password.
|
||||||
|
*/
|
||||||
|
public class InvalidPasswordException extends AuthenticationException {
|
||||||
|
|
||||||
|
private Account account;
|
||||||
|
|
||||||
|
public InvalidPasswordException(Account account) {
|
||||||
|
super();
|
||||||
|
this.account = account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getAccount() {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,9 +15,10 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
package org.jackhuang.hmcl.auth;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||||
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -68,7 +68,7 @@ public class OfflineAccount extends Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Object, Object> toStorage() {
|
public Map<Object, Object> toStorageImpl() {
|
||||||
return Lang.mapOf(
|
return Lang.mapOf(
|
||||||
new Pair<>("uuid", uuid),
|
new Pair<>("uuid", uuid),
|
||||||
new Pair<>("username", username)
|
new Pair<>("username", username)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class OfflineAccountFactory extends AccountFactory<OfflineAccount> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OfflineAccount fromStorage(Map<Object, Object> storage) {
|
public OfflineAccount fromStorageImpl(Map<Object, Object> storage) {
|
||||||
Object username = storage.get("username");
|
Object username = storage.get("username");
|
||||||
if (username == null || !(username instanceof String))
|
if (username == null || !(username instanceof String))
|
||||||
throw new IllegalStateException("Offline account configuration malformed.");
|
throw new IllegalStateException("Offline account configuration malformed.");
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public class ServerDisconnectException extends AuthenticationException {
|
||||||
|
public ServerDisconnectException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerDisconnectException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerDisconnectException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerDisconnectException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Hello Minecraft! Launcher.
|
* Hello Minecraft! Launcher.
|
||||||
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
* Copyright (C) 2017 huangyuhui <huanghongxun2008@126.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -15,25 +15,28 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
* along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.game;
|
package org.jackhuang.hmcl.auth;
|
||||||
|
|
||||||
import org.jackhuang.hmcl.auth.Account;
|
|
||||||
import org.jackhuang.hmcl.auth.MultiCharacterSelector;
|
|
||||||
import org.jackhuang.hmcl.auth.NoSelectedCharacterException;
|
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author huangyuhui
|
* Select character by name.
|
||||||
*/
|
*/
|
||||||
public final class HMCLMultiCharacterSelector implements MultiCharacterSelector {
|
public class SpecificCharacterSelector implements MultiCharacterSelector {
|
||||||
public static final HMCLMultiCharacterSelector INSTANCE = new HMCLMultiCharacterSelector();
|
private final String id;
|
||||||
|
|
||||||
private HMCLMultiCharacterSelector() {}
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param id character's name.
|
||||||
|
*/
|
||||||
|
public SpecificCharacterSelector(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GameProfile select(Account account, List<GameProfile> names) throws NoSelectedCharacterException {
|
public GameProfile select(Account account, List<GameProfile> names) throws NoSelectedCharacterException {
|
||||||
return names.stream().findFirst().orElseThrow(() -> new NoSelectedCharacterException(account));
|
return names.stream().filter(profile -> profile.getName().equals(id)).findAny().orElseThrow(() -> new NoSelectedCharacterException(account));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,8 +32,8 @@ public final class AuthenticationRequest {
|
|||||||
private final String clientToken;
|
private final String clientToken;
|
||||||
|
|
||||||
private final Map<String, Object> agent = Lang.mapOf(
|
private final Map<String, Object> agent = Lang.mapOf(
|
||||||
new Pair("name", "minecraft"),
|
new Pair<>("name", "minecraft"),
|
||||||
new Pair("version", 1));
|
new Pair<>("version", 1));
|
||||||
|
|
||||||
private final boolean requestUser = true;
|
private final boolean requestUser = true;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ package org.jackhuang.hmcl.auth.yggdrasil;
|
|||||||
*
|
*
|
||||||
* @author huangyuhui
|
* @author huangyuhui
|
||||||
*/
|
*/
|
||||||
public final class Response {
|
public final class AuthenticationResponse {
|
||||||
|
|
||||||
private final String accessToken;
|
private final String accessToken;
|
||||||
private final String clientToken;
|
private final String clientToken;
|
||||||
@@ -32,11 +32,11 @@ public final class Response {
|
|||||||
private final String errorMessage;
|
private final String errorMessage;
|
||||||
private final String cause;
|
private final String cause;
|
||||||
|
|
||||||
public Response() {
|
public AuthenticationResponse() {
|
||||||
this(null, null, null, null, null, null, null, null);
|
this(null, null, null, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response(String accessToken, String clientToken, GameProfile selectedProfile, GameProfile[] availableProfiles, User user, String error, String errorMessage, String cause) {
|
public AuthenticationResponse(String accessToken, String clientToken, GameProfile selectedProfile, GameProfile[] availableProfiles, User user, String error, String errorMessage, String cause) {
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
this.clientToken = clientToken;
|
this.clientToken = clientToken;
|
||||||
this.selectedProfile = selectedProfile;
|
this.selectedProfile = selectedProfile;
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.yggdrasil;
|
||||||
|
|
||||||
|
public class ProfileResponse {
|
||||||
|
private final String id;
|
||||||
|
private final String name;
|
||||||
|
private final PropertyMap properties;
|
||||||
|
|
||||||
|
public ProfileResponse() {
|
||||||
|
this("", "", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileResponse(String id, String name, PropertyMap properties) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyMap getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.yggdrasil;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
public final class ProfileTexture {
|
||||||
|
|
||||||
|
private final String url;
|
||||||
|
private final Map<String, String> metadata;
|
||||||
|
|
||||||
|
public ProfileTexture() {
|
||||||
|
this(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileTexture(String url, Map<String, String> metadata) {
|
||||||
|
this.url = url;
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMetadata(String key) {
|
||||||
|
if (metadata == null)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return metadata.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
SKIN, CAPE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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.yggdrasil;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.Immutable;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
public final class TextureResponse {
|
||||||
|
private final UUID profileId;
|
||||||
|
private final String profileName;
|
||||||
|
private final Map<ProfileTexture.Type, ProfileTexture> textures;
|
||||||
|
|
||||||
|
public TextureResponse() {
|
||||||
|
this(UUID.randomUUID(), "", Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureResponse(UUID profileId, String profileName, Map<ProfileTexture.Type, ProfileTexture> textures) {
|
||||||
|
this.profileId = profileId;
|
||||||
|
this.profileName = profileName;
|
||||||
|
this.textures = textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getProfileId() {
|
||||||
|
return profileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProfileName() {
|
||||||
|
return profileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<ProfileTexture.Type, ProfileTexture> getTextures() {
|
||||||
|
return textures == null ? null : Collections.unmodifiableMap(textures);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import com.google.gson.Gson;
|
|||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonParseException;
|
import com.google.gson.JsonParseException;
|
||||||
import org.jackhuang.hmcl.auth.*;
|
import org.jackhuang.hmcl.auth.*;
|
||||||
|
import org.jackhuang.hmcl.util.Charsets;
|
||||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||||
@@ -28,10 +29,7 @@ import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -63,7 +61,7 @@ public final class YggdrasilAccount extends Account {
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserId() {
|
public String getCurrentCharacterName() {
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +144,7 @@ public final class YggdrasilAccount extends Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void logIn1(URL url, Object input, Proxy proxy) throws AuthenticationException {
|
private void logIn1(URL url, Object input, Proxy proxy) throws AuthenticationException {
|
||||||
Response response = makeRequest(url, input, proxy);
|
AuthenticationResponse response = makeRequest(url, input, proxy);
|
||||||
if (response == null || !clientToken.equals(response.getClientToken()))
|
if (response == null || !clientToken.equals(response.getClientToken()))
|
||||||
throw new AuthenticationException("Client token changed");
|
throw new AuthenticationException("Client token changed");
|
||||||
|
|
||||||
@@ -183,13 +181,13 @@ public final class YggdrasilAccount extends Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Object, Object> toStorage() {
|
public Map<Object, Object> toStorageImpl() {
|
||||||
HashMap<Object, Object> result = new HashMap<>();
|
HashMap<Object, Object> result = new HashMap<>();
|
||||||
|
|
||||||
result.put(STORAGE_KEY_USER_NAME, getUsername());
|
result.put(STORAGE_KEY_USER_NAME, getUsername());
|
||||||
result.put(STORAGE_KEY_CLIENT_TOKEN, getClientToken());
|
result.put(STORAGE_KEY_CLIENT_TOKEN, getClientToken());
|
||||||
if (getUserId() != null)
|
if (getCurrentCharacterName() != null)
|
||||||
result.put(STORAGE_KEY_USER_ID, getUserId());
|
result.put(STORAGE_KEY_USER_ID, getCurrentCharacterName());
|
||||||
if (!userProperties.isEmpty())
|
if (!userProperties.isEmpty())
|
||||||
result.put(STORAGE_KEY_USER_PROPERTIES, userProperties.toList());
|
result.put(STORAGE_KEY_USER_PROPERTIES, userProperties.toList());
|
||||||
GameProfile profile = selectedProfile;
|
GameProfile profile = selectedProfile;
|
||||||
@@ -207,10 +205,10 @@ public final class YggdrasilAccount extends Account {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response makeRequest(URL url, Object input, Proxy proxy) throws AuthenticationException {
|
private AuthenticationResponse makeRequest(URL url, Object input, Proxy proxy) throws AuthenticationException {
|
||||||
try {
|
try {
|
||||||
String jsonResult = input == null ? NetworkUtils.doGet(url, proxy) : NetworkUtils.doPost(url, GSON.toJson(input), "application/json", proxy);
|
String jsonResult = input == null ? NetworkUtils.doGet(url, proxy) : NetworkUtils.doPost(url, GSON.toJson(input), "application/json", proxy);
|
||||||
Response response = GSON.fromJson(jsonResult, Response.class);
|
AuthenticationResponse response = GSON.fromJson(jsonResult, AuthenticationResponse.class);
|
||||||
if (response == null)
|
if (response == null)
|
||||||
return null;
|
return null;
|
||||||
if (!StringUtils.isBlank(response.getError())) {
|
if (!StringUtils.isBlank(response.getError())) {
|
||||||
@@ -219,12 +217,14 @@ public final class YggdrasilAccount extends Account {
|
|||||||
throw new InvalidCredentialsException(this);
|
throw new InvalidCredentialsException(this);
|
||||||
else if (response.getErrorMessage().contains("Invalid token"))
|
else if (response.getErrorMessage().contains("Invalid token"))
|
||||||
throw new InvalidTokenException(this);
|
throw new InvalidTokenException(this);
|
||||||
|
else if (response.getErrorMessage().contains("Invalid username or password"))
|
||||||
|
throw new InvalidPasswordException(this);
|
||||||
throw new AuthenticationException(response.getError() + ": " + response.getErrorMessage());
|
throw new AuthenticationException(response.getError() + ": " + response.getErrorMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AuthenticationException("Unable to connect to authentication server", e);
|
throw new ServerDisconnectException(e);
|
||||||
} catch (JsonParseException e) {
|
} catch (JsonParseException e) {
|
||||||
throw new AuthenticationException("Unable to parse server response", e);
|
throw new AuthenticationException("Unable to parse server response", e);
|
||||||
}
|
}
|
||||||
@@ -242,12 +242,31 @@ public final class YggdrasilAccount extends Account {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ProfileTexture getSkin(GameProfile profile) throws IOException, JsonParseException {
|
||||||
|
if (StringUtils.isBlank(userId))
|
||||||
|
throw new IllegalStateException("Not logged in");
|
||||||
|
|
||||||
|
ProfileResponse response = GSON.fromJson(NetworkUtils.doGet(NetworkUtils.toURL(BASE_PROFILE + UUIDTypeAdapter.fromUUID(profile.getId()))), ProfileResponse.class);
|
||||||
|
if (response.getProperties() == null) return null;
|
||||||
|
Property textureProperty = response.getProperties().get("textures");
|
||||||
|
if (textureProperty == null) return null;
|
||||||
|
|
||||||
|
TextureResponse texture;
|
||||||
|
String json = new String(Base64.getDecoder().decode(textureProperty.getValue()), Charsets.UTF_8);
|
||||||
|
texture = GSON.fromJson(json, TextureResponse.class);
|
||||||
|
if (texture == null || texture.getTextures() == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return texture.getTextures().get(ProfileTexture.Type.SKIN);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "YggdrasilAccount[username=" + getUsername() + "]";
|
return "YggdrasilAccount[username=" + getUsername() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String BASE_URL = "https://authserver.mojang.com/";
|
private static final String BASE_URL = "http://localhost:8080/authserver/"; //"https://authserver.mojang.com/";
|
||||||
|
private static final String BASE_PROFILE = "http://localhost:8080/sessionserver/session/minecraft/profile/"; //"https://sessionserver.mojang.com/session/minecraft/profile/";
|
||||||
private static final URL ROUTE_AUTHENTICATE = NetworkUtils.toURL(BASE_URL + "authenticate");
|
private static final URL ROUTE_AUTHENTICATE = NetworkUtils.toURL(BASE_URL + "authenticate");
|
||||||
private static final URL ROUTE_REFRESH = NetworkUtils.toURL(BASE_URL + "refresh");
|
private static final URL ROUTE_REFRESH = NetworkUtils.toURL(BASE_URL + "refresh");
|
||||||
private static final URL ROUTE_VALIDATE = NetworkUtils.toURL(BASE_URL + "validate");
|
private static final URL ROUTE_VALIDATE = NetworkUtils.toURL(BASE_URL + "validate");
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ public final class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccou
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public YggdrasilAccount fromStorage(Map<Object, Object> storage) {
|
public YggdrasilAccount fromStorageImpl(Map<Object, Object> storage) {
|
||||||
String username = Lang.get(storage, STORAGE_KEY_USER_NAME, String.class)
|
String username = Lang.get(storage, STORAGE_KEY_USER_NAME, String.class)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_USER_NAME));
|
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_USER_NAME));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user