Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 4 additions & 14 deletions src/main/kotlin/net/ccbluex/liquidbounce/api/core/HttpClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package net.ccbluex.liquidbounce.api.core

import com.mojang.blaze3d.platform.NativeImage
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
Expand All @@ -31,11 +30,10 @@ import net.ccbluex.liquidbounce.api.interceptors.DefaultHeaderInterceptor
import net.ccbluex.liquidbounce.api.thirdparty.mojang.MojangApiClient
import net.ccbluex.liquidbounce.config.gson.interopGson
import net.ccbluex.liquidbounce.config.gson.util.readJson
import net.ccbluex.liquidbounce.utils.client.error.ErrorHandler
import net.ccbluex.liquidbounce.utils.client.logger
import net.ccbluex.liquidbounce.utils.client.mc
import net.ccbluex.liquidbounce.utils.kotlin.CommonCoroutineExceptionHandler
import net.ccbluex.liquidbounce.utils.render.readNativeImage
import net.minecraft.ReportedException
import okhttp3.Cache
import okhttp3.Call
import okhttp3.Dispatcher
Expand All @@ -61,22 +59,14 @@ import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

val renderScope = CoroutineScope(
Dispatchers.Main + SupervisorJob() + CoroutineExceptionHandler { _, throwable ->
if (throwable is ReportedException) {
ErrorHandler.fatal(throwable, additionalMessage = "Render scope")
}
}
Dispatchers.Main + SupervisorJob() + CommonCoroutineExceptionHandler.Default
)

val ioScope = CoroutineScope(
Dispatchers.IO + SupervisorJob() + CoroutineExceptionHandler { _, throwable ->
if (throwable is ReportedException) {
ErrorHandler.fatal(throwable, additionalMessage = "IO scope")
}
}
Dispatchers.IO + SupervisorJob() + CommonCoroutineExceptionHandler.Default
)

fun withScope(block: suspend CoroutineScope.() -> Unit) = ioScope.launch { block() }
fun withScope(block: suspend CoroutineScope.() -> Unit) = ioScope.launch(block = block)

object HttpClient {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,21 @@
package net.ccbluex.liquidbounce.features.module.modules.render

import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.ccbluex.liquidbounce.api.core.HttpClient
import net.ccbluex.liquidbounce.api.core.withScope
import net.ccbluex.liquidbounce.event.eventListenerScope
import net.ccbluex.liquidbounce.features.module.ClientModule
import net.ccbluex.liquidbounce.features.module.ModuleCategories
import net.ccbluex.liquidbounce.utils.kotlin.toUndashedString
import net.ccbluex.liquidbounce.utils.text.withFormat
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Style
import net.minecraft.util.FormattedCharSequence
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.TamableAnimal
import net.minecraft.world.entity.animal.equine.AbstractHorse
import net.minecraft.world.entity.OwnableEntity
import net.minecraft.world.entity.projectile.Projectile
import java.util.UUID
import java.util.concurrent.ConcurrentHashMap

/**
* MobOwners module
Expand All @@ -44,52 +45,44 @@ object ModuleMobOwners : ClientModule("MobOwners", ModuleCategories.RENDER) {

private val projectiles by boolean("Projectiles", false)

private val uuidNameCache = ConcurrentHashMap<UUID, FormattedCharSequence>()
private val uuidNameCache = hashMapOf<UUID, FormattedCharSequence>()

fun getOwnerInfoText(entity: Entity?): FormattedCharSequence? {
if (entity == null || !this.running) {
return null
}

val ownerId = when (entity) {
is TamableAnimal -> entity.ownerReference?.uuid
is AbstractHorse -> entity.ownerReference?.uuid
is OwnableEntity -> entity.ownerReference?.uuid
is Projectile if projectiles -> entity.owner?.uuid
else -> null
} ?: return null

return world.getPlayerByUUID(ownerId)
?.let { FormattedCharSequence.forward(it.scoreboardName, Style.EMPTY) }
return world.getPlayerByUUID(ownerId)?.scoreboardName?.withFormat()
?: getFromMojangApi(ownerId)
}

private val LOADING_TEXT = FormattedCharSequence.forward(
"Loading...",
Style.EMPTY.withItalic(true)
)
private val LOADING_TEXT = "Loading..."
.withFormat(Style.EMPTY.withItalic(true))

private val FAILED_TEXT = FormattedCharSequence.forward(
"Failed to query Mojang API",
Style.EMPTY.withItalic(true).withColor(ChatFormatting.RED)
)
private val FAILED_TEXT = "Failed to query Mojang API"
.withFormat(Style.EMPTY.withItalic(true).withColor(ChatFormatting.RED))

private val CANCELED_TEXT = FormattedCharSequence.forward(
"Query is canceled",
Style.EMPTY.withItalic(true).withColor(ChatFormatting.YELLOW)
)
private val CANCELED_TEXT = "Query is canceled"
.withFormat(Style.EMPTY.withItalic(true).withColor(ChatFormatting.YELLOW))

@Suppress("SwallowedException")
private fun getFromMojangApi(ownerId: UUID): FormattedCharSequence {
return uuidNameCache.putIfAbsent(ownerId, LOADING_TEXT) ?: run {
// The job will still run even if the module is disabled
withScope {
eventListenerScope.launch(Dispatchers.Main) {
uuidNameCache[ownerId] = try {
val profile = HttpClient.mojangApiClient.mcServicesApi
.lookupNameByUuid(ownerId.toUndashedString())
FormattedCharSequence.forward(profile.name, Style.EMPTY)
} catch (e: CancellationException) {
profile.name.withFormat()
} catch (_: CancellationException) {
CANCELED_TEXT
} catch (e: Exception) {
} catch (_: Exception) {
FAILED_TEXT
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ import net.ccbluex.liquidbounce.event.events.PacketEvent
import net.ccbluex.liquidbounce.event.events.WorldChangeEvent
import net.ccbluex.liquidbounce.event.handler
import net.ccbluex.liquidbounce.features.module.MinecraftShortcuts
import net.ccbluex.liquidbounce.utils.client.logger
import net.ccbluex.liquidbounce.utils.client.clientLogger
import net.ccbluex.liquidbounce.utils.kotlin.CommonCoroutineExceptionHandler
import net.ccbluex.liquidbounce.utils.kotlin.EventPriorityConvention.FIRST_PRIORITY
import net.ccbluex.liquidbounce.utils.kotlin.EventPriorityConvention.READ_FINAL_STATE
import net.ccbluex.liquidbounce.utils.kotlin.joinAll
Expand All @@ -54,6 +55,8 @@ import kotlin.time.measureTime

object ChunkScanner : EventListener, MinecraftShortcuts {

private val logger = clientLogger("ChunkScanner")

private val loadedChunks = LongOpenHashSet()

private val threadLocalBlockPos = ThreadLocal.withInitial(BlockPos::MutableBlockPos)
Expand Down Expand Up @@ -146,11 +149,7 @@ object ChunkScanner : EventListener, MinecraftShortcuts {
*/
private val worldJob = SupervisorJob()

val scope = CoroutineScope(dispatcher + worldJob + CoroutineExceptionHandler { context, throwable ->
if (throwable !is CancellationException) {
logger.warn("Chunk update error", throwable)
}
})
private val scope = CoroutineScope(dispatcher + worldJob + CommonCoroutineExceptionHandler { logger })

/**
* Cancel all existing enqueue(emit) jobs and scanner jobs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

package net.ccbluex.liquidbounce.utils.kotlin

import kotlinx.coroutines.Job
import net.ccbluex.liquidbounce.utils.client.mc
import net.minecraft.server.packs.resources.PreparableReloadListener
import net.minecraft.util.Util
Expand All @@ -32,8 +31,6 @@ inline operator fun <T> ThreadLocal<T>.getValue(receiver: Any?, property: KPrope

inline operator fun <T> ThreadLocal<T>.setValue(receiver: Any?, property: KProperty<*>, value: T) = set(value)

suspend inline fun Array<out Job>.joinAll() = forEach { it.join() }

/**
* A [PreparableReloadListener] with a simplified async reload entry point.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* This file is part of LiquidBounce (https://github.com/CCBlueX/LiquidBounce)
*
* Copyright (c) 2015 - 2026 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 <https://www.gnu.org/licenses/>.
*/

package net.ccbluex.liquidbounce.utils.kotlin

import com.google.common.base.Suppliers
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Job
import net.ccbluex.liquidbounce.utils.client.error.ErrorHandler
import net.ccbluex.liquidbounce.utils.client.logger
import net.minecraft.ReportedException
import org.apache.logging.log4j.Logger
import java.util.function.Supplier
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.cancellation.CancellationException

suspend inline fun Array<out Job>.joinAll() = forEach { it.join() }

internal class CommonCoroutineExceptionHandler(
private val logger: Supplier<out Logger>,
): CoroutineExceptionHandler {
constructor(logger: Logger): this(Suppliers.ofInstance(logger))

private fun coroutineName(context: CoroutineContext) =
context[CoroutineName]?.toString() ?: context.toString()

override fun handleException(context: CoroutineContext, exception: Throwable) {
when (exception) {
is CancellationException -> return
is ReportedException -> ErrorHandler.fatal(exception, additionalMessage = coroutineName(context))
else -> logger.get().error("Unhandled exception caught for ${coroutineName(context)}", exception)
}
}

override val key: CoroutineContext.Key<*>
get() = CoroutineExceptionHandler.Key

companion object {
val Default = CommonCoroutineExceptionHandler(logger)
}
}
Loading