diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt b/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt index dc36c188366..dbf695f3aaf 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/LiquidBounce.kt @@ -19,8 +19,8 @@ */ package net.ccbluex.liquidbounce +import net.ccbluex.liquidbounce.api.core.withScope import net.ccbluex.liquidbounce.api.models.auth.ClientAccount -import net.ccbluex.liquidbounce.api.services.auth.OAuthClient import net.ccbluex.liquidbounce.api.services.client.ClientUpdate.gitInfo import net.ccbluex.liquidbounce.api.services.client.ClientUpdate.hasUpdate import net.ccbluex.liquidbounce.api.thirdparty.IpInfoApi @@ -261,7 +261,7 @@ object LiquidBounce : EventListener { // Check if client account is available if (ClientAccountManager.clientAccount != ClientAccount.EMPTY_ACCOUNT) { - OAuthClient.runWithScope { + withScope { runCatching { ClientAccountManager.clientAccount.renew() }.onFailure { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/api/core/BaseApi.kt b/src/main/kotlin/net/ccbluex/liquidbounce/api/core/BaseApi.kt index 72536df092a..168876518a3 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/api/core/BaseApi.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/api/core/BaseApi.kt @@ -47,7 +47,7 @@ abstract class BaseApi(protected val baseUrl: String) { protected suspend inline fun request( endpoint: String, method: HttpMethod, - noinline headers: Headers.Builder.() -> Unit = {}, + crossinline headers: Headers.Builder.() -> Unit = {}, body: RequestBody? = null ): T = HttpClient.request("$baseUrl$endpoint", method, headers = { add("X-Session-Token", SESSION_TOKEN) @@ -56,30 +56,30 @@ abstract class BaseApi(protected val baseUrl: String) { protected suspend inline fun get( endpoint: String, - noinline headers: Headers.Builder.() -> Unit = {} + crossinline headers: Headers.Builder.() -> Unit = {} ): T = request(endpoint, HttpMethod.GET, headers) protected suspend inline fun post( endpoint: String, body: RequestBody? = null, - noinline headers: Headers.Builder.() -> Unit = {} + crossinline headers: Headers.Builder.() -> Unit = {} ): T = request(endpoint, HttpMethod.POST, headers, body) protected suspend inline fun put( endpoint: String, body: RequestBody? = null, - noinline headers: Headers.Builder.() -> Unit = {} + crossinline headers: Headers.Builder.() -> Unit = {} ): T = request(endpoint, HttpMethod.PUT, headers, body) protected suspend inline fun patch( endpoint: String, body: RequestBody? = null, - noinline headers: Headers.Builder.() -> Unit = {} + crossinline headers: Headers.Builder.() -> Unit = {} ): T = request(endpoint, HttpMethod.PATCH, headers, body) protected suspend inline fun delete( endpoint: String, - noinline headers: Headers.Builder.() -> Unit = {} + crossinline headers: Headers.Builder.() -> Unit = {} ): T = request(endpoint, HttpMethod.DELETE, headers) } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/api/core/HttpClient.kt b/src/main/kotlin/net/ccbluex/liquidbounce/api/core/HttpClient.kt index 6f723db86c7..2fa39a59c02 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/api/core/HttpClient.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/api/core/HttpClient.kt @@ -18,6 +18,10 @@ */ package net.ccbluex.liquidbounce.api.core +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import net.ccbluex.liquidbounce.LiquidBounce import net.ccbluex.liquidbounce.config.gson.util.decode import net.minecraft.client.texture.NativeImage @@ -34,6 +38,10 @@ import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine +private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + +fun withScope(block: suspend CoroutineScope.() -> Unit) = scope.launch { block() } + object HttpClient { val DEFAULT_AGENT = "${LiquidBounce.CLIENT_NAME}/${LiquidBounce.clientVersion}" + @@ -131,4 +139,4 @@ suspend inline fun Response.parse(): T { fun String.asJson() = toRequestBody(HttpClient.JSON_MEDIA_TYPE) fun String.asForm() = toRequestBody(HttpClient.FORM_MEDIA_TYPE) -class HttpException(val code: Int, message: String) : Exception(message) +class HttpException(val code: Int, message: String) : Exception("HTTP $code: $message") diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/api/services/auth/OAuthClient.kt b/src/main/kotlin/net/ccbluex/liquidbounce/api/services/auth/OAuthClient.kt index 031fc35b8fb..1ea8e0790e9 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/api/services/auth/OAuthClient.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/api/services/auth/OAuthClient.kt @@ -24,12 +24,9 @@ import io.netty.channel.nio.NioEventLoopGroup import io.netty.channel.socket.SocketChannel import io.netty.channel.socket.nio.NioServerSocketChannel import io.netty.handler.codec.http.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch import net.ccbluex.liquidbounce.api.core.AUTH_AUTHORIZE_URL import net.ccbluex.liquidbounce.api.core.AUTH_CLIENT_ID +import net.ccbluex.liquidbounce.api.core.withScope import net.ccbluex.liquidbounce.api.models.auth.ClientAccount import net.ccbluex.liquidbounce.api.models.auth.OAuthSession import java.net.InetSocketAddress @@ -44,16 +41,10 @@ import kotlin.coroutines.suspendCoroutine */ object OAuthClient { - private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) - private var serverPort: Int? = null @Volatile private var authCodeContinuation: Continuation? = null - fun runWithScope(block: suspend CoroutineScope.() -> Unit) { - scope.launch { block() } - } - /** * Start the OAuth authentication flow * @@ -89,7 +80,7 @@ object OAuthClient { } private suspend fun startNettyServer(): Int = suspendCoroutine { cont -> - scope.launch { + withScope { runCatching { val bossGroup = NioEventLoopGroup(1) val workerGroup = NioEventLoopGroup() diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/api/thirdparty/MojangApi.kt b/src/main/kotlin/net/ccbluex/liquidbounce/api/thirdparty/MojangApi.kt new file mode 100644 index 00000000000..d26fe3c4ea3 --- /dev/null +++ b/src/main/kotlin/net/ccbluex/liquidbounce/api/thirdparty/MojangApi.kt @@ -0,0 +1,30 @@ +/* + * This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce) + * + * Copyright (c) 2015 - 2025 CCBlueX + * + * LiquidBounce 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. + * + * LiquidBounce 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 LiquidBounce. If not, see . + */ +package net.ccbluex.liquidbounce.api.thirdparty + +import net.ccbluex.liquidbounce.api.core.BaseApi + +object MojangApi : BaseApi("https://api.mojang.com") { + + suspend fun getNames(uuidAsString: String): List = + get>("/user/profiles/$uuidAsString/names") + + data class UsernameRecord(val name: String, val changedToAt: Int?) + +} diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/config/AutoConfig.kt b/src/main/kotlin/net/ccbluex/liquidbounce/config/AutoConfig.kt index d5329183dac..33240ba65a5 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/config/AutoConfig.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/config/AutoConfig.kt @@ -22,6 +22,7 @@ import com.google.gson.JsonObject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import net.ccbluex.liquidbounce.LiquidBounce +import net.ccbluex.liquidbounce.api.core.withScope import net.ccbluex.liquidbounce.api.models.client.AutoSettings import net.ccbluex.liquidbounce.api.services.client.ClientApi import net.ccbluex.liquidbounce.api.types.enums.AutoSettingsStatusType @@ -35,7 +36,6 @@ import net.ccbluex.liquidbounce.features.module.ModuleManager import net.ccbluex.liquidbounce.features.module.modules.render.ModuleClickGui import net.ccbluex.liquidbounce.utils.client.* import net.minecraft.util.Formatting -import net.minecraft.util.Util import java.io.Writer import java.text.SimpleDateFormat import java.util.* @@ -73,8 +73,6 @@ object AutoConfig { } } - fun startLoaderTask(task: Runnable) = Util.getDownloadWorkerExecutor().execute(task) - inline fun withLoading(block: () -> Unit) { loadingNow = true try { @@ -84,13 +82,11 @@ object AutoConfig { } } - fun loadAutoConfig(autoConfig: AutoSettings) = startLoaderTask { + fun loadAutoConfig(autoConfig: AutoSettings) = withScope { withLoading { runCatching { - runBlocking(Dispatchers.IO) { - ClientApi.requestSettingsScript(autoConfig.settingId).apply { - ConfigSystem.deserializeConfigurable(ModuleManager.modulesConfigurable, reader(), publicGson) - } + ClientApi.requestSettingsScript(autoConfig.settingId).apply { + ConfigSystem.deserializeConfigurable(ModuleManager.modulesConfigurable, reader(), publicGson) } }.onFailure { notification("Auto Config", "Failed to load config ${autoConfig.name}.", diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/CommandConfig.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/CommandConfig.kt index bcbead5d349..0f36e1dfc82 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/CommandConfig.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/CommandConfig.kt @@ -18,11 +18,10 @@ */ package net.ccbluex.liquidbounce.features.command.commands.client -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking import net.ccbluex.liquidbounce.api.core.HttpClient import net.ccbluex.liquidbounce.api.core.HttpMethod import net.ccbluex.liquidbounce.api.core.parse +import net.ccbluex.liquidbounce.api.core.withScope import net.ccbluex.liquidbounce.api.services.client.ClientApi import net.ccbluex.liquidbounce.config.AutoConfig import net.ccbluex.liquidbounce.config.AutoConfig.configs @@ -149,16 +148,14 @@ object CommandConfig : CommandFactory { val modules = ModuleManager.parseModulesFromParameter(moduleNames) // Load the config in a separate thread to prevent the client from freezing - AutoConfig.startLoaderTask { + withScope { runCatching { - runBlocking(Dispatchers.IO) { - if (name.startsWith("http")) { - // Load the config from the specified URL - HttpClient.request(name, HttpMethod.GET).parse().reader() - } else { - // Get online config from API - ClientApi.requestSettingsScript(name).reader() - } + if (name.startsWith("http")) { + // Load the config from the specified URL + HttpClient.request(name, HttpMethod.GET).parse().reader() + } else { + // Get online config from API + ClientApi.requestSettingsScript(name).reader() } }.onSuccess { sourceReader -> AutoConfig.withLoading { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/client/CommandClientAccountSubcommand.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/client/CommandClientAccountSubcommand.kt index 19deb640666..04b32c438a6 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/client/CommandClientAccountSubcommand.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/command/commands/client/client/CommandClientAccountSubcommand.kt @@ -1,7 +1,7 @@ package net.ccbluex.liquidbounce.features.command.commands.client.client +import net.ccbluex.liquidbounce.api.core.withScope import net.ccbluex.liquidbounce.api.models.auth.ClientAccount.Companion.EMPTY_ACCOUNT -import net.ccbluex.liquidbounce.api.services.auth.OAuthClient import net.ccbluex.liquidbounce.api.services.auth.OAuthClient.startAuth import net.ccbluex.liquidbounce.config.ConfigSystem import net.ccbluex.liquidbounce.features.command.builder.CommandBuilder @@ -28,7 +28,7 @@ object CommandClientAccountSubcommand { } chat(regular("Getting user information...")) - OAuthClient.runWithScope { + withScope { runCatching { val account = ClientAccountManager.clientAccount account.updateInfo() @@ -53,7 +53,7 @@ object CommandClientAccountSubcommand { } chat(regular("Logging out...")) - OAuthClient.runWithScope { + withScope { ClientAccountManager.clientAccount = EMPTY_ACCOUNT ConfigSystem.storeConfigurable(ClientAccountManager) chat(regular("Successfully logged out.")) @@ -68,7 +68,7 @@ object CommandClientAccountSubcommand { } chat(regular("Starting OAuth authorization process...")) - OAuthClient.runWithScope { + withScope { val account = startAuth { Util.getOperatingSystem().open(it) } ClientAccountManager.clientAccount = account ConfigSystem.storeConfigurable(ClientAccountManager) diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/cosmetic/CosmeticService.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/cosmetic/CosmeticService.kt index 7b73a104171..78944774435 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/cosmetic/CosmeticService.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/cosmetic/CosmeticService.kt @@ -18,12 +18,11 @@ */ package net.ccbluex.liquidbounce.features.cosmetic -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.Job +import net.ccbluex.liquidbounce.api.core.withScope import net.ccbluex.liquidbounce.api.models.auth.ClientAccount import net.ccbluex.liquidbounce.api.models.cosmetics.Cosmetic import net.ccbluex.liquidbounce.api.models.cosmetics.CosmeticCategory -import net.ccbluex.liquidbounce.api.services.auth.OAuthClient import net.ccbluex.liquidbounce.api.services.cosmetics.CosmeticApi import net.ccbluex.liquidbounce.config.types.Configurable import net.ccbluex.liquidbounce.event.EventListener @@ -36,9 +35,7 @@ import net.ccbluex.liquidbounce.utils.client.mc import net.ccbluex.liquidbounce.utils.client.player import net.ccbluex.liquidbounce.utils.kotlin.toMD5 import net.minecraft.client.session.Session -import net.minecraft.util.Util import java.util.* -import java.util.concurrent.Future /** * A more reliable, safer and stress reduced cosmetics service @@ -63,7 +60,7 @@ object CosmeticService : EventListener, Configurable("Cosmetics") { internal var carriersCosmetics = hashMapOf>() private val lastUpdate = Chronometer() - private var task: Future<*>? = null + private var task: Job? = null /** * Refresh cosmetic carriers if needed from the API in a MD5-hashed UUID set @@ -75,11 +72,9 @@ object CosmeticService : EventListener, Configurable("Cosmetics") { if (task == null) { // Check if the required time in milliseconds has passed of the REFRESH_DELAY if (lastUpdate.hasElapsed(REFRESH_DELAY) || force) { - task = Util.getDownloadWorkerExecutor().service.submit { + task = withScope { runCatching { - carriers = runBlocking(Dispatchers.IO) { - CosmeticApi.getCarriers() - } + carriers = CosmeticApi.getCarriers() task = null // Reset timer and start once again @@ -112,11 +107,11 @@ object CosmeticService : EventListener, Configurable("Cosmetics") { clientAccount.cosmetics = emptySet() // Update cosmetics - OAuthClient.runWithScope { + withScope { clientAccount.updateCosmetics() clientAccount.cosmetics?.let { cosmetics -> - done(cosmetics.find { cosmetic -> cosmetic.category == category } ?: return@runWithScope) + done(cosmetics.find { cosmetic -> cosmetic.category == category } ?: return@withScope) } } return @@ -136,11 +131,9 @@ object CosmeticService : EventListener, Configurable("Cosmetics") { // Pre-allocate a set to prevent multiple requests carriersCosmetics[uuid] = emptySet() - Util.getDownloadWorkerExecutor().execute { + withScope { runCatching { - val cosmetics = runBlocking(Dispatchers.IO) { - CosmeticApi.getCarrierCosmetics(uuid) - } + val cosmetics = CosmeticApi.getCarrierCosmetics(uuid) carriersCosmetics[uuid] = cosmetics done(cosmetics.find { cosmetic -> cosmetic.category == category } ?: return@runCatching) @@ -178,7 +171,7 @@ object CosmeticService : EventListener, Configurable("Cosmetics") { return } - OAuthClient.runWithScope { + withScope { runCatching { clientAccount.transferTemporaryOwnership(uuid) }.onSuccess { diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/itemgroup/groups/HeadsItemGroup.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/itemgroup/groups/HeadsItemGroup.kt index 02bcf63d820..9919a3f0b98 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/itemgroup/groups/HeadsItemGroup.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/itemgroup/groups/HeadsItemGroup.kt @@ -63,7 +63,7 @@ data class Head(val name: String, val uuid: UUID, val value: String) { */ const val HEAD_DB_API = "https://headdb.org/api/category/all" -val headsCollection by lazy { +val headsCollection by lazy(LazyThreadSafetyMode.NONE) { runCatching { logger.info("Loading heads...") // Load heads from service diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleAntiStaff.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleAntiStaff.kt index ccec32eee9c..de40adef1d0 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleAntiStaff.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/misc/ModuleAntiStaff.kt @@ -1,12 +1,8 @@ package net.ccbluex.liquidbounce.features.module.modules.misc import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking import net.ccbluex.liquidbounce.LiquidBounce.CLIENT_CLOUD -import net.ccbluex.liquidbounce.api.core.HttpClient -import net.ccbluex.liquidbounce.api.core.HttpException -import net.ccbluex.liquidbounce.api.core.HttpMethod -import net.ccbluex.liquidbounce.api.core.parse +import net.ccbluex.liquidbounce.api.core.* import net.ccbluex.liquidbounce.config.types.ToggleableConfigurable import net.ccbluex.liquidbounce.event.events.NotificationEvent import net.ccbluex.liquidbounce.event.events.PacketEvent @@ -19,7 +15,6 @@ import net.ccbluex.liquidbounce.utils.client.* import net.ccbluex.liquidbounce.utils.kotlin.EventPriorityConvention import net.minecraft.network.packet.s2c.play.EntityVelocityUpdateS2CPacket import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket -import kotlin.concurrent.thread /** * Notifies you about staff actions. @@ -78,7 +73,9 @@ object ModuleAntiStaff : ClientModule("AntiStaff", Category.MISC) { } serverStaffList[address] = arrayOf() - loadStaffList(address) + withScope { + loadStaffList(address) + } super.enable() } @@ -93,7 +90,11 @@ object ModuleAntiStaff : ClientModule("AntiStaff", Category.MISC) { // Keeps us from loading the staff list multiple times waitUntil { inGame && mc.currentScreen != null } - loadStaffList(address) + + // Load the staff list + waitFor(Dispatchers.IO) { + loadStaffList(address) + } } val packetHandler = handler { event -> @@ -113,30 +114,26 @@ object ModuleAntiStaff : ClientModule("AntiStaff", Category.MISC) { } } - fun loadStaffList(address: String) { - // Loads the server config - thread(name = "staff-loader") { - - try { - val staffs = runBlocking(Dispatchers.IO) { - HttpClient.request("$CLIENT_CLOUD/staffs/$address", HttpMethod.GET).parse() - }.lines().toTypedArray() - - serverStaffList[address] = staffs - - notification("AntiStaff", message("staffsLoaded", staffs.size, address), - NotificationEvent.Severity.SUCCESS) - } catch (httpException: HttpException) { - when (httpException.code) { - 404 -> notification("AntiStaff", message("noStaffs", address), - NotificationEvent.Severity.ERROR) - else -> notification("AntiStaff", message("staffsFailed", address, httpException.code), - NotificationEvent.Severity.ERROR) - } - } catch (exception: Exception) { - notification("AntiStaff", message("staffsFailed", address, exception.javaClass.simpleName), + suspend fun loadStaffList(address: String) { + try { + val staffs = HttpClient.request("$CLIENT_CLOUD/staffs/$address", HttpMethod.GET).parse() + .lines() + .toTypedArray() + + serverStaffList[address] = staffs + + notification("AntiStaff", message("staffsLoaded", staffs.size, address), + NotificationEvent.Severity.SUCCESS) + } catch (httpException: HttpException) { + when (httpException.code) { + 404 -> notification("AntiStaff", message("noStaffs", address), + NotificationEvent.Severity.ERROR) + else -> notification("AntiStaff", message("staffsFailed", address, httpException.code), NotificationEvent.Severity.ERROR) } + } catch (exception: Exception) { + notification("AntiStaff", message("staffsFailed", address, exception.javaClass.simpleName), + NotificationEvent.Severity.ERROR) } } diff --git a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleMobOwners.kt b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleMobOwners.kt index 765bc4e62d5..cb19f1df1c9 100644 --- a/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleMobOwners.kt +++ b/src/main/kotlin/net/ccbluex/liquidbounce/features/module/modules/render/ModuleMobOwners.kt @@ -18,11 +18,8 @@ */ package net.ccbluex.liquidbounce.features.module.modules.render -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import net.ccbluex.liquidbounce.api.core.HttpClient -import net.ccbluex.liquidbounce.api.core.HttpMethod -import net.ccbluex.liquidbounce.api.core.parse +import net.ccbluex.liquidbounce.api.core.withScope +import net.ccbluex.liquidbounce.api.thirdparty.MojangApi import net.ccbluex.liquidbounce.features.module.Category import net.ccbluex.liquidbounce.features.module.ClientModule import net.minecraft.entity.Entity @@ -32,7 +29,6 @@ import net.minecraft.entity.projectile.ProjectileEntity import net.minecraft.text.OrderedText import net.minecraft.text.Style import net.minecraft.util.Formatting -import net.minecraft.util.Util import java.util.* import java.util.concurrent.ConcurrentHashMap @@ -67,31 +63,31 @@ object ModuleMobOwners : ClientModule("MobOwners", Category.RENDER) { @Suppress("SwallowedException") private fun getFromMojangApi(ownerId: UUID): OrderedText { - return uuidNameCache.computeIfAbsent(ownerId) { - Util.getDownloadWorkerExecutor().execute { + return uuidNameCache.computeIfAbsent(ownerId) { uuid -> + val loadingText = OrderedText.styledForwardsVisitedString("Loading", Style.EMPTY.withItalic(true)) + uuidNameCache[uuid] = loadingText + + withScope { try { - val uuidAsString = it.toString().replace("-", "") - val url = "https://api.mojang.com/user/profiles/$uuidAsString/names" - val response = runBlocking(Dispatchers.IO) { - HttpClient.request(url, HttpMethod.GET).parse>() - } + val uuidAsString = uuid.toString().replace("-", "") + val response = MojangApi.getNames(uuidAsString) val entityName = response.first { it.changedToAt == null }.name - uuidNameCache[it] = OrderedText.styledForwardsVisitedString(entityName, Style.EMPTY) + uuidNameCache[uuid] = OrderedText.styledForwardsVisitedString(entityName, Style.EMPTY) } catch (_: InterruptedException) { } catch (e: Exception) { - uuidNameCache[it] = OrderedText.styledForwardsVisitedString( + uuidNameCache[uuid] = OrderedText.styledForwardsVisitedString( "Failed to query Mojang API", Style.EMPTY.withItalic(true).withColor(Formatting.RED) ) } } - OrderedText.styledForwardsVisitedString("Loading", Style.EMPTY.withItalic(true)) + loadingText } } - private data class UsernameRecord(val name: String, val changedToAt: Int?) + }