mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 19:05:02 -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 LANGUAGE_MANAGER = MultiLanguageManager()
|
||||
val START_UP_LATCH = CountUpAndDownLatch(1)
|
||||
|
||||
@Deprecated("Will be singleton interface")
|
||||
lateinit var config: Configuration
|
||||
|
||||
var initialized: Boolean = false
|
||||
|
@ -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
|
||||
|
@ -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<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)
|
||||
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) }
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* 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()
|
||||
}
|
@ -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 LAYOUT = "minosoft:eros/main/main.fxml".asResourceLocation()
|
||||
|
||||
lateinit var mainErosController: MainErosController
|
||||
|
||||
|
||||
init {
|
||||
Minosoft.GLOBAL_EVENT_MASTER.registerEvent(CallbackEventInvoker.of<FinishInitializingEvent> {
|
||||
Platform.runLater {
|
||||
val mainErosController = JavaFXUtil.openModal<MainErosController>(TITLE, LAYOUT)
|
||||
mainErosController = JavaFXUtil.openModal<MainErosController>(TITLE, LAYOUT)
|
||||
mainErosController.stage.show()
|
||||
}
|
||||
})
|
||||
|
@ -35,4 +35,6 @@ abstract class JavaFXController : Initializable {
|
||||
}
|
||||
|
||||
open fun init() {}
|
||||
|
||||
open fun postInit() {}
|
||||
}
|
||||
|
@ -17,7 +17,4 @@ import javafx.stage.Stage
|
||||
|
||||
abstract class JavaFXWindowController : JavaFXController() {
|
||||
lateinit var stage: Stage
|
||||
|
||||
|
||||
open fun postInit() {}
|
||||
}
|
||||
|
@ -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<Parent>()
|
||||
@ -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}
|
||||
|
@ -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<FontIcon>
|
||||
|
||||
@ -84,6 +92,12 @@ class MainErosController : JavaFXWindowController() {
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -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<Pane>() {
|
||||
}
|
||||
}
|
||||
|
||||
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<Pane>() {
|
||||
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<Pane>() {
|
||||
|
||||
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<Pane>() {
|
||||
|
||||
|
||||
private companion object {
|
||||
private val SERVER_INFO_PROPERTIES: Map<ResourceLocation, (server: Server) -> Any> = mapOf(
|
||||
"minosoft:server_name".asResourceLocation() to { it.name },
|
||||
"minosoft:server_address".asResourceLocation() to { it.address },
|
||||
private val SERVER_INFO_PROPERTIES: Map<ResourceLocation, (server: Server) -> 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)!! } },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -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<E : Event> private constructor(
|
||||
ignoreCancelled: Boolean,
|
||||
private val callback: (E) -> Unit,
|
||||
override val kEventType: KClass<out Event>,
|
||||
override val eventType: Class<out Event>,
|
||||
override val instantFire: Boolean,
|
||||
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable {
|
||||
@ -46,6 +48,7 @@ class JavaFXEventInvoker<E : Event> private constructor(
|
||||
return JavaFXEventInvoker(
|
||||
ignoreCancelled = ignoreCancelled,
|
||||
callback = callback,
|
||||
kEventType = E::class,
|
||||
eventType = E::class.java,
|
||||
instantFire = instantFire,
|
||||
)
|
||||
|
@ -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()
|
||||
|
@ -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<T : Event> {
|
||||
|
||||
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.Event
|
||||
import de.bixilon.minosoft.modding.loading.Priorities
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class CallbackEventInvoker<E : Event> private constructor(
|
||||
ignoreCancelled: Boolean,
|
||||
private val callback: (E) -> Unit,
|
||||
override val kEventType: KClass<out Event>,
|
||||
override val eventType: Class<out Event>,
|
||||
override val instantFire: Boolean,
|
||||
) : EventInvoker(ignoreCancelled, Priorities.NORMAL, null), EventInstantFireable {
|
||||
@ -37,6 +39,7 @@ class CallbackEventInvoker<E : Event> private constructor(
|
||||
return CallbackEventInvoker(
|
||||
ignoreCancelled = ignoreCancelled,
|
||||
callback = callback,
|
||||
kEventType = E::class,
|
||||
eventType = E::class.java,
|
||||
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.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<out Event?>
|
||||
abstract val kEventType: KClass<out Event>?
|
||||
abstract val eventType: Class<out 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.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<out Event>? = null
|
||||
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)
|
||||
|
@ -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<AbstractEventMaster> = 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<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)}
|
||||
try {
|
||||
fireEvent(RegistriesLoadEvent(this, registries, RegistriesLoadEvent.States.PRE))
|
||||
|
@ -64,8 +64,8 @@ class StatusConnection(
|
||||
field = value
|
||||
value?.let {
|
||||
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) {
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ open class InByteBuffer {
|
||||
}
|
||||
|
||||
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>> {
|
||||
|
@ -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";
|
||||
|
@ -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<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 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 <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 {
|
||||
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 <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.
|
||||
*/
|
||||
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)
|
@ -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
|
||||
|
||||
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<String, Any>): 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<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
|
||||
|
||||
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<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)!!
|
||||
}
|
||||
|
@ -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),
|
||||
ASSETS(ChatColors.BLACK),
|
||||
|
||||
AUTHENTICATION(ChatColors.BLACK),
|
||||
|
||||
NETWORK_RESOLVING(ChatColors.DARK_GREEN),
|
||||
NETWORK_STATUS(ChatColors.DARK_GREEN),
|
||||
NETWORK_PACKETS_IN(ChatColors.BLUE, mapOf(
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
object NBTUtil {
|
||||
|
||||
fun compound(): MutableMap<String, Any> {
|
||||
return mutableMapOf()
|
||||
}
|
||||
|
||||
fun MutableMap<String, Any>.getAndRemove(key: String): Any? {
|
||||
val value = this[key]
|
||||
this.remove(key)
|
||||
|
@ -5,7 +5,7 @@
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
<?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">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="ALWAYS" minWidth="10.0" prefWidth="100.0"/>
|
||||
@ -77,7 +77,21 @@
|
||||
</GridPane.margin>
|
||||
</FontIcon>
|
||||
</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>
|
||||
<Insets bottom="3.0" left="5.0" right="5.0" top="3.0"/>
|
||||
</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: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...
|
||||
|
Loading…
x
Reference in New Issue
Block a user