mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
account refactoring, eros: wip connecting to server
This commit is contained in:
parent
06fc142d51
commit
9f6c2fb6b0
@ -50,6 +50,8 @@ object Minosoft {
|
|||||||
val GLOBAL_EVENT_MASTER = GlobalEventMaster()
|
val GLOBAL_EVENT_MASTER = GlobalEventMaster()
|
||||||
val LANGUAGE_MANAGER = MultiLanguageManager()
|
val LANGUAGE_MANAGER = MultiLanguageManager()
|
||||||
val START_UP_LATCH = CountUpAndDownLatch(1)
|
val START_UP_LATCH = CountUpAndDownLatch(1)
|
||||||
|
|
||||||
|
@Deprecated("Will be singleton interface")
|
||||||
lateinit var config: Configuration
|
lateinit var config: Configuration
|
||||||
|
|
||||||
var initialized: Boolean = false
|
var initialized: Boolean = false
|
||||||
|
@ -34,7 +34,7 @@ class Configuration(private val configName: String = RunConfiguration.CONFIG_FIL
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
val config = JSONSerializer.MAP_ADAPTER.fromJson(Util.readFile(file.absolutePath))!!
|
val config = JSONSerializer.MUTABLE_MAP_ADAPTER.fromJson(Util.readFile(file.absolutePath))!!
|
||||||
|
|
||||||
migrate(config)
|
migrate(config)
|
||||||
var wasMigrated = false
|
var wasMigrated = false
|
||||||
|
@ -14,12 +14,22 @@
|
|||||||
package de.bixilon.minosoft.config.config.account
|
package de.bixilon.minosoft.config.config.account
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.data.accounts.Account
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
|
import de.bixilon.minosoft.modding.event.events.account.AccountSelectEvent
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class AccountConfig(
|
data class AccountConfig(
|
||||||
var selected: String = "",
|
@Json(name = "selected") var selectedAccountId: String? = null,
|
||||||
@Json(name = "client_token")
|
@Json(name = "client_token") var clientToken: String = UUID.randomUUID().toString(),
|
||||||
var clientToken: String = UUID.randomUUID().toString(),
|
|
||||||
val entries: MutableMap<String, Account> = mutableMapOf(),
|
val entries: MutableMap<String, Account> = mutableMapOf(),
|
||||||
)
|
) {
|
||||||
|
@Transient
|
||||||
|
var selected: Account? = null
|
||||||
|
get() = entries[selectedAccountId]
|
||||||
|
set(value) {
|
||||||
|
Minosoft.GLOBAL_EVENT_MASTER.fireEvent(AccountSelectEvent(selected, value))
|
||||||
|
field // To allow transient for moshi
|
||||||
|
selectedAccountId = value?.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,7 +25,7 @@ data class Server(
|
|||||||
val id: Int = nextServerId++, // ToDo: Is duplicated in config (first key, then in value)
|
val id: Int = nextServerId++, // ToDo: Is duplicated in config (first key, then in value)
|
||||||
var address: String,
|
var address: String,
|
||||||
var name: ChatComponent = ChatComponent.of(address),
|
var name: ChatComponent = ChatComponent.of(address),
|
||||||
@Json(name = "version") var desiredVersion: Int = -1,
|
@Json(name = "version") var forcedVersion: Int? = null,
|
||||||
@Json(name = "favicon") var faviconHash: String? = null,
|
@Json(name = "favicon") var faviconHash: String? = null,
|
||||||
var type: ServerTypes = ServerTypes.NORMAL,
|
var type: ServerTypes = ServerTypes.NORMAL,
|
||||||
) {
|
) {
|
||||||
@ -56,6 +56,11 @@ data class Server(
|
|||||||
if (id > nextServerId) {
|
if (id > nextServerId) {
|
||||||
nextServerId = id + 1
|
nextServerId = id + 1
|
||||||
}
|
}
|
||||||
|
forcedVersion?.let {
|
||||||
|
if (it < 0) {
|
||||||
|
forcedVersion = null
|
||||||
|
}
|
||||||
|
}
|
||||||
faviconHash?.let { favicon = AssetsUtil.readAsset(it, true) }
|
faviconHash?.let { favicon = AssetsUtil.readAsset(it, true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.bixilon.minosoft.data.accounts;
|
|
||||||
|
|
||||||
import de.bixilon.minosoft.Minosoft;
|
|
||||||
import de.bixilon.minosoft.util.logging.Log;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.MojangJoinServerErrorException;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.NoNetworkConnectionException;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public abstract class Account {
|
|
||||||
protected final String username;
|
|
||||||
protected final UUID uuid;
|
|
||||||
|
|
||||||
protected Account(String username, UUID uuid) {
|
|
||||||
this.username = username;
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addAccount(Account account) {
|
|
||||||
Minosoft.config.getConfig().getAccount().getEntries().put(account.getId(), account);
|
|
||||||
account.saveToConfig();
|
|
||||||
Log.info(String.format("Added and saved account (type=%s, id=%s, username=%s, uuid=%s)", account.getClass().getSimpleName(), account.getId(), account.getUsername(), account.getUUID()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getUUID() {
|
|
||||||
return this.uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Map<String, Object> serialize();
|
|
||||||
|
|
||||||
public abstract void join(String serverId) throws MojangJoinServerErrorException, NoNetworkConnectionException;
|
|
||||||
|
|
||||||
public abstract boolean select();
|
|
||||||
|
|
||||||
public abstract void logout();
|
|
||||||
|
|
||||||
public abstract String getId();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return getId().hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (super.equals(obj)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (hashCode() != obj.hashCode()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Account account = (Account) obj;
|
|
||||||
return getId().equals(account.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveToConfig() {
|
|
||||||
Minosoft.config.getConfig().getAccount().getEntries().put(this.getId(), this);
|
|
||||||
Minosoft.config.saveToFile();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* Minosoft
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
*
|
*
|
||||||
* 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 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.
|
||||||
*
|
*
|
||||||
@ -11,19 +11,18 @@
|
|||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.bixilon.minosoft.util.mojang.api.exceptions;
|
package de.bixilon.minosoft.data.accounts
|
||||||
|
|
||||||
public class NoNetworkConnectionException extends Exception {
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
|
||||||
public NoNetworkConnectionException(Exception cause) {
|
abstract class Account(
|
||||||
super(cause);
|
val username: String,
|
||||||
}
|
) {
|
||||||
|
abstract val id: String
|
||||||
|
abstract val type: ResourceLocation
|
||||||
|
|
||||||
public NoNetworkConnectionException(String message) {
|
abstract fun join(serverId: String)
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NoNetworkConnectionException() {
|
abstract fun logout()
|
||||||
|
abstract fun verify()
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.accounts
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.registries.CompanionResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.json.JSONSerializer
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
abstract class AccountType(`class`: KClass<out Account>) : CompanionResourceLocation {
|
||||||
|
val TYPE = JSONSerializer.MOSHI.adapter(`class`.java)
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.accounts
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.accounts.types.MicrosoftAccount
|
||||||
|
import de.bixilon.minosoft.data.accounts.types.MojangAccount
|
||||||
|
import de.bixilon.minosoft.data.accounts.types.OfflineAccount
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.asResourceLocationMap
|
||||||
|
|
||||||
|
object AccountTypes {
|
||||||
|
val ACCOUNT_TYPES: Map<ResourceLocation, AccountType> = listOf(
|
||||||
|
MicrosoftAccount,
|
||||||
|
MojangAccount,
|
||||||
|
OfflineAccount,
|
||||||
|
).asResourceLocationMap()
|
||||||
|
}
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.bixilon.minosoft.data.accounts;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import de.bixilon.minosoft.util.Util;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class MicrosoftAccount extends MojangAccount {
|
|
||||||
|
|
||||||
public MicrosoftAccount(String accessToken, String id, UUID uuid, String username) {
|
|
||||||
super(accessToken, id, uuid, username, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MicrosoftAccount deserialize(JsonObject json) {
|
|
||||||
return new MicrosoftAccount(json.get("accessToken").getAsString(), json.get("id").getAsString(), Util.getUUIDFromString(json.get("uuid").getAsString()), json.get("username").getAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> serialize() {
|
|
||||||
Map<String, Object> json = super.serialize();
|
|
||||||
json.put("type", "microsoft");
|
|
||||||
json.remove("email");
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,128 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.bixilon.minosoft.data.accounts;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import de.bixilon.minosoft.Minosoft;
|
|
||||||
import de.bixilon.minosoft.util.Util;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.MojangAuthentication;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.AuthenticationException;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.MojangJoinServerErrorException;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.NoNetworkConnectionException;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class MojangAccount extends Account {
|
|
||||||
protected final String id;
|
|
||||||
protected final String email;
|
|
||||||
protected String accessToken;
|
|
||||||
protected RefreshStates lastRefreshStatus;
|
|
||||||
protected boolean needsRefresh = true;
|
|
||||||
|
|
||||||
public MojangAccount(String username, JsonObject json) {
|
|
||||||
super(json.getAsJsonObject("selectedProfile").get("name").getAsString(), Util.getUUIDFromString(json.getAsJsonObject("selectedProfile").get("id").getAsString()));
|
|
||||||
this.accessToken = json.get("accessToken").getAsString();
|
|
||||||
this.id = json.getAsJsonObject("user").get("id").getAsString();
|
|
||||||
this.email = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MojangAccount(String accessToken, String id, UUID uuid, String username, String email) {
|
|
||||||
super(username, uuid);
|
|
||||||
this.accessToken = accessToken;
|
|
||||||
this.id = id;
|
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MojangAccount deserialize(Map<String, Object> json) {
|
|
||||||
return new MojangAccount((String) json.get("accessToken"), (String) json.get("id"), Util.getUUIDFromString((String) json.get("uuid")), (String) json.get("username"), (String) json.get("email"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> serialize() {
|
|
||||||
Map<String, Object> json = new HashMap<>();
|
|
||||||
json.put("id", this.id);
|
|
||||||
json.put("accessToken", this.accessToken);
|
|
||||||
json.put("uuid", getUUID().toString());
|
|
||||||
json.put("username", getUsername());
|
|
||||||
json.put("email", this.email);
|
|
||||||
json.put("type", "mojang");
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void join(String serverId) throws MojangJoinServerErrorException, NoNetworkConnectionException {
|
|
||||||
MojangAuthentication.joinServer(this, serverId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean select() {
|
|
||||||
if (this.needsRefresh) {
|
|
||||||
return refreshToken() != RefreshStates.ERROR;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logout() {
|
|
||||||
Minosoft.config.getConfig().getAccount().getEntries().remove(this.getId());
|
|
||||||
Minosoft.config.saveToFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RefreshStates refreshToken() {
|
|
||||||
try {
|
|
||||||
this.accessToken = MojangAuthentication.refresh(this.accessToken);
|
|
||||||
this.lastRefreshStatus = RefreshStates.SUCCESSFUL;
|
|
||||||
} catch (NoNetworkConnectionException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
this.lastRefreshStatus = RefreshStates.FAILED;
|
|
||||||
} catch (AuthenticationException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
this.lastRefreshStatus = RefreshStates.ERROR;
|
|
||||||
}
|
|
||||||
return this.lastRefreshStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAccessToken() {
|
|
||||||
return this.accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAccessToken(String accessToken) {
|
|
||||||
this.accessToken = accessToken;
|
|
||||||
this.needsRefresh = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEmail() {
|
|
||||||
return this.email;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean needsRefresh() {
|
|
||||||
return this.needsRefresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNeedRefresh(boolean needsRefresh) {
|
|
||||||
this.needsRefresh = needsRefresh;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum RefreshStates {
|
|
||||||
SUCCESSFUL,
|
|
||||||
ERROR, // account not valid anymore
|
|
||||||
FAILED // error occurred while checking -> Unknown state
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.bixilon.minosoft.data.accounts;
|
|
||||||
|
|
||||||
import de.bixilon.minosoft.util.Util;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class OfflineAccount extends Account {
|
|
||||||
public OfflineAccount(String username) {
|
|
||||||
super(username, UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public OfflineAccount(String username, UUID uuid) {
|
|
||||||
super(username, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OfflineAccount deserialize(Map<String, Object> json) {
|
|
||||||
return new OfflineAccount((String) json.get("username"), Util.getUUIDFromString((String) json.get("uuid")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> serialize() {
|
|
||||||
Map<String, Object> json = new HashMap<>();
|
|
||||||
json.put("username", getUsername());
|
|
||||||
json.put("uuid", getUUID().toString());
|
|
||||||
json.put("type", "offline");
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void join(String serverId) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean select() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void logout() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return getUsername() + ":" + getUUID().toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.accounts.types
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
|
import de.bixilon.minosoft.data.accounts.AccountType
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MicrosoftAccount(
|
||||||
|
override val id: String,
|
||||||
|
username: String,
|
||||||
|
val uuid: UUID,
|
||||||
|
val email: String,
|
||||||
|
@Json(name = "access_token") private var accessToken: String,
|
||||||
|
) : Account(username) {
|
||||||
|
override val type: ResourceLocation = RESOURCE_LOCATION
|
||||||
|
|
||||||
|
override fun join(serverId: String) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logout() {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun verify() {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : AccountType(MicrosoftAccount::class) {
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:microsoft_account".asResourceLocation()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.accounts.types
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import de.bixilon.minosoft.Minosoft
|
||||||
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
|
import de.bixilon.minosoft.data.accounts.AccountType
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.nullCast
|
||||||
|
import de.bixilon.minosoft.util.KUtil.trim
|
||||||
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
|
import de.bixilon.minosoft.util.http.HTTP2.postJson
|
||||||
|
import de.bixilon.minosoft.util.http.exceptions.AuthenticationException
|
||||||
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
|
import de.bixilon.minosoft.util.logging.LogLevels
|
||||||
|
import de.bixilon.minosoft.util.logging.LogMessageType
|
||||||
|
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class MojangAccount(
|
||||||
|
override val id: String,
|
||||||
|
username: String,
|
||||||
|
val uuid: UUID,
|
||||||
|
val email: String,
|
||||||
|
@Json(name = "access_token") private var accessToken: String,
|
||||||
|
) : Account(username) {
|
||||||
|
private var refreshed: Boolean = false
|
||||||
|
override val type: ResourceLocation = RESOURCE_LOCATION
|
||||||
|
|
||||||
|
override fun join(serverId: String) {
|
||||||
|
val response = mutableMapOf(
|
||||||
|
"accessToken" to accessToken,
|
||||||
|
"selectedProfile" to uuid.trim(),
|
||||||
|
"serverId" to serverId,
|
||||||
|
).postJson(MOJANG_URL_JOIN)
|
||||||
|
|
||||||
|
response.body!!
|
||||||
|
|
||||||
|
if (response.statusCode != 204) {
|
||||||
|
throw AuthenticationException(response.statusCode, response.body["errorMessage"]?.nullCast())
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang server join successful (username=$username, serverId=$serverId)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun logout() {
|
||||||
|
val response = mutableMapOf(
|
||||||
|
"accessToken" to accessToken,
|
||||||
|
"clientToken" to Minosoft.config.config.account.clientToken,
|
||||||
|
).postJson(MOJANG_URL_INVALIDATE)
|
||||||
|
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw AuthenticationException(response.statusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang account login successful (username=$username)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun verify() {
|
||||||
|
if (refreshed) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refresh() {
|
||||||
|
val response = mutableMapOf(
|
||||||
|
"accessToken" to accessToken,
|
||||||
|
"clientToken" to Minosoft.config.config.account.clientToken,
|
||||||
|
).postJson(MOJANG_URL_REFRESH)
|
||||||
|
|
||||||
|
response.body!!
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw AuthenticationException(response.statusCode, response.body["errorMessage"].nullCast())
|
||||||
|
}
|
||||||
|
|
||||||
|
this.accessToken = response.body["accessToken"].unsafeCast()
|
||||||
|
|
||||||
|
refreshed = true
|
||||||
|
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang account refresh successful (username=$username)" }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : AccountType(MojangAccount::class) {
|
||||||
|
private const val MOJANG_URL_LOGIN = "https://authserver.mojang.com/authenticate"
|
||||||
|
private const val MOJANG_URL_JOIN = "https://sessionserver.mojang.com/session/minecraft/join"
|
||||||
|
private const val MOJANG_URL_REFRESH = "https://authserver.mojang.com/refresh"
|
||||||
|
private const val MOJANG_URL_INVALIDATE = "https://authserver.mojang.com/invalidate"
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:mojang_account".asResourceLocation()
|
||||||
|
|
||||||
|
fun login(clientToken: String = Minosoft.config.config.account.clientToken, email: String, password: String): MojangAccount {
|
||||||
|
val response = mutableMapOf(
|
||||||
|
"agent" to mutableMapOf(
|
||||||
|
"name" to "Minecraft",
|
||||||
|
"version" to 1,
|
||||||
|
),
|
||||||
|
"username" to email,
|
||||||
|
"password" to password,
|
||||||
|
"clientToken" to clientToken,
|
||||||
|
"requestUser" to true,
|
||||||
|
).postJson(MOJANG_URL_LOGIN)
|
||||||
|
|
||||||
|
response.body!!
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw AuthenticationException(response.statusCode, response.body["errorMessage"]?.nullCast())
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.log(LogMessageType.AUTHENTICATION, LogLevels.VERBOSE) { "Mojang login successful (email=$email)" }
|
||||||
|
|
||||||
|
return MojangAccount(
|
||||||
|
id = response.body["user"].asCompound()["id"].unsafeCast(),
|
||||||
|
username = response.body["selectedProfile"].asCompound()["name"].unsafeCast(),
|
||||||
|
uuid = response.body["selectedProfile"].asCompound()["id"].unsafeCast(),
|
||||||
|
email = email,
|
||||||
|
accessToken = response.body["accessToken"].unsafeCast(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.accounts.types
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
|
import de.bixilon.minosoft.data.accounts.AccountType
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
|
|
||||||
|
class OfflineAccount(username: String) : Account(username) {
|
||||||
|
override val id: String = username
|
||||||
|
override val type: ResourceLocation = RESOURCE_LOCATION
|
||||||
|
|
||||||
|
override fun join(serverId: String) {}
|
||||||
|
|
||||||
|
override fun logout() {}
|
||||||
|
|
||||||
|
override fun verify() {}
|
||||||
|
|
||||||
|
companion object : AccountType(OfflineAccount::class) {
|
||||||
|
override val RESOURCE_LOCATION: ResourceLocation = "minosoft:offline_account".asResourceLocation()
|
||||||
|
}
|
||||||
|
}
|
@ -25,11 +25,13 @@ object Eros {
|
|||||||
private val TITLE = "minosoft:eros_window_title".asResourceLocation()
|
private val TITLE = "minosoft:eros_window_title".asResourceLocation()
|
||||||
private val LAYOUT = "minosoft:eros/main/main.fxml".asResourceLocation()
|
private val LAYOUT = "minosoft:eros/main/main.fxml".asResourceLocation()
|
||||||
|
|
||||||
|
lateinit var mainErosController: MainErosController
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
Minosoft.GLOBAL_EVENT_MASTER.registerEvent(CallbackEventInvoker.of<FinishInitializingEvent> {
|
Minosoft.GLOBAL_EVENT_MASTER.registerEvent(CallbackEventInvoker.of<FinishInitializingEvent> {
|
||||||
Platform.runLater {
|
Platform.runLater {
|
||||||
val mainErosController = JavaFXUtil.openModal<MainErosController>(TITLE, LAYOUT)
|
mainErosController = JavaFXUtil.openModal<MainErosController>(TITLE, LAYOUT)
|
||||||
mainErosController.stage.show()
|
mainErosController.stage.show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -35,4 +35,6 @@ abstract class JavaFXController : Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun init() {}
|
open fun init() {}
|
||||||
|
|
||||||
|
open fun postInit() {}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,4 @@ import javafx.stage.Stage
|
|||||||
|
|
||||||
abstract class JavaFXWindowController : JavaFXController() {
|
abstract class JavaFXWindowController : JavaFXController() {
|
||||||
lateinit var stage: Stage
|
lateinit var stage: Stage
|
||||||
|
|
||||||
|
|
||||||
open fun postInit() {}
|
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,7 @@ class ErosCrashReport : JavaFXWindowController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private var alreadyCrashed = false
|
||||||
private val CRASH_REPORT_COMMENTS = listOf(
|
private val CRASH_REPORT_COMMENTS = listOf(
|
||||||
"Let's blame Bixilon for this",
|
"Let's blame Bixilon for this",
|
||||||
"But it worked once",
|
"But it worked once",
|
||||||
@ -111,22 +112,10 @@ class ErosCrashReport : JavaFXWindowController() {
|
|||||||
* Special: Does not use any general functions/translations/..., because when a crash happens, you can't rely on anything.
|
* Special: Does not use any general functions/translations/..., because when a crash happens, you can't rely on anything.
|
||||||
*/
|
*/
|
||||||
fun Throwable?.crash() {
|
fun Throwable?.crash() {
|
||||||
if (RunConfiguration.DISABLE_EROS) {
|
if (alreadyCrashed) {
|
||||||
ShutdownManager.shutdown(this?.message, ShutdownReasons.CRITICAL_EXCEPTION)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
alreadyCrashed = true
|
||||||
if (!JavaFXInitializer.initializing && !JavaFXInitializer.initialized) {
|
|
||||||
try {
|
|
||||||
JavaFXInitializer.start()
|
|
||||||
} catch (exception: Throwable) {
|
|
||||||
Log.log(LogMessageType.JAVAFX, LogLevels.WARN) { "Can not show crash report screen!" }
|
|
||||||
exception.printStackTrace()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JavaFXInitializer.await()
|
|
||||||
|
|
||||||
// Kill some stuff
|
// Kill some stuff
|
||||||
tryCatch(executor = { DefaultThreadPool.shutdownNow() })
|
tryCatch(executor = { DefaultThreadPool.shutdownNow() })
|
||||||
@ -149,6 +138,23 @@ class ErosCrashReport : JavaFXWindowController() {
|
|||||||
crashReportPath = null
|
crashReportPath = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RunConfiguration.DISABLE_EROS) {
|
||||||
|
ShutdownManager.shutdown(this?.message, ShutdownReasons.CRITICAL_EXCEPTION)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!JavaFXInitializer.initializing && !JavaFXInitializer.initialized) {
|
||||||
|
try {
|
||||||
|
JavaFXInitializer.start()
|
||||||
|
} catch (exception: Throwable) {
|
||||||
|
Log.log(LogMessageType.JAVAFX, LogLevels.WARN) { "Can not show crash report screen!" }
|
||||||
|
exception.printStackTrace()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JavaFXInitializer.await()
|
||||||
|
|
||||||
Platform.runLater {
|
Platform.runLater {
|
||||||
val fxmlLoader = FXMLLoader(ErosCrashReport::class.java.getResource("/assets/minosoft/eros/crash/crash_screen.fxml"))
|
val fxmlLoader = FXMLLoader(ErosCrashReport::class.java.getResource("/assets/minosoft/eros/crash/crash_screen.fxml"))
|
||||||
val parent = fxmlLoader.load<Parent>()
|
val parent = fxmlLoader.load<Parent>()
|
||||||
@ -175,15 +181,16 @@ class ErosCrashReport : JavaFXWindowController() {
|
|||||||
// ${CRASH_REPORT_COMMENTS.random()}
|
// ${CRASH_REPORT_COMMENTS.random()}
|
||||||
|
|
||||||
Time: ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis())} (${System.currentTimeMillis() / 1000L})
|
Time: ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis())} (${System.currentTimeMillis() / 1000L})
|
||||||
|
Crash thread: ${Thread.currentThread().name}
|
||||||
|
|
||||||
${exception?.toStackTrace() ?: ""}
|
${exception?.toStackTrace() ?: ""}
|
||||||
|
|
||||||
-- Runtime Details --
|
-- Runtime Details --
|
||||||
Start arguments: ${CommandLineArguments.ARGUMENTS}
|
Start arguments: ${CommandLineArguments.ARGUMENTS}
|
||||||
JVM Flags: ${ManagementFactory.getRuntimeMXBean().inputArguments}
|
JVM flags: ${ManagementFactory.getRuntimeMXBean().inputArguments}
|
||||||
Home directory: ${RunConfiguration.HOME_DIRECTORY}
|
Home directory: ${RunConfiguration.HOME_DIRECTORY}
|
||||||
Disable Eros: ${RunConfiguration.DISABLE_EROS}
|
Disable Eros: ${RunConfiguration.DISABLE_EROS}
|
||||||
Disable Rendering: ${RunConfiguration.DISABLE_RENDERING}
|
Disable rendering: ${RunConfiguration.DISABLE_RENDERING}
|
||||||
|
|
||||||
-- System Details --
|
-- System Details --
|
||||||
Operating system: ${SystemInformation.OS_TEXT}
|
Operating system: ${SystemInformation.OS_TEXT}
|
||||||
|
@ -13,11 +13,15 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.gui.eros.main
|
package de.bixilon.minosoft.gui.eros.main
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.ShutdownReasons
|
import de.bixilon.minosoft.ShutdownReasons
|
||||||
import de.bixilon.minosoft.config.StaticConfiguration
|
import de.bixilon.minosoft.config.StaticConfiguration
|
||||||
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController
|
import de.bixilon.minosoft.gui.eros.controller.JavaFXWindowController
|
||||||
import de.bixilon.minosoft.gui.eros.main.play.PlayMainController
|
import de.bixilon.minosoft.gui.eros.main.play.PlayMainController
|
||||||
|
import de.bixilon.minosoft.gui.eros.modding.invoker.JavaFXEventInvoker
|
||||||
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
|
import de.bixilon.minosoft.gui.eros.util.JavaFXUtil
|
||||||
|
import de.bixilon.minosoft.modding.event.events.account.AccountSelectEvent
|
||||||
import de.bixilon.minosoft.util.GitInfo
|
import de.bixilon.minosoft.util.GitInfo
|
||||||
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
import de.bixilon.minosoft.util.KUtil.decide
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
@ -34,13 +38,11 @@ import org.kordamp.ikonli.javafx.FontIcon
|
|||||||
class MainErosController : JavaFXWindowController() {
|
class MainErosController : JavaFXWindowController() {
|
||||||
@FXML
|
@FXML
|
||||||
private lateinit var logoFX: ImageView
|
private lateinit var logoFX: ImageView
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private lateinit var versionTextFX: Text
|
private lateinit var versionTextFX: Text
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private lateinit var playIconFX: FontIcon
|
private lateinit var playIconFX: FontIcon
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
private lateinit var settingsIconFX: FontIcon
|
private lateinit var settingsIconFX: FontIcon
|
||||||
|
|
||||||
@ -56,6 +58,12 @@ class MainErosController : JavaFXWindowController() {
|
|||||||
@FXML
|
@FXML
|
||||||
private lateinit var contentFX: Pane
|
private lateinit var contentFX: Pane
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private lateinit var accountImageFX: ImageView
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private lateinit var accountNameFX: Text
|
||||||
|
|
||||||
|
|
||||||
private lateinit var icons: List<FontIcon>
|
private lateinit var icons: List<FontIcon>
|
||||||
|
|
||||||
@ -84,6 +92,12 @@ class MainErosController : JavaFXWindowController() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentFX.children.setAll(JavaFXUtil.loadEmbeddedController<PlayMainController>("minosoft:eros/main/play/play.fxml".asResourceLocation()).root)
|
contentFX.children.setAll(JavaFXUtil.loadEmbeddedController<PlayMainController>("minosoft:eros/main/play/play.fxml".asResourceLocation()).root)
|
||||||
|
|
||||||
|
|
||||||
|
Minosoft.GLOBAL_EVENT_MASTER.registerEvent(JavaFXEventInvoker.of<AccountSelectEvent> {
|
||||||
|
accountImageFX.image = JavaFXUtil.MINOSOFT_LOGO // ToDo
|
||||||
|
accountNameFX.text = it.account?.username
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun postInit() {
|
override fun postInit() {
|
||||||
@ -91,4 +105,16 @@ class MainErosController : JavaFXWindowController() {
|
|||||||
ShutdownManager.shutdown(reason = ShutdownReasons.REQUESTED_BY_USER)
|
ShutdownManager.shutdown(reason = ShutdownReasons.REQUESTED_BY_USER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun requestAccountSelect() {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyAccount(account: Account? = Minosoft.config.config.account.selected, onSuccess: (Account) -> Unit) {
|
||||||
|
if (account == null) {
|
||||||
|
requestAccountSelect()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,19 @@ package de.bixilon.minosoft.gui.eros.main.play.server
|
|||||||
import de.bixilon.minosoft.Minosoft
|
import de.bixilon.minosoft.Minosoft
|
||||||
import de.bixilon.minosoft.config.server.Server
|
import de.bixilon.minosoft.config.server.Server
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.data.registries.versions.Versions
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
|
import de.bixilon.minosoft.gui.eros.Eros
|
||||||
import de.bixilon.minosoft.gui.eros.controller.EmbeddedJavaFXController
|
import de.bixilon.minosoft.gui.eros.controller.EmbeddedJavaFXController
|
||||||
import de.bixilon.minosoft.gui.eros.main.play.server.card.ServerCard
|
import de.bixilon.minosoft.gui.eros.main.play.server.card.ServerCard
|
||||||
import de.bixilon.minosoft.gui.eros.main.play.server.card.ServerCardController
|
import de.bixilon.minosoft.gui.eros.main.play.server.card.ServerCardController
|
||||||
import de.bixilon.minosoft.gui.eros.modding.invoker.JavaFXEventInvoker
|
import de.bixilon.minosoft.gui.eros.modding.invoker.JavaFXEventInvoker
|
||||||
import de.bixilon.minosoft.modding.event.events.status.StatusConnectionUpdateEvent
|
import de.bixilon.minosoft.modding.event.events.status.StatusConnectionUpdateEvent
|
||||||
|
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
|
||||||
|
import de.bixilon.minosoft.util.DNSUtil
|
||||||
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
|
import de.bixilon.minosoft.util.KUtil.decide
|
||||||
|
import de.bixilon.minosoft.util.task.pool.DefaultThreadPool
|
||||||
import javafx.fxml.FXML
|
import javafx.fxml.FXML
|
||||||
import javafx.geometry.HPos
|
import javafx.geometry.HPos
|
||||||
import javafx.geometry.Insets
|
import javafx.geometry.Insets
|
||||||
@ -63,13 +69,20 @@ class ServerListController : EmbeddedJavaFXController<Pane>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun postInit() {
|
||||||
|
root.setOnKeyPressed { serverListViewFX.selectionModel.select(null) } // ToDo: Only on escape; not working
|
||||||
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
|
val selected = serverListViewFX.selectionModel.selectedItem
|
||||||
serverListViewFX.items.clear()
|
serverListViewFX.items.clear()
|
||||||
|
|
||||||
for (server in Minosoft.config.config.server.entries.values) {
|
for (server in Minosoft.config.config.server.entries.values) {
|
||||||
updateServer(server)
|
updateServer(server)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverListViewFX.selectionModel.select(serverListViewFX.items.contains(selected).decide(selected, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateServer(server: Server) {
|
private fun updateServer(server: Server) {
|
||||||
@ -121,8 +134,10 @@ class ServerListController : EmbeddedJavaFXController<Pane>() {
|
|||||||
var row = 0
|
var row = 0
|
||||||
|
|
||||||
for ((key, property) in SERVER_INFO_PROPERTIES) {
|
for ((key, property) in SERVER_INFO_PROPERTIES) {
|
||||||
|
val propertyValue = property(serverCard.server) ?: continue
|
||||||
|
|
||||||
it.add(Minosoft.LANGUAGE_MANAGER.translate(key).textFlow, 0, row)
|
it.add(Minosoft.LANGUAGE_MANAGER.translate(key).textFlow, 0, row)
|
||||||
it.add(ChatComponent.of(property(serverCard.server)).textFlow, 1, row++)
|
it.add(ChatComponent.of(propertyValue).textFlow, 1, row++)
|
||||||
}
|
}
|
||||||
|
|
||||||
it.columnConstraints += ColumnConstraints(10.0, 100.0, 150.0)
|
it.columnConstraints += ColumnConstraints(10.0, 100.0, 150.0)
|
||||||
@ -138,7 +153,14 @@ class ServerListController : EmbeddedJavaFXController<Pane>() {
|
|||||||
|
|
||||||
it.add(Button("Delete"), 1, 0)
|
it.add(Button("Delete"), 1, 0)
|
||||||
it.add(Button("Edit"), 2, 0)
|
it.add(Button("Edit"), 2, 0)
|
||||||
it.add(Button("Connect"), 3, 0)
|
it.add(Button("Connect").apply {
|
||||||
|
setOnAction {
|
||||||
|
Eros.mainErosController.verifyAccount { account ->
|
||||||
|
val connection = PlayConnection(serverCard.server.ping?.realAddress ?: DNSUtil.getServerAddress(serverCard.server.address), account, Versions.getVersionById(serverCard.server.forcedVersion!!)) // ToDo: Get ping version
|
||||||
|
DefaultThreadPool += { connection.connect() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 3, 0)
|
||||||
|
|
||||||
|
|
||||||
it.hgap = 5.0
|
it.hgap = 5.0
|
||||||
@ -153,9 +175,10 @@ class ServerListController : EmbeddedJavaFXController<Pane>() {
|
|||||||
|
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val SERVER_INFO_PROPERTIES: Map<ResourceLocation, (server: Server) -> Any> = mapOf(
|
private val SERVER_INFO_PROPERTIES: Map<ResourceLocation, (server: Server) -> Any?> = mapOf(
|
||||||
"minosoft:server_name".asResourceLocation() to { it.name },
|
"minosoft:server.info.server_name".asResourceLocation() to { it.name },
|
||||||
"minosoft:server_address".asResourceLocation() to { it.address },
|
"minosoft:server.info.server_address".asResourceLocation() to { it.address },
|
||||||
|
"minosoft:server.info.forced_version".asResourceLocation() to { it.forcedVersion?.let { version -> Versions.getVersionById(version)!! } },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import de.bixilon.minosoft.modding.event.invoker.EventInstantFireable
|
|||||||
import de.bixilon.minosoft.modding.event.invoker.EventInvoker
|
import de.bixilon.minosoft.modding.event.invoker.EventInvoker
|
||||||
import de.bixilon.minosoft.modding.loading.Priorities
|
import de.bixilon.minosoft.modding.loading.Priorities
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basically a CallbackEventInvoker, bt the callback runs on the java fx ui thread
|
* Basically a CallbackEventInvoker, bt the callback runs on the java fx ui thread
|
||||||
@ -26,6 +27,7 @@ import javafx.application.Platform
|
|||||||
class JavaFXEventInvoker<E : Event> private constructor(
|
class JavaFXEventInvoker<E : Event> private constructor(
|
||||||
ignoreCancelled: Boolean,
|
ignoreCancelled: Boolean,
|
||||||
private val callback: (E) -> Unit,
|
private val callback: (E) -> Unit,
|
||||||
|
override val kEventType: KClass<out Event>,
|
||||||
override val eventType: Class<out Event>,
|
override val eventType: Class<out Event>,
|
||||||
override val instantFire: Boolean,
|
override val instantFire: Boolean,
|
||||||
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable {
|
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable {
|
||||||
@ -46,6 +48,7 @@ class JavaFXEventInvoker<E : Event> private constructor(
|
|||||||
return JavaFXEventInvoker(
|
return JavaFXEventInvoker(
|
||||||
ignoreCancelled = ignoreCancelled,
|
ignoreCancelled = ignoreCancelled,
|
||||||
callback = callback,
|
callback = callback,
|
||||||
|
kEventType = E::class,
|
||||||
eventType = E::class.java,
|
eventType = E::class.java,
|
||||||
instantFire = instantFire,
|
instantFire = instantFire,
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
package de.bixilon.minosoft.gui.eros.util
|
package de.bixilon.minosoft.gui.eros.util
|
||||||
|
|
||||||
import de.bixilon.minosoft.Minosoft
|
import de.bixilon.minosoft.Minosoft
|
||||||
|
import de.bixilon.minosoft.gui.eros.crash.ErosCrashReport.Companion.crash
|
||||||
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
import de.bixilon.minosoft.util.CountUpAndDownLatch
|
||||||
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
import de.bixilon.minosoft.util.logging.Log
|
import de.bixilon.minosoft.util.logging.Log
|
||||||
@ -49,6 +50,7 @@ class JavaFXInitializer internal constructor() : Application() {
|
|||||||
@Synchronized
|
@Synchronized
|
||||||
fun start() {
|
fun start() {
|
||||||
check(LATCH.count == 2) { "Already initialized!" }
|
check(LATCH.count == 2) { "Already initialized!" }
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler { _, exception -> exception.crash() }
|
||||||
|
|
||||||
Log.log(LogMessageType.JAVAFX, LogLevels.VERBOSE) { "Initializing JavaFX Toolkit..." }
|
Log.log(LogMessageType.JAVAFX, LogLevels.VERBOSE) { "Initializing JavaFX Toolkit..." }
|
||||||
Thread({ Application.launch(JavaFXInitializer::class.java) }, "JavaFX Toolkit Initializing Thread").start()
|
Thread({ Application.launch(JavaFXInitializer::class.java) }, "JavaFX Toolkit Initializing Thread").start()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Minosoft
|
* Minosoft
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
*
|
*
|
||||||
* 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 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.
|
||||||
*
|
*
|
||||||
@ -11,14 +11,11 @@
|
|||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.bixilon.minosoft.util.mojang.api.exceptions;
|
package de.bixilon.minosoft.modding.event
|
||||||
|
|
||||||
public class MojangJoinServerErrorException extends Exception {
|
import de.bixilon.minosoft.modding.event.events.Event
|
||||||
|
|
||||||
public MojangJoinServerErrorException(String message) {
|
interface EventInstantFire<T : Event> {
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MojangJoinServerErrorException() {
|
fun fire(): T
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
package de.bixilon.minosoft.modding.event.events.account
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.Minosoft
|
||||||
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
|
import de.bixilon.minosoft.modding.event.EventInstantFire
|
||||||
|
import de.bixilon.minosoft.modding.event.events.Event
|
||||||
|
|
||||||
|
class AccountSelectEvent(
|
||||||
|
val previous: Account?,
|
||||||
|
val account: Account?,
|
||||||
|
) : Event() {
|
||||||
|
|
||||||
|
companion object : EventInstantFire<AccountSelectEvent> {
|
||||||
|
|
||||||
|
override fun fire(): AccountSelectEvent {
|
||||||
|
return AccountSelectEvent(null, Minosoft.config.config.account.selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,10 +15,12 @@ package de.bixilon.minosoft.modding.event.invoker
|
|||||||
import de.bixilon.minosoft.modding.event.events.CancelableEvent
|
import de.bixilon.minosoft.modding.event.events.CancelableEvent
|
||||||
import de.bixilon.minosoft.modding.event.events.Event
|
import de.bixilon.minosoft.modding.event.events.Event
|
||||||
import de.bixilon.minosoft.modding.loading.Priorities
|
import de.bixilon.minosoft.modding.loading.Priorities
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class CallbackEventInvoker<E : Event> private constructor(
|
class CallbackEventInvoker<E : Event> private constructor(
|
||||||
ignoreCancelled: Boolean,
|
ignoreCancelled: Boolean,
|
||||||
private val callback: (E) -> Unit,
|
private val callback: (E) -> Unit,
|
||||||
|
override val kEventType: KClass<out Event>,
|
||||||
override val eventType: Class<out Event>,
|
override val eventType: Class<out Event>,
|
||||||
override val instantFire: Boolean,
|
override val instantFire: Boolean,
|
||||||
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable {
|
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable {
|
||||||
@ -37,6 +39,7 @@ class CallbackEventInvoker<E : Event> private constructor(
|
|||||||
return CallbackEventInvoker(
|
return CallbackEventInvoker(
|
||||||
ignoreCancelled = ignoreCancelled,
|
ignoreCancelled = ignoreCancelled,
|
||||||
callback = callback,
|
callback = callback,
|
||||||
|
kEventType = E::class,
|
||||||
eventType = E::class.java,
|
eventType = E::class.java,
|
||||||
instantFire = instantFire,
|
instantFire = instantFire,
|
||||||
)
|
)
|
||||||
|
@ -15,13 +15,15 @@ package de.bixilon.minosoft.modding.event.invoker
|
|||||||
import de.bixilon.minosoft.modding.event.EventListener
|
import de.bixilon.minosoft.modding.event.EventListener
|
||||||
import de.bixilon.minosoft.modding.event.events.Event
|
import de.bixilon.minosoft.modding.event.events.Event
|
||||||
import de.bixilon.minosoft.modding.loading.Priorities
|
import de.bixilon.minosoft.modding.loading.Priorities
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
abstract class EventInvoker(
|
abstract class EventInvoker(
|
||||||
val isIgnoreCancelled: Boolean,
|
val isIgnoreCancelled: Boolean,
|
||||||
val priority: Priorities,
|
val priority: Priorities,
|
||||||
protected val listener: EventListener?,
|
protected val listener: EventListener?,
|
||||||
) {
|
) {
|
||||||
abstract val eventType: Class<out Event?>
|
abstract val kEventType: KClass<out Event>?
|
||||||
|
abstract val eventType: Class<out Event>
|
||||||
|
|
||||||
abstract operator fun invoke(event: Event)
|
abstract operator fun invoke(event: Event)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import de.bixilon.minosoft.modding.event.events.Event
|
|||||||
import de.bixilon.minosoft.modding.event.events.annotations.EventHandler
|
import de.bixilon.minosoft.modding.event.events.annotations.EventHandler
|
||||||
import de.bixilon.minosoft.modding.loading.Priorities
|
import de.bixilon.minosoft.modding.loading.Priorities
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class EventInvokerMethod(
|
class EventInvokerMethod(
|
||||||
ignoreCancelled: Boolean,
|
ignoreCancelled: Boolean,
|
||||||
@ -25,6 +26,7 @@ class EventInvokerMethod(
|
|||||||
listener: EventListener,
|
listener: EventListener,
|
||||||
val method: Method,
|
val method: Method,
|
||||||
) : EventInvoker(ignoreCancelled, priority, listener) {
|
) : EventInvoker(ignoreCancelled, priority, listener) {
|
||||||
|
override val kEventType: KClass<out Event>? = null
|
||||||
override val eventType: Class<out Event> = method.parameters[0].type as Class<out Event>
|
override val eventType: Class<out Event> = method.parameters[0].type as Class<out Event>
|
||||||
|
|
||||||
constructor(annotation: EventHandler, listener: EventListener, method: Method) : this(annotation.ignoreCancelled, annotation.priority, listener, method)
|
constructor(annotation: EventHandler, listener: EventListener, method: Method) : this(annotation.ignoreCancelled, annotation.priority, listener, method)
|
||||||
|
@ -13,12 +13,15 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.modding.event.master
|
package de.bixilon.minosoft.modding.event.master
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.modding.event.EventInstantFire
|
||||||
import de.bixilon.minosoft.modding.event.events.CancelableEvent
|
import de.bixilon.minosoft.modding.event.events.CancelableEvent
|
||||||
import de.bixilon.minosoft.modding.event.events.Event
|
import de.bixilon.minosoft.modding.event.events.Event
|
||||||
|
import de.bixilon.minosoft.modding.event.invoker.EventInstantFireable
|
||||||
import de.bixilon.minosoft.modding.event.invoker.EventInvoker
|
import de.bixilon.minosoft.modding.event.invoker.EventInvoker
|
||||||
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
|
import de.bixilon.minosoft.util.KUtil.synchronizedSetOf
|
||||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedList
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedList
|
||||||
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
|
import de.bixilon.minosoft.util.KUtil.toSynchronizedSet
|
||||||
|
import kotlin.reflect.full.companionObjectInstance
|
||||||
|
|
||||||
open class EventMaster(vararg parents: AbstractEventMaster) : AbstractEventMaster {
|
open class EventMaster(vararg parents: AbstractEventMaster) : AbstractEventMaster {
|
||||||
val parents: MutableSet<AbstractEventMaster> = synchronizedSetOf(*parents)
|
val parents: MutableSet<AbstractEventMaster> = synchronizedSetOf(*parents)
|
||||||
@ -62,10 +65,20 @@ open class EventMaster(vararg parents: AbstractEventMaster) : AbstractEventMaste
|
|||||||
|
|
||||||
override fun registerEvent(invoker: EventInvoker) {
|
override fun registerEvent(invoker: EventInvoker) {
|
||||||
eventInvokers += invoker
|
eventInvokers += invoker
|
||||||
|
|
||||||
|
if (invoker is EventInstantFireable && invoker.instantFire) {
|
||||||
|
val companion = invoker.kEventType?.companionObjectInstance ?: return
|
||||||
|
|
||||||
|
if (companion is EventInstantFire<*>) {
|
||||||
|
invoker.invoke(companion.fire())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun registerEvents(vararg invoker: EventInvoker) {
|
override fun registerEvents(vararg invokers: EventInvoker) {
|
||||||
eventInvokers += invoker
|
for (invoker in invokers) {
|
||||||
|
registerEvent(invoker)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(): Iterator<EventInvoker> {
|
override fun iterator(): Iterator<EventInvoker> {
|
||||||
|
@ -175,7 +175,7 @@ class PlayConnection(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun connect(latch: CountUpAndDownLatch) {
|
fun connect(latch: CountUpAndDownLatch = CountUpAndDownLatch(1)) {
|
||||||
// Log.log(LogMessageType.OTHER, LogLevels.VERBOSE){TranslatableComponents.HELLO_WORLD(Minosoft.LANGUAGE_MANAGER, "Moritz", 17)}
|
// Log.log(LogMessageType.OTHER, LogLevels.VERBOSE){TranslatableComponents.HELLO_WORLD(Minosoft.LANGUAGE_MANAGER, "Moritz", 17)}
|
||||||
try {
|
try {
|
||||||
fireEvent(RegistriesLoadEvent(this, registries, RegistriesLoadEvent.States.PRE))
|
fireEvent(RegistriesLoadEvent(this, registries, RegistriesLoadEvent.States.PRE))
|
||||||
|
@ -64,8 +64,8 @@ class StatusConnection(
|
|||||||
field = value
|
field = value
|
||||||
value?.let {
|
value?.let {
|
||||||
fireEvent(StatusConnectionErrorEvent(this, EventInitiators.UNKNOWN, it))
|
fireEvent(StatusConnectionErrorEvent(this, EventInitiators.UNKNOWN, it))
|
||||||
|
pingStatus = StatusConnectionStatuses.ERROR
|
||||||
}
|
}
|
||||||
pingStatus = StatusConnectionStatuses.ERROR
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class LoginKickS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() {
|
|||||||
|
|
||||||
override fun handle(connection: PlayConnection) {
|
override fun handle(connection: PlayConnection) {
|
||||||
connection.fireEvent(LoginKickEvent(connection, this))
|
connection.fireEvent(LoginKickEvent(connection, this))
|
||||||
Log.log(LogMessageType.NETWORK_STATUS, level = LogLevels.WARN) { "Kicked from: $reason" }
|
Log.log(LogMessageType.NETWORK_STATUS, level = LogLevels.WARN) { "Kicked from ${connection.address}: $reason" }
|
||||||
connection.disconnect()
|
connection.disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ open class InByteBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun readJson(): Map<String, Any> {
|
fun readJson(): Map<String, Any> {
|
||||||
return JSONSerializer.MAP_ADAPTER.fromJson(readString())!!
|
return JSONSerializer.MUTABLE_MAP_ADAPTER.fromJson(readString())!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun readJsonArray(length: Int = readVarInt()): Array<Map<String, Any>> {
|
fun readJsonArray(length: Int = readVarInt()): Array<Map<String, Any>> {
|
||||||
|
@ -72,10 +72,6 @@ public final class ProtocolDefinition {
|
|||||||
public static final String MOJANG_URL_PACKAGES = "https://launchermeta.mojang.com/v1/packages/%s/%s";
|
public static final String MOJANG_URL_PACKAGES = "https://launchermeta.mojang.com/v1/packages/%s/%s";
|
||||||
public static final String MOJANG_LAUNCHER_URL_PACKAGES = "https://launcher.mojang.com/v1/objects/%s/%s";
|
public static final String MOJANG_LAUNCHER_URL_PACKAGES = "https://launcher.mojang.com/v1/objects/%s/%s";
|
||||||
|
|
||||||
public static final String MOJANG_URL_BLOCKED_SERVERS = "https://sessionserver.mojang.com/blockedservers";
|
|
||||||
public static final String MOJANG_URL_LOGIN = "https://authserver.mojang.com/authenticate";
|
|
||||||
public static final String MOJANG_URL_JOIN = "https://sessionserver.mojang.com/session/minecraft/join";
|
|
||||||
public static final String MOJANG_URL_REFRESH = "https://authserver.mojang.com/refresh";
|
|
||||||
|
|
||||||
public static final String MICROSOFT_ACCOUNT_APPLICATION_ID = "00000000402b5328"; // ToDo: Should we use our own application id?
|
public static final String MICROSOFT_ACCOUNT_APPLICATION_ID = "00000000402b5328"; // ToDo: Should we use our own application id?
|
||||||
// public static final String MICROSOFT_ACCOUNT_APPLICATION_ID = "fe6f0fbf-3038-486a-9c84-6a28b71e0455";
|
// public static final String MICROSOFT_ACCOUNT_APPLICATION_ID = "fe6f0fbf-3038-486a-9c84-6a28b71e0455";
|
||||||
|
@ -24,6 +24,7 @@ import java.net.http.HttpRequest;
|
|||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public final class HTTP {
|
public final class HTTP {
|
||||||
|
|
||||||
public static HttpResponse<String> postJson(String url, String json, HashMap<String, String> headers) throws IOException, InterruptedException {
|
public static HttpResponse<String> postJson(String url, String json, HashMap<String, String> headers) throws IOException, InterruptedException {
|
||||||
|
@ -17,6 +17,7 @@ import com.squareup.moshi.JsonAdapter
|
|||||||
import com.squareup.moshi.JsonWriter
|
import com.squareup.moshi.JsonWriter
|
||||||
import de.bixilon.minosoft.data.entities.entities.Entity
|
import de.bixilon.minosoft.data.entities.entities.Entity
|
||||||
import de.bixilon.minosoft.data.registries.ResourceLocation
|
import de.bixilon.minosoft.data.registries.ResourceLocation
|
||||||
|
import de.bixilon.minosoft.data.registries.ResourceLocationAble
|
||||||
import de.bixilon.minosoft.data.text.ChatColors
|
import de.bixilon.minosoft.data.text.ChatColors
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
import de.bixilon.minosoft.data.text.TextComponent
|
import de.bixilon.minosoft.data.text.TextComponent
|
||||||
@ -169,6 +170,22 @@ object KUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> Boolean.decide(`true`: T, `false`: () -> T): T {
|
||||||
|
return if (this) {
|
||||||
|
`true`
|
||||||
|
} else {
|
||||||
|
`false`()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Boolean.decide(`true`: () -> T, `false`: T): T {
|
||||||
|
return if (this) {
|
||||||
|
`true`()
|
||||||
|
} else {
|
||||||
|
`false`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun String.asUUID(): UUID {
|
fun String.asUUID(): UUID {
|
||||||
return Util.getUUIDFromString(this)
|
return Util.getUUIDFromString(this)
|
||||||
}
|
}
|
||||||
@ -325,4 +342,19 @@ object KUtil {
|
|||||||
|
|
||||||
val Class<*>.realName: String
|
val Class<*>.realName: String
|
||||||
get() = this.name.removePrefix(this.packageName).removePrefix(".")
|
get() = this.name.removePrefix(this.packageName).removePrefix(".")
|
||||||
|
|
||||||
|
fun UUID.trim(): String {
|
||||||
|
return this.toString().replace("-", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <T : ResourceLocationAble> List<T>.asResourceLocationMap(): Map<ResourceLocation, T> {
|
||||||
|
val ret: MutableMap<ResourceLocation, T> = mutableMapOf()
|
||||||
|
|
||||||
|
for (value in this) {
|
||||||
|
ret[value.resourceLocation] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.toMap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
62
src/main/java/de/bixilon/minosoft/util/http/HTTP2.kt
Normal file
62
src/main/java/de/bixilon/minosoft/util/http/HTTP2.kt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.util.http
|
||||||
|
|
||||||
|
import de.bixilon.minosoft.util.KUtil.extend
|
||||||
|
import de.bixilon.minosoft.util.json.JSONSerializer
|
||||||
|
import java.net.URI
|
||||||
|
import java.net.http.HttpClient
|
||||||
|
import java.net.http.HttpRequest
|
||||||
|
import java.net.http.HttpResponse
|
||||||
|
|
||||||
|
object HTTP2 {
|
||||||
|
|
||||||
|
|
||||||
|
fun Map<String, Any>.headers(): Array<String> {
|
||||||
|
val headers: MutableList<String> = mutableListOf()
|
||||||
|
|
||||||
|
for ((key, value) in this) {
|
||||||
|
headers += key
|
||||||
|
headers += value.toString()
|
||||||
|
}
|
||||||
|
return headers.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <Payload, Response> post(url: String, data: Payload, bodyPublisher: (Payload) -> String, bodyBuilder: (String) -> Response, headers: Map<String, Any> = mapOf()): HTTPResponse<Response> {
|
||||||
|
val client = HttpClient.newHttpClient()
|
||||||
|
val request = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create(url))
|
||||||
|
.POST(HttpRequest.BodyPublishers.ofString(bodyPublisher(data)))
|
||||||
|
.headers(*headers.headers())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val response = client.send(request, HttpResponse.BodyHandlers.ofString())
|
||||||
|
return HTTPResponse(response.statusCode(), bodyBuilder(response.body()))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun Map<String, Any>.postJson(url: String, headers: Map<String, Any> = mapOf()): HTTPResponse<Map<String, Any>?> {
|
||||||
|
return post(
|
||||||
|
url = url,
|
||||||
|
data = this,
|
||||||
|
bodyPublisher = { JSONSerializer.MAP_ADAPTER.toJson(it) },
|
||||||
|
bodyBuilder = { JSONSerializer.MAP_ADAPTER.fromJson(it) },
|
||||||
|
headers = headers.extend(
|
||||||
|
"Content-Type" to "application/json",
|
||||||
|
"Accept" to "application/json",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
src/main/java/de/bixilon/minosoft/util/http/HTTPResponse.kt
Normal file
19
src/main/java/de/bixilon/minosoft/util/http/HTTPResponse.kt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.util.http
|
||||||
|
|
||||||
|
class HTTPResponse<T>(
|
||||||
|
val statusCode: Int,
|
||||||
|
val body: T,
|
||||||
|
)
|
@ -10,12 +10,9 @@
|
|||||||
*
|
*
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
*/
|
*/
|
||||||
|
package de.bixilon.minosoft.util.http.exceptions
|
||||||
|
|
||||||
package de.bixilon.minosoft.util.mojang.api.exceptions;
|
class AuthenticationException(
|
||||||
|
statusCode: Int,
|
||||||
public class AuthenticationException extends Exception {
|
message: String? = null,
|
||||||
|
) : HTTPException(statusCode, message)
|
||||||
public AuthenticationException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2021 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.util.http.exceptions
|
||||||
|
|
||||||
|
open class HTTPException(
|
||||||
|
val statusCode: Int,
|
||||||
|
message: String? = null,
|
||||||
|
) : Exception(message)
|
@ -14,25 +14,22 @@
|
|||||||
package de.bixilon.minosoft.util.json
|
package de.bixilon.minosoft.util.json
|
||||||
|
|
||||||
import com.squareup.moshi.FromJson
|
import com.squareup.moshi.FromJson
|
||||||
|
import com.squareup.moshi.JsonAdapter
|
||||||
import com.squareup.moshi.ToJson
|
import com.squareup.moshi.ToJson
|
||||||
import de.bixilon.minosoft.data.accounts.Account
|
import de.bixilon.minosoft.data.accounts.Account
|
||||||
import de.bixilon.minosoft.data.accounts.MicrosoftAccount
|
import de.bixilon.minosoft.data.accounts.AccountTypes
|
||||||
import de.bixilon.minosoft.data.accounts.MojangAccount
|
import de.bixilon.minosoft.util.KUtil.asResourceLocation
|
||||||
import de.bixilon.minosoft.data.accounts.OfflineAccount
|
import de.bixilon.minosoft.util.KUtil.unsafeCast
|
||||||
|
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound
|
||||||
|
|
||||||
object AccountSerializer {
|
object AccountSerializer {
|
||||||
@FromJson
|
@FromJson
|
||||||
fun fromJson(json: Map<String, Any>): Account {
|
fun fromJson(json: Map<String, Any>): Account {
|
||||||
return when (json["type"]!!) {
|
return AccountTypes.ACCOUNT_TYPES[json["type"]!!.asResourceLocation()]!!.TYPE.fromJsonValue(json)!!
|
||||||
"mojang" -> MojangAccount.deserialize(json)
|
|
||||||
"offline" -> OfflineAccount.deserialize(json)
|
|
||||||
"microsoft" -> MicrosoftAccount.deserialize(json)
|
|
||||||
else -> throw IllegalArgumentException("Invalid account type: ${json["type"]}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ToJson
|
@ToJson
|
||||||
fun toJson(account: Account): Map<String, Any> {
|
fun toJson(account: Account): Map<String, Any> {
|
||||||
return account.serialize()
|
return AccountTypes.ACCOUNT_TYPES[account.type]!!.TYPE.unsafeCast<JsonAdapter<Account>>().toJsonValue(account).asCompound()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,19 +21,21 @@ import de.bixilon.minosoft.config.config.Config
|
|||||||
import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties
|
import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties
|
||||||
|
|
||||||
object JSONSerializer {
|
object JSONSerializer {
|
||||||
private val MOSHI = Moshi.Builder()
|
val MOSHI = Moshi.Builder()
|
||||||
.add(RGBColorSerializer)
|
.add(RGBColorSerializer)
|
||||||
.add(Vec2Serializer)
|
.add(Vec2Serializer)
|
||||||
.add(AccountSerializer)
|
.add(AccountSerializer)
|
||||||
.add(ChatComponentSerializer)
|
.add(ChatComponentSerializer)
|
||||||
.add(ServerAddressSerializer)
|
.add(ServerAddressSerializer)
|
||||||
.add(ResourceLocationSerializer)
|
.add(ResourceLocationSerializer)
|
||||||
|
.add(UUIDSerializer)
|
||||||
.add(KotlinJsonAdapterFactory())
|
.add(KotlinJsonAdapterFactory())
|
||||||
.build()!!
|
.build()!!
|
||||||
|
|
||||||
val ANY_ADAPTER = MOSHI.adapter(Any::class.java)!!
|
val ANY_ADAPTER = MOSHI.adapter(Any::class.java)!!
|
||||||
val CONFIG_ADAPTER = MOSHI.adapter(Config::class.java)!!
|
val CONFIG_ADAPTER = MOSHI.adapter(Config::class.java)!!
|
||||||
val MAP_ADAPTER: JsonAdapter<MutableMap<String, Any>> = MOSHI.adapter(Types.newParameterizedType(MutableMap::class.java, String::class.java, Any::class.java))
|
val MUTABLE_MAP_ADAPTER: JsonAdapter<MutableMap<String, Any>> = MOSHI.adapter(Types.newParameterizedType(MutableMap::class.java, String::class.java, Any::class.java))
|
||||||
|
val MAP_ADAPTER: JsonAdapter<Map<String, Any>> = MOSHI.adapter(Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java))
|
||||||
|
|
||||||
val IMAGE_PROPERTIES_ADAPTER = MOSHI.adapter(ImageProperties::class.java)!!
|
val IMAGE_PROPERTIES_ADAPTER = MOSHI.adapter(ImageProperties::class.java)!!
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.util.json
|
||||||
|
|
||||||
|
import com.squareup.moshi.*
|
||||||
|
import de.bixilon.minosoft.util.Util
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object UUIDSerializer : JsonAdapter<UUID>() {
|
||||||
|
@FromJson
|
||||||
|
override fun fromJson(jsonReader: JsonReader): UUID? {
|
||||||
|
if (jsonReader.peek() == JsonReader.Token.NULL) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return Util.getUUIDFromString(jsonReader.nextString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToJson
|
||||||
|
override fun toJson(jsonWriter: JsonWriter, uuid: UUID?) {
|
||||||
|
if (uuid == null) {
|
||||||
|
jsonWriter.nullValue()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
jsonWriter.value(uuid.toString())
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,8 @@ enum class LogMessageType(
|
|||||||
VERSION_LOADING(ChatColors.YELLOW),
|
VERSION_LOADING(ChatColors.YELLOW),
|
||||||
ASSETS(ChatColors.BLACK),
|
ASSETS(ChatColors.BLACK),
|
||||||
|
|
||||||
|
AUTHENTICATION(ChatColors.BLACK),
|
||||||
|
|
||||||
NETWORK_RESOLVING(ChatColors.DARK_GREEN),
|
NETWORK_RESOLVING(ChatColors.DARK_GREEN),
|
||||||
NETWORK_STATUS(ChatColors.DARK_GREEN),
|
NETWORK_STATUS(ChatColors.DARK_GREEN),
|
||||||
NETWORK_PACKETS_IN(ChatColors.BLUE, mapOf(
|
NETWORK_PACKETS_IN(ChatColors.BLUE, mapOf(
|
||||||
|
@ -14,8 +14,7 @@
|
|||||||
package de.bixilon.minosoft.util.microsoft
|
package de.bixilon.minosoft.util.microsoft
|
||||||
|
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import de.bixilon.minosoft.data.accounts.Account
|
import de.bixilon.minosoft.data.accounts.types.MicrosoftAccount
|
||||||
import de.bixilon.minosoft.data.accounts.MicrosoftAccount
|
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||||
import de.bixilon.minosoft.terminal.RunConfiguration
|
import de.bixilon.minosoft.terminal.RunConfiguration
|
||||||
import de.bixilon.minosoft.util.HTTP
|
import de.bixilon.minosoft.util.HTTP
|
||||||
@ -38,7 +37,7 @@ object MicrosoftOAuthUtils {
|
|||||||
val xstsToken = getXSTSToken(xboxLiveToken.first)
|
val xstsToken = getXSTSToken(xboxLiveToken.first)
|
||||||
|
|
||||||
val microsoftAccount = getMicrosoftAccount(getMinecraftAccessToken(xboxLiveToken.second, xstsToken))
|
val microsoftAccount = getMicrosoftAccount(getMinecraftAccessToken(xboxLiveToken.second, xstsToken))
|
||||||
Account.addAccount(microsoftAccount)
|
// ToDo: Account.addAccount(microsoftAccount)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.warn("Can not login into microsoft account")
|
Log.warn("Can not login into microsoft account")
|
||||||
exception.printStackTrace()
|
exception.printStackTrace()
|
||||||
@ -162,7 +161,8 @@ object MicrosoftOAuthUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val body = JsonParser.parseString(response.body()).asJsonObject
|
val body = JsonParser.parseString(response.body()).asJsonObject
|
||||||
return MicrosoftAccount(bearerToken, body["id"].asString!!, Util.getUUIDFromString(body["id"].asString!!), body["name"].asString!!)
|
// return MicrosoftAccount(bearerToken, body["id"].asString!!, Util.getUUIDFromString(body["id"].asString!!), body["name"].asString!!)
|
||||||
|
TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* Minosoft
|
|
||||||
* Copyright (C) 2020 Moritz Zwerger
|
|
||||||
*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.bixilon.minosoft.util.mojang.api;
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import de.bixilon.minosoft.Minosoft;
|
|
||||||
import de.bixilon.minosoft.data.accounts.MojangAccount;
|
|
||||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition;
|
|
||||||
import de.bixilon.minosoft.util.HTTP;
|
|
||||||
import de.bixilon.minosoft.util.logging.Log;
|
|
||||||
import de.bixilon.minosoft.util.logging.LogMessageType;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.AuthenticationException;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.MojangJoinServerErrorException;
|
|
||||||
import de.bixilon.minosoft.util.mojang.api.exceptions.NoNetworkConnectionException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.http.HttpResponse;
|
|
||||||
|
|
||||||
public final class MojangAuthentication {
|
|
||||||
|
|
||||||
public static MojangAccount login(String username, String password) throws AuthenticationException, NoNetworkConnectionException {
|
|
||||||
return login(Minosoft.config.getConfig().getAccount().getClientToken(), username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MojangAccount login(String clientToken, String username, String password) throws NoNetworkConnectionException, AuthenticationException {
|
|
||||||
JsonObject agent = new JsonObject();
|
|
||||||
agent.addProperty("name", "Minecraft");
|
|
||||||
agent.addProperty("version", 1);
|
|
||||||
|
|
||||||
JsonObject payload = new JsonObject();
|
|
||||||
payload.add("agent", agent);
|
|
||||||
payload.addProperty("username", username);
|
|
||||||
payload.addProperty("password", password);
|
|
||||||
payload.addProperty("clientToken", clientToken);
|
|
||||||
payload.addProperty("requestUser", true);
|
|
||||||
|
|
||||||
HttpResponse<String> response;
|
|
||||||
try {
|
|
||||||
response = HTTP.postJson(ProtocolDefinition.MOJANG_URL_LOGIN, payload);
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
Log.printException(e, LogMessageType.OTHER);
|
|
||||||
throw new NoNetworkConnectionException(e);
|
|
||||||
}
|
|
||||||
if (response == null) {
|
|
||||||
Log.mojang(String.format("Failed to login with username %s", username));
|
|
||||||
throw new NoNetworkConnectionException("Unknown error, check your Internet connection");
|
|
||||||
}
|
|
||||||
JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
|
|
||||||
if (response.statusCode() != 200) {
|
|
||||||
Log.mojang(String.format("Failed to login with error code %d: %s", response.statusCode(), jsonResponse.get("errorMessage").getAsString()));
|
|
||||||
throw new AuthenticationException(jsonResponse.get("errorMessage").getAsString());
|
|
||||||
}
|
|
||||||
// now it is okay
|
|
||||||
return new MojangAccount(username, jsonResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static void joinServer(MojangAccount account, String serverId) throws NoNetworkConnectionException, MojangJoinServerErrorException {
|
|
||||||
JsonObject payload = new JsonObject();
|
|
||||||
payload.addProperty("accessToken", account.getAccessToken());
|
|
||||||
payload.addProperty("selectedProfile", account.getUUID().toString().replace("-", ""));
|
|
||||||
payload.addProperty("serverId", serverId);
|
|
||||||
|
|
||||||
HttpResponse<String> response;
|
|
||||||
try {
|
|
||||||
response = HTTP.postJson(ProtocolDefinition.MOJANG_URL_JOIN, payload);
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
throw new NoNetworkConnectionException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response == null) {
|
|
||||||
Log.mojang(String.format("Failed to join server: %s", serverId));
|
|
||||||
throw new MojangJoinServerErrorException();
|
|
||||||
}
|
|
||||||
if (response.statusCode() != 204) {
|
|
||||||
JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
|
|
||||||
Log.mojang(String.format("Failed to join server with error code %d: %s", response.statusCode(), jsonResponse.has("errorMessage") ? jsonResponse.get("errorMessage").getAsString() : "null"));
|
|
||||||
throw new MojangJoinServerErrorException(jsonResponse.get("errorMessage").getAsString());
|
|
||||||
}
|
|
||||||
// joined
|
|
||||||
Log.mojang("Joined server successfully");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String refresh(String accessToken) throws NoNetworkConnectionException, AuthenticationException {
|
|
||||||
return refresh(Minosoft.config.getConfig().getAccount().getClientToken(), accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String refresh(String clientToken, String accessToken) throws NoNetworkConnectionException, AuthenticationException {
|
|
||||||
JsonObject payload = new JsonObject();
|
|
||||||
payload.addProperty("accessToken", accessToken);
|
|
||||||
payload.addProperty("clientToken", clientToken);
|
|
||||||
|
|
||||||
HttpResponse<String> response;
|
|
||||||
try {
|
|
||||||
response = HTTP.postJson(ProtocolDefinition.MOJANG_URL_REFRESH, payload);
|
|
||||||
} catch (IOException | InterruptedException e) {
|
|
||||||
Log.mojang(String.format("Could not connect to mojang server: %s", e.getCause().toString()));
|
|
||||||
throw new NoNetworkConnectionException(e);
|
|
||||||
}
|
|
||||||
if (response == null) {
|
|
||||||
Log.mojang("Failed to refresh session");
|
|
||||||
throw new NoNetworkConnectionException();
|
|
||||||
}
|
|
||||||
JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject();
|
|
||||||
if (response.statusCode() != 200) {
|
|
||||||
Log.mojang(String.format("Failed to refresh session with error code %d: %s", response.statusCode(), jsonResponse.get("errorMessage").getAsString()));
|
|
||||||
throw new AuthenticationException(jsonResponse.get("errorMessage").getAsString());
|
|
||||||
}
|
|
||||||
// now it is okay
|
|
||||||
Log.mojang("Refreshed 1 session token");
|
|
||||||
return jsonResponse.get("accessToken").getAsString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,6 +14,11 @@
|
|||||||
package de.bixilon.minosoft.util.nbt.tag
|
package de.bixilon.minosoft.util.nbt.tag
|
||||||
|
|
||||||
object NBTUtil {
|
object NBTUtil {
|
||||||
|
|
||||||
|
fun compound(): MutableMap<String, Any> {
|
||||||
|
return mutableMapOf()
|
||||||
|
}
|
||||||
|
|
||||||
fun MutableMap<String, Any>.getAndRemove(key: String): Any? {
|
fun MutableMap<String, Any>.getAndRemove(key: String): Any? {
|
||||||
val value = this[key]
|
val value = this[key]
|
||||||
this.remove(key)
|
this.remove(key)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.scene.text.Text?>
|
<?import javafx.scene.text.Text?>
|
||||||
<?import org.kordamp.ikonli.javafx.*?>
|
<?import org.kordamp.ikonli.javafx.*?>
|
||||||
<HBox xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" fx:controller="de.bixilon.minosoft.gui.eros.main.MainErosController">
|
<HBox xmlns:fx="http://javafx.com/fxml/1" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/16" fx:controller="de.bixilon.minosoft.gui.eros.main.MainErosController">
|
||||||
<GridPane HBox.hgrow="ALWAYS">
|
<GridPane HBox.hgrow="ALWAYS">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
|
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
|
||||||
@ -77,7 +77,21 @@
|
|||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
</FontIcon>
|
</FontIcon>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
<Text text="Account" GridPane.columnIndex="3"/>
|
<GridPane GridPane.columnIndex="3">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints hgrow="NEVER" minWidth="10.0"/>
|
||||||
|
<ColumnConstraints hgrow="NEVER"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints minHeight="10.0" vgrow="ALWAYS"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<ImageView fx:id="accountImageFX" fitHeight="30.0" fitWidth="30.0" pickOnBounds="true" preserveRatio="true" GridPane.hgrow="ALWAYS" GridPane.vgrow="ALWAYS">
|
||||||
|
<GridPane.margin>
|
||||||
|
<Insets right="5.0"/>
|
||||||
|
</GridPane.margin>
|
||||||
|
</ImageView>
|
||||||
|
<Text fx:id="accountNameFX" text="Account" GridPane.columnIndex="1"/>
|
||||||
|
</GridPane>
|
||||||
<GridPane.margin>
|
<GridPane.margin>
|
||||||
<Insets bottom="3.0" left="5.0" right="5.0" top="3.0"/>
|
<Insets bottom="3.0" left="5.0" right="5.0" top="3.0"/>
|
||||||
</GridPane.margin>
|
</GridPane.margin>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
minosoft:hello.world=§aHi, my name is §e%1$s§a. I am §e%2$s §ayears old and I want to say the following: §cHello world!
|
minosoft:hello.world=§aHi, my name is §e%1$s§a. I am §e%2$s §ayears old and I want to say the following: §cHello world!
|
||||||
minosoft:eros_window_title=Minosoft
|
minosoft:eros_window_title=Minosoft
|
||||||
minosoft:server_name=Server name
|
|
||||||
minosoft:server_address=Server address
|
minosoft:server.info.server_name=Server name
|
||||||
|
minosoft:server.info.server_address=Server address
|
||||||
|
minosoft:server.info.forced_version=Forced version
|
||||||
|
|
||||||
minosoft:status.connection.state.waiting=Waiting...
|
minosoft:status.connection.state.waiting=Waiting...
|
||||||
minosoft:status.connection.state.resolving=Resolving hostname...
|
minosoft:status.connection.state.resolving=Resolving hostname...
|
||||||
|
Loading…
x
Reference in New Issue
Block a user