diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.kt b/src/main/java/de/bixilon/minosoft/Minosoft.kt index eadd00541..319e446e8 100644 --- a/src/main/java/de/bixilon/minosoft/Minosoft.kt +++ b/src/main/java/de/bixilon/minosoft/Minosoft.kt @@ -50,6 +50,8 @@ object Minosoft { val GLOBAL_EVENT_MASTER = GlobalEventMaster() val LANGUAGE_MANAGER = MultiLanguageManager() val START_UP_LATCH = CountUpAndDownLatch(1) + + @Deprecated("Will be singleton interface") lateinit var config: Configuration var initialized: Boolean = false diff --git a/src/main/java/de/bixilon/minosoft/config/Configuration.kt b/src/main/java/de/bixilon/minosoft/config/Configuration.kt index ce8ec4bad..1eee78d63 100644 --- a/src/main/java/de/bixilon/minosoft/config/Configuration.kt +++ b/src/main/java/de/bixilon/minosoft/config/Configuration.kt @@ -34,7 +34,7 @@ class Configuration(private val configName: String = RunConfiguration.CONFIG_FIL init { 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) var wasMigrated = false diff --git a/src/main/java/de/bixilon/minosoft/config/config/account/AccountConfig.kt b/src/main/java/de/bixilon/minosoft/config/config/account/AccountConfig.kt index e43bf3310..c9cb56b4e 100644 --- a/src/main/java/de/bixilon/minosoft/config/config/account/AccountConfig.kt +++ b/src/main/java/de/bixilon/minosoft/config/config/account/AccountConfig.kt @@ -14,12 +14,22 @@ package de.bixilon.minosoft.config.config.account import com.squareup.moshi.Json +import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.accounts.Account +import de.bixilon.minosoft.modding.event.events.account.AccountSelectEvent import java.util.* data class AccountConfig( - var selected: String = "", - @Json(name = "client_token") - var clientToken: String = UUID.randomUUID().toString(), + @Json(name = "selected") var selectedAccountId: String? = null, + @Json(name = "client_token") var clientToken: String = UUID.randomUUID().toString(), val entries: MutableMap = 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 + } +} diff --git a/src/main/java/de/bixilon/minosoft/config/server/Server.kt b/src/main/java/de/bixilon/minosoft/config/server/Server.kt index a3209914d..f089066a2 100644 --- a/src/main/java/de/bixilon/minosoft/config/server/Server.kt +++ b/src/main/java/de/bixilon/minosoft/config/server/Server.kt @@ -25,7 +25,7 @@ data class Server( val id: Int = nextServerId++, // ToDo: Is duplicated in config (first key, then in value) var address: String, 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, var type: ServerTypes = ServerTypes.NORMAL, ) { @@ -56,6 +56,11 @@ data class Server( if (id > nextServerId) { nextServerId = id + 1 } + forcedVersion?.let { + if (it < 0) { + forcedVersion = null + } + } faviconHash?.let { favicon = AssetsUtil.readAsset(it, true) } } diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/Account.java b/src/main/java/de/bixilon/minosoft/data/accounts/Account.java deleted file mode 100644 index 6355c77e7..000000000 --- a/src/main/java/de/bixilon/minosoft/data/accounts/Account.java +++ /dev/null @@ -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 . - * - * 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 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(); - } -} diff --git a/src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/NoNetworkConnectionException.java b/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt similarity index 66% rename from src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/NoNetworkConnectionException.java rename to src/main/java/de/bixilon/minosoft/data/accounts/Account.kt index 0141e0fb6..97f56e3a7 100644 --- a/src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/NoNetworkConnectionException.java +++ b/src/main/java/de/bixilon/minosoft/data/accounts/Account.kt @@ -1,6 +1,6 @@ /* * 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. * @@ -11,19 +11,18 @@ * 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) { - super(cause); - } +abstract class Account( + val username: String, +) { + abstract val id: String + abstract val type: ResourceLocation - public NoNetworkConnectionException(String message) { - super(message); - } + abstract fun join(serverId: String) - public NoNetworkConnectionException() { - - } + abstract fun logout() + abstract fun verify() } diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/AccountType.kt b/src/main/java/de/bixilon/minosoft/data/accounts/AccountType.kt new file mode 100644 index 000000000..4f70db22e --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/accounts/AccountType.kt @@ -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 . + * + * 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) : CompanionResourceLocation { + val TYPE = JSONSerializer.MOSHI.adapter(`class`.java) +} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/AccountTypes.kt b/src/main/java/de/bixilon/minosoft/data/accounts/AccountTypes.kt new file mode 100644 index 000000000..80fb75328 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/accounts/AccountTypes.kt @@ -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 . + * + * 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 = listOf( + MicrosoftAccount, + MojangAccount, + OfflineAccount, + ).asResourceLocationMap() +} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/MicrosoftAccount.java b/src/main/java/de/bixilon/minosoft/data/accounts/MicrosoftAccount.java deleted file mode 100644 index e2a606998..000000000 --- a/src/main/java/de/bixilon/minosoft/data/accounts/MicrosoftAccount.java +++ /dev/null @@ -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 . - * - * 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 serialize() { - Map json = super.serialize(); - json.put("type", "microsoft"); - json.remove("email"); - return json; - } -} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/MojangAccount.java b/src/main/java/de/bixilon/minosoft/data/accounts/MojangAccount.java deleted file mode 100644 index 79f30dea5..000000000 --- a/src/main/java/de/bixilon/minosoft/data/accounts/MojangAccount.java +++ /dev/null @@ -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 . - * - * 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 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 serialize() { - Map 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 - } -} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/OfflineAccount.java b/src/main/java/de/bixilon/minosoft/data/accounts/OfflineAccount.java deleted file mode 100644 index 496fb3d3f..000000000 --- a/src/main/java/de/bixilon/minosoft/data/accounts/OfflineAccount.java +++ /dev/null @@ -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 . - * - * 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 json) { - return new OfflineAccount((String) json.get("username"), Util.getUUIDFromString((String) json.get("uuid"))); - } - - @Override - public Map serialize() { - Map 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(); - } -} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/types/MicrosoftAccount.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/MicrosoftAccount.kt new file mode 100644 index 000000000..11b9985f1 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/MicrosoftAccount.kt @@ -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 . + * + * 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() + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/types/MojangAccount.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/MojangAccount.kt new file mode 100644 index 000000000..31f87c70c --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/MojangAccount.kt @@ -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 . + * + * 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(), + ) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/data/accounts/types/OfflineAccount.kt b/src/main/java/de/bixilon/minosoft/data/accounts/types/OfflineAccount.kt new file mode 100644 index 000000000..de2d98c6a --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/accounts/types/OfflineAccount.kt @@ -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 . + * + * 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() + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/Eros.kt b/src/main/java/de/bixilon/minosoft/gui/eros/Eros.kt index 8bdb4ff1d..d8714a707 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/Eros.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/Eros.kt @@ -25,11 +25,13 @@ object Eros { private val TITLE = "minosoft:eros_window_title".asResourceLocation() private val LAYOUT = "minosoft:eros/main/main.fxml".asResourceLocation() + lateinit var mainErosController: MainErosController + init { Minosoft.GLOBAL_EVENT_MASTER.registerEvent(CallbackEventInvoker.of { Platform.runLater { - val mainErosController = JavaFXUtil.openModal(TITLE, LAYOUT) + mainErosController = JavaFXUtil.openModal(TITLE, LAYOUT) mainErosController.stage.show() } }) diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXController.kt b/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXController.kt index af70e3c89..682979855 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXController.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXController.kt @@ -35,4 +35,6 @@ abstract class JavaFXController : Initializable { } open fun init() {} + + open fun postInit() {} } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXWindowController.kt b/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXWindowController.kt index 5a7709620..659394f09 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXWindowController.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/controller/JavaFXWindowController.kt @@ -17,7 +17,4 @@ import javafx.stage.Stage abstract class JavaFXWindowController : JavaFXController() { lateinit var stage: Stage - - - open fun postInit() {} } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt b/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt index 74bcd65da..0646e712e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/crash/ErosCrashReport.kt @@ -82,6 +82,7 @@ class ErosCrashReport : JavaFXWindowController() { } companion object { + private var alreadyCrashed = false private val CRASH_REPORT_COMMENTS = listOf( "Let's blame Bixilon for this", "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. */ fun Throwable?.crash() { - if (RunConfiguration.DISABLE_EROS) { - ShutdownManager.shutdown(this?.message, ShutdownReasons.CRITICAL_EXCEPTION) + if (alreadyCrashed) { 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() + alreadyCrashed = true // Kill some stuff tryCatch(executor = { DefaultThreadPool.shutdownNow() }) @@ -149,6 +138,23 @@ class ErosCrashReport : JavaFXWindowController() { 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 { val fxmlLoader = FXMLLoader(ErosCrashReport::class.java.getResource("/assets/minosoft/eros/crash/crash_screen.fxml")) val parent = fxmlLoader.load() @@ -175,15 +181,16 @@ class ErosCrashReport : JavaFXWindowController() { // ${CRASH_REPORT_COMMENTS.random()} Time: ${SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis())} (${System.currentTimeMillis() / 1000L}) +Crash thread: ${Thread.currentThread().name} ${exception?.toStackTrace() ?: ""} -- Runtime Details -- Start arguments: ${CommandLineArguments.ARGUMENTS} - JVM Flags: ${ManagementFactory.getRuntimeMXBean().inputArguments} + JVM flags: ${ManagementFactory.getRuntimeMXBean().inputArguments} Home directory: ${RunConfiguration.HOME_DIRECTORY} Disable Eros: ${RunConfiguration.DISABLE_EROS} - Disable Rendering: ${RunConfiguration.DISABLE_RENDERING} + Disable rendering: ${RunConfiguration.DISABLE_RENDERING} -- System Details -- Operating system: ${SystemInformation.OS_TEXT} diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/main/MainErosController.kt b/src/main/java/de/bixilon/minosoft/gui/eros/main/MainErosController.kt index 23a7c8655..086f7432e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/main/MainErosController.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/main/MainErosController.kt @@ -13,11 +13,15 @@ package de.bixilon.minosoft.gui.eros.main +import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.ShutdownReasons 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.main.play.PlayMainController +import de.bixilon.minosoft.gui.eros.modding.invoker.JavaFXEventInvoker 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.KUtil.asResourceLocation import de.bixilon.minosoft.util.KUtil.decide @@ -34,13 +38,11 @@ import org.kordamp.ikonli.javafx.FontIcon class MainErosController : JavaFXWindowController() { @FXML private lateinit var logoFX: ImageView - @FXML private lateinit var versionTextFX: Text @FXML private lateinit var playIconFX: FontIcon - @FXML private lateinit var settingsIconFX: FontIcon @@ -56,6 +58,12 @@ class MainErosController : JavaFXWindowController() { @FXML private lateinit var contentFX: Pane + @FXML + private lateinit var accountImageFX: ImageView + + @FXML + private lateinit var accountNameFX: Text + private lateinit var icons: List @@ -84,6 +92,12 @@ class MainErosController : JavaFXWindowController() { } contentFX.children.setAll(JavaFXUtil.loadEmbeddedController("minosoft:eros/main/play/play.fxml".asResourceLocation()).root) + + + Minosoft.GLOBAL_EVENT_MASTER.registerEvent(JavaFXEventInvoker.of { + accountImageFX.image = JavaFXUtil.MINOSOFT_LOGO // ToDo + accountNameFX.text = it.account?.username + }) } override fun postInit() { @@ -91,4 +105,16 @@ class MainErosController : JavaFXWindowController() { 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") + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt b/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt index 7b8114017..1f0f79347 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/main/play/server/ServerListController.kt @@ -16,13 +16,19 @@ package de.bixilon.minosoft.gui.eros.main.play.server import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.config.server.Server 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.gui.eros.Eros 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.ServerCardController import de.bixilon.minosoft.gui.eros.modding.invoker.JavaFXEventInvoker 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.decide +import de.bixilon.minosoft.util.task.pool.DefaultThreadPool import javafx.fxml.FXML import javafx.geometry.HPos import javafx.geometry.Insets @@ -63,13 +69,20 @@ class ServerListController : EmbeddedJavaFXController() { } } + override fun postInit() { + root.setOnKeyPressed { serverListViewFX.selectionModel.select(null) } // ToDo: Only on escape; not working + } + @FXML fun refresh() { + val selected = serverListViewFX.selectionModel.selectedItem serverListViewFX.items.clear() for (server in Minosoft.config.config.server.entries.values) { updateServer(server) } + + serverListViewFX.selectionModel.select(serverListViewFX.items.contains(selected).decide(selected, null)) } private fun updateServer(server: Server) { @@ -121,8 +134,10 @@ class ServerListController : EmbeddedJavaFXController() { var row = 0 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(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) @@ -138,7 +153,14 @@ class ServerListController : EmbeddedJavaFXController() { it.add(Button("Delete"), 1, 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 @@ -153,9 +175,10 @@ class ServerListController : EmbeddedJavaFXController() { private companion object { - private val SERVER_INFO_PROPERTIES: Map Any> = mapOf( - "minosoft:server_name".asResourceLocation() to { it.name }, - "minosoft:server_address".asResourceLocation() to { it.address }, + private val SERVER_INFO_PROPERTIES: Map Any?> = mapOf( + "minosoft:server.info.server_name".asResourceLocation() to { it.name }, + "minosoft:server.info.server_address".asResourceLocation() to { it.address }, + "minosoft:server.info.forced_version".asResourceLocation() to { it.forcedVersion?.let { version -> Versions.getVersionById(version)!! } }, ) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/modding/invoker/JavaFXEventInvoker.kt b/src/main/java/de/bixilon/minosoft/gui/eros/modding/invoker/JavaFXEventInvoker.kt index 6947a79f9..3c84a7f9a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/modding/invoker/JavaFXEventInvoker.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/modding/invoker/JavaFXEventInvoker.kt @@ -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.loading.Priorities import javafx.application.Platform +import kotlin.reflect.KClass /** * Basically a CallbackEventInvoker, bt the callback runs on the java fx ui thread @@ -26,6 +27,7 @@ import javafx.application.Platform class JavaFXEventInvoker private constructor( ignoreCancelled: Boolean, private val callback: (E) -> Unit, + override val kEventType: KClass, override val eventType: Class, override val instantFire: Boolean, ) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable { @@ -46,6 +48,7 @@ class JavaFXEventInvoker private constructor( return JavaFXEventInvoker( ignoreCancelled = ignoreCancelled, callback = callback, + kEventType = E::class, eventType = E::class.java, instantFire = instantFire, ) diff --git a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt index 2c1e9b905..40085aba4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/eros/util/JavaFXInitializer.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.gui.eros.util 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.KUtil.asResourceLocation import de.bixilon.minosoft.util.logging.Log @@ -49,6 +50,7 @@ class JavaFXInitializer internal constructor() : Application() { @Synchronized fun start() { check(LATCH.count == 2) { "Already initialized!" } + Thread.setDefaultUncaughtExceptionHandler { _, exception -> exception.crash() } Log.log(LogMessageType.JAVAFX, LogLevels.VERBOSE) { "Initializing JavaFX Toolkit..." } Thread({ Application.launch(JavaFXInitializer::class.java) }, "JavaFX Toolkit Initializing Thread").start() diff --git a/src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/MojangJoinServerErrorException.java b/src/main/java/de/bixilon/minosoft/modding/event/EventInstantFire.kt similarity index 71% rename from src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/MojangJoinServerErrorException.java rename to src/main/java/de/bixilon/minosoft/modding/event/EventInstantFire.kt index a49dc8e98..69c21845c 100644 --- a/src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/MojangJoinServerErrorException.java +++ b/src/main/java/de/bixilon/minosoft/modding/event/EventInstantFire.kt @@ -1,6 +1,6 @@ /* * 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. * @@ -11,14 +11,11 @@ * 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) { - super(message); - } +interface EventInstantFire { - public MojangJoinServerErrorException() { - } + fun fire(): T } diff --git a/src/main/java/de/bixilon/minosoft/modding/event/events/account/AccountSelectEvent.kt b/src/main/java/de/bixilon/minosoft/modding/event/events/account/AccountSelectEvent.kt new file mode 100644 index 000000000..0c97f11bb --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/modding/event/events/account/AccountSelectEvent.kt @@ -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 . + * + * 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 { + + override fun fire(): AccountSelectEvent { + return AccountSelectEvent(null, Minosoft.config.config.account.selected) + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/modding/event/invoker/CallbackEventInvoker.kt b/src/main/java/de/bixilon/minosoft/modding/event/invoker/CallbackEventInvoker.kt index 0add5ab5a..e3f3b9bdc 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/invoker/CallbackEventInvoker.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/invoker/CallbackEventInvoker.kt @@ -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.Event import de.bixilon.minosoft.modding.loading.Priorities +import kotlin.reflect.KClass class CallbackEventInvoker private constructor( ignoreCancelled: Boolean, private val callback: (E) -> Unit, + override val kEventType: KClass, override val eventType: Class, override val instantFire: Boolean, ) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable { @@ -37,6 +39,7 @@ class CallbackEventInvoker private constructor( return CallbackEventInvoker( ignoreCancelled = ignoreCancelled, callback = callback, + kEventType = E::class, eventType = E::class.java, instantFire = instantFire, ) diff --git a/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvoker.kt b/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvoker.kt index a9200610c..21a400e45 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvoker.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvoker.kt @@ -15,13 +15,15 @@ package de.bixilon.minosoft.modding.event.invoker import de.bixilon.minosoft.modding.event.EventListener import de.bixilon.minosoft.modding.event.events.Event import de.bixilon.minosoft.modding.loading.Priorities +import kotlin.reflect.KClass abstract class EventInvoker( val isIgnoreCancelled: Boolean, val priority: Priorities, protected val listener: EventListener?, ) { - abstract val eventType: Class + abstract val kEventType: KClass? + abstract val eventType: Class abstract operator fun invoke(event: Event) } diff --git a/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvokerMethod.kt b/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvokerMethod.kt index afc2f56b3..338f21074 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvokerMethod.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/invoker/EventInvokerMethod.kt @@ -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.loading.Priorities import java.lang.reflect.Method +import kotlin.reflect.KClass class EventInvokerMethod( ignoreCancelled: Boolean, @@ -25,6 +26,7 @@ class EventInvokerMethod( listener: EventListener, val method: Method, ) : EventInvoker(ignoreCancelled, priority, listener) { + override val kEventType: KClass? = null override val eventType: Class = method.parameters[0].type as Class constructor(annotation: EventHandler, listener: EventListener, method: Method) : this(annotation.ignoreCancelled, annotation.priority, listener, method) diff --git a/src/main/java/de/bixilon/minosoft/modding/event/master/EventMaster.kt b/src/main/java/de/bixilon/minosoft/modding/event/master/EventMaster.kt index 4b1ff9013..f245761e8 100644 --- a/src/main/java/de/bixilon/minosoft/modding/event/master/EventMaster.kt +++ b/src/main/java/de/bixilon/minosoft/modding/event/master/EventMaster.kt @@ -13,12 +13,15 @@ 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.Event +import de.bixilon.minosoft.modding.event.invoker.EventInstantFireable import de.bixilon.minosoft.modding.event.invoker.EventInvoker import de.bixilon.minosoft.util.KUtil.synchronizedSetOf import de.bixilon.minosoft.util.KUtil.toSynchronizedList import de.bixilon.minosoft.util.KUtil.toSynchronizedSet +import kotlin.reflect.full.companionObjectInstance open class EventMaster(vararg parents: AbstractEventMaster) : AbstractEventMaster { val parents: MutableSet = synchronizedSetOf(*parents) @@ -62,10 +65,20 @@ open class EventMaster(vararg parents: AbstractEventMaster) : AbstractEventMaste override fun registerEvent(invoker: EventInvoker) { 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) { - eventInvokers += invoker + override fun registerEvents(vararg invokers: EventInvoker) { + for (invoker in invokers) { + registerEvent(invoker) + } } override fun iterator(): Iterator { diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt index 91bf47278..4f126099b 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/play/PlayConnection.kt @@ -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)} try { fireEvent(RegistriesLoadEvent(this, registries, RegistriesLoadEvent.States.PRE)) diff --git a/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt b/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt index ffb9ebdf7..06793d66d 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/network/connection/status/StatusConnection.kt @@ -64,8 +64,8 @@ class StatusConnection( field = value value?.let { fireEvent(StatusConnectionErrorEvent(this, EventInitiators.UNKNOWN, it)) + pingStatus = StatusConnectionStatuses.ERROR } - pingStatus = StatusConnectionStatuses.ERROR } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/login/LoginKickS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/login/LoginKickS2CP.kt index dd61adb13..396de295a 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/login/LoginKickS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/login/LoginKickS2CP.kt @@ -26,7 +26,7 @@ class LoginKickS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { override fun handle(connection: PlayConnection) { 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() } diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt index 7d090a462..5ba68b7af 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/InByteBuffer.kt @@ -249,7 +249,7 @@ open class InByteBuffer { } fun readJson(): Map { - return JSONSerializer.MAP_ADAPTER.fromJson(readString())!! + return JSONSerializer.MUTABLE_MAP_ADAPTER.fromJson(readString())!! } fun readJsonArray(length: Int = readVarInt()): Array> { diff --git a/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java b/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java index e81e5b749..ded06c478 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java +++ b/src/main/java/de/bixilon/minosoft/protocol/protocol/ProtocolDefinition.java @@ -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_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 = "fe6f0fbf-3038-486a-9c84-6a28b71e0455"; diff --git a/src/main/java/de/bixilon/minosoft/util/HTTP.java b/src/main/java/de/bixilon/minosoft/util/HTTP.java index 2a3c8924c..9812ea1fd 100644 --- a/src/main/java/de/bixilon/minosoft/util/HTTP.java +++ b/src/main/java/de/bixilon/minosoft/util/HTTP.java @@ -24,6 +24,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.HashMap; +@Deprecated public final class HTTP { public static HttpResponse postJson(String url, String json, HashMap headers) throws IOException, InterruptedException { diff --git a/src/main/java/de/bixilon/minosoft/util/KUtil.kt b/src/main/java/de/bixilon/minosoft/util/KUtil.kt index 90b5b1f3d..f168668e9 100644 --- a/src/main/java/de/bixilon/minosoft/util/KUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/KUtil.kt @@ -17,6 +17,7 @@ import com.squareup.moshi.JsonAdapter import com.squareup.moshi.JsonWriter import de.bixilon.minosoft.data.entities.entities.Entity 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.ChatComponent import de.bixilon.minosoft.data.text.TextComponent @@ -169,6 +170,22 @@ object KUtil { } } + fun Boolean.decide(`true`: T, `false`: () -> T): T { + return if (this) { + `true` + } else { + `false`() + } + } + + fun Boolean.decide(`true`: () -> T, `false`: T): T { + return if (this) { + `true`() + } else { + `false` + } + } + fun String.asUUID(): UUID { return Util.getUUIDFromString(this) } @@ -325,4 +342,19 @@ object KUtil { val Class<*>.realName: String get() = this.name.removePrefix(this.packageName).removePrefix(".") + + fun UUID.trim(): String { + return this.toString().replace("-", "") + } + + + fun List.asResourceLocationMap(): Map { + val ret: MutableMap = mutableMapOf() + + for (value in this) { + ret[value.resourceLocation] = value + } + + return ret.toMap() + } } diff --git a/src/main/java/de/bixilon/minosoft/util/http/HTTP2.kt b/src/main/java/de/bixilon/minosoft/util/http/HTTP2.kt new file mode 100644 index 000000000..db910cb10 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/http/HTTP2.kt @@ -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 . + * + * 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.headers(): Array { + val headers: MutableList = mutableListOf() + + for ((key, value) in this) { + headers += key + headers += value.toString() + } + return headers.toTypedArray() + } + + fun post(url: String, data: Payload, bodyPublisher: (Payload) -> String, bodyBuilder: (String) -> Response, headers: Map = mapOf()): HTTPResponse { + 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.postJson(url: String, headers: Map = mapOf()): HTTPResponse?> { + 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", + ) + ) + } + +} diff --git a/src/main/java/de/bixilon/minosoft/util/http/HTTPResponse.kt b/src/main/java/de/bixilon/minosoft/util/http/HTTPResponse.kt new file mode 100644 index 000000000..476450df2 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/http/HTTPResponse.kt @@ -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 . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.util.http + +class HTTPResponse( + val statusCode: Int, + val body: T, +) diff --git a/src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/AuthenticationException.java b/src/main/java/de/bixilon/minosoft/util/http/exceptions/AuthenticationException.kt similarity index 79% rename from src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/AuthenticationException.java rename to src/main/java/de/bixilon/minosoft/util/http/exceptions/AuthenticationException.kt index 310019d2a..90c03c7f4 100644 --- a/src/main/java/de/bixilon/minosoft/util/mojang/api/exceptions/AuthenticationException.java +++ b/src/main/java/de/bixilon/minosoft/util/http/exceptions/AuthenticationException.kt @@ -10,12 +10,9 @@ * * 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; - -public class AuthenticationException extends Exception { - - public AuthenticationException(String message) { - super(message); - } -} +class AuthenticationException( + statusCode: Int, + message: String? = null, +) : HTTPException(statusCode, message) diff --git a/src/main/java/de/bixilon/minosoft/util/http/exceptions/HTTPException.kt b/src/main/java/de/bixilon/minosoft/util/http/exceptions/HTTPException.kt new file mode 100644 index 000000000..00c04104d --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/http/exceptions/HTTPException.kt @@ -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 . + * + * 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) diff --git a/src/main/java/de/bixilon/minosoft/util/json/AccountSerializer.kt b/src/main/java/de/bixilon/minosoft/util/json/AccountSerializer.kt index add679feb..4a6d4a495 100644 --- a/src/main/java/de/bixilon/minosoft/util/json/AccountSerializer.kt +++ b/src/main/java/de/bixilon/minosoft/util/json/AccountSerializer.kt @@ -14,25 +14,22 @@ package de.bixilon.minosoft.util.json import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonAdapter import com.squareup.moshi.ToJson import de.bixilon.minosoft.data.accounts.Account -import de.bixilon.minosoft.data.accounts.MicrosoftAccount -import de.bixilon.minosoft.data.accounts.MojangAccount -import de.bixilon.minosoft.data.accounts.OfflineAccount +import de.bixilon.minosoft.data.accounts.AccountTypes +import de.bixilon.minosoft.util.KUtil.asResourceLocation +import de.bixilon.minosoft.util.KUtil.unsafeCast +import de.bixilon.minosoft.util.nbt.tag.NBTUtil.asCompound object AccountSerializer { @FromJson fun fromJson(json: Map): Account { - return when (json["type"]!!) { - "mojang" -> MojangAccount.deserialize(json) - "offline" -> OfflineAccount.deserialize(json) - "microsoft" -> MicrosoftAccount.deserialize(json) - else -> throw IllegalArgumentException("Invalid account type: ${json["type"]}") - } + return AccountTypes.ACCOUNT_TYPES[json["type"]!!.asResourceLocation()]!!.TYPE.fromJsonValue(json)!! } @ToJson fun toJson(account: Account): Map { - return account.serialize() + return AccountTypes.ACCOUNT_TYPES[account.type]!!.TYPE.unsafeCast>().toJsonValue(account).asCompound() } } diff --git a/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt b/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt index d45afb36c..c0041687d 100644 --- a/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt +++ b/src/main/java/de/bixilon/minosoft/util/json/JSONSerializer.kt @@ -21,19 +21,21 @@ import de.bixilon.minosoft.config.config.Config import de.bixilon.minosoft.gui.rendering.textures.properties.ImageProperties object JSONSerializer { - private val MOSHI = Moshi.Builder() + val MOSHI = Moshi.Builder() .add(RGBColorSerializer) .add(Vec2Serializer) .add(AccountSerializer) .add(ChatComponentSerializer) .add(ServerAddressSerializer) .add(ResourceLocationSerializer) + .add(UUIDSerializer) .add(KotlinJsonAdapterFactory()) .build()!! val ANY_ADAPTER = MOSHI.adapter(Any::class.java)!! val CONFIG_ADAPTER = MOSHI.adapter(Config::class.java)!! - val MAP_ADAPTER: JsonAdapter> = MOSHI.adapter(Types.newParameterizedType(MutableMap::class.java, String::class.java, Any::class.java)) + val MUTABLE_MAP_ADAPTER: JsonAdapter> = MOSHI.adapter(Types.newParameterizedType(MutableMap::class.java, String::class.java, Any::class.java)) + val MAP_ADAPTER: JsonAdapter> = MOSHI.adapter(Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)) val IMAGE_PROPERTIES_ADAPTER = MOSHI.adapter(ImageProperties::class.java)!! } diff --git a/src/main/java/de/bixilon/minosoft/util/json/UUIDSerializer.kt b/src/main/java/de/bixilon/minosoft/util/json/UUIDSerializer.kt new file mode 100644 index 000000000..7c653c955 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/util/json/UUIDSerializer.kt @@ -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 . + * + * 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() { + @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()) + } +} diff --git a/src/main/java/de/bixilon/minosoft/util/logging/LogMessageType.kt b/src/main/java/de/bixilon/minosoft/util/logging/LogMessageType.kt index bf75817e2..ad4d7ef93 100644 --- a/src/main/java/de/bixilon/minosoft/util/logging/LogMessageType.kt +++ b/src/main/java/de/bixilon/minosoft/util/logging/LogMessageType.kt @@ -30,6 +30,8 @@ enum class LogMessageType( VERSION_LOADING(ChatColors.YELLOW), ASSETS(ChatColors.BLACK), + AUTHENTICATION(ChatColors.BLACK), + NETWORK_RESOLVING(ChatColors.DARK_GREEN), NETWORK_STATUS(ChatColors.DARK_GREEN), NETWORK_PACKETS_IN(ChatColors.BLUE, mapOf( diff --git a/src/main/java/de/bixilon/minosoft/util/microsoft/MicrosoftOAuthUtils.kt b/src/main/java/de/bixilon/minosoft/util/microsoft/MicrosoftOAuthUtils.kt index 5c79220df..1e46df006 100644 --- a/src/main/java/de/bixilon/minosoft/util/microsoft/MicrosoftOAuthUtils.kt +++ b/src/main/java/de/bixilon/minosoft/util/microsoft/MicrosoftOAuthUtils.kt @@ -14,8 +14,7 @@ package de.bixilon.minosoft.util.microsoft import com.google.gson.JsonParser -import de.bixilon.minosoft.data.accounts.Account -import de.bixilon.minosoft.data.accounts.MicrosoftAccount +import de.bixilon.minosoft.data.accounts.types.MicrosoftAccount import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition import de.bixilon.minosoft.terminal.RunConfiguration import de.bixilon.minosoft.util.HTTP @@ -38,7 +37,7 @@ object MicrosoftOAuthUtils { val xstsToken = getXSTSToken(xboxLiveToken.first) val microsoftAccount = getMicrosoftAccount(getMinecraftAccessToken(xboxLiveToken.second, xstsToken)) - Account.addAccount(microsoftAccount) + // ToDo: Account.addAccount(microsoftAccount) } catch (exception: Exception) { Log.warn("Can not login into microsoft account") exception.printStackTrace() @@ -162,7 +161,8 @@ object MicrosoftOAuthUtils { } 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 { diff --git a/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAuthentication.java b/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAuthentication.java deleted file mode 100644 index bd15735bc..000000000 --- a/src/main/java/de/bixilon/minosoft/util/mojang/api/MojangAuthentication.java +++ /dev/null @@ -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 . - * - * 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 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 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 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(); - } -} diff --git a/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt b/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt index f22ea400b..82b984f8e 100644 --- a/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt +++ b/src/main/java/de/bixilon/minosoft/util/nbt/tag/NBTUtil.kt @@ -14,6 +14,11 @@ package de.bixilon.minosoft.util.nbt.tag object NBTUtil { + + fun compound(): MutableMap { + return mutableMapOf() + } + fun MutableMap.getAndRemove(key: String): Any? { val value = this[key] this.remove(key) diff --git a/src/main/resources/assets/minosoft/eros/main/main.fxml b/src/main/resources/assets/minosoft/eros/main/main.fxml index 0e78fc51e..8c53b7633 100644 --- a/src/main/resources/assets/minosoft/eros/main/main.fxml +++ b/src/main/resources/assets/minosoft/eros/main/main.fxml @@ -5,7 +5,7 @@ - + @@ -77,7 +77,21 @@ - + + + + + + + + + + + + + + + diff --git a/src/main/resources/assets/minosoft/language/en_us.lang b/src/main/resources/assets/minosoft/language/en_us.lang index ccff3f6db..853782082 100644 --- a/src/main/resources/assets/minosoft/language/en_us.lang +++ b/src/main/resources/assets/minosoft/language/en_us.lang @@ -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: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.resolving=Resolving hostname...