Skip to content

Commit

Permalink
feat: add MojangUtil.queueUsernameForUUID
Browse files Browse the repository at this point in the history
  • Loading branch information
My-Name-Is-Jeff committed Feb 9, 2024
1 parent 5a01a54 commit 1c6a3f3
Showing 1 changed file with 68 additions and 0 deletions.
68 changes: 68 additions & 0 deletions src/main/kotlin/gg/skytils/skytilsmod/utils/MojangUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ package gg.skytils.skytilsmod.utils

import gg.essential.lib.caffeine.cache.Cache
import gg.essential.lib.caffeine.cache.Caffeine
import gg.skytils.skytilsmod.Skytils
import gg.skytils.skytilsmod.Skytils.Companion.client
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import net.minecraft.client.entity.EntityOtherPlayerMP
import net.minecraftforge.common.MinecraftForge
Expand All @@ -34,6 +38,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.util.*
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import kotlin.collections.ArrayDeque
import kotlin.concurrent.fixedRateTimer


Expand All @@ -42,6 +47,9 @@ object MojangUtil {
private val usernameToUuid: Cache<String, UUID>
private val requestCount = AtomicInteger()

private val usernameQueue = MutableSharedFlow<Pair<String, Long>>()
private val uuidFlow = MutableSharedFlow<Pair<String, UUID?>>()

init {
Caffeine.newBuilder()
.weakKeys()
Expand All @@ -65,6 +73,13 @@ object MojangUtil {
}
}

suspend fun queueUsernameForUUID(name: String): UUID? {
val username = name.lowercase()
usernameQueue.emit(username to System.currentTimeMillis())

return uuidFlow.first { it.first == username }.second
}

suspend fun getUUIDFromUsername(name: String): UUID? {
val username = name.lowercase()
return usernameToUuid.getIfPresent(username) ?: run {
Expand All @@ -84,6 +99,46 @@ object MojangUtil {
}
}

suspend fun getUUIDsFromUsernames(names: Collection<String>): Map<String, UUID?> {
if (requestCount.incrementAndGet() % 6 == 0) {
client.get("https://api.minecraftservices.com/minecraft/profile/lookup/name/SlashSlayer?ts=${System.currentTimeMillis()}")
requestCount.getAndIncrement()
}
val usernames = names.mapTo(hashSetOf()) { it.lowercase() }
val map = HashMap<String, UUID?>()
map.putAll(usernameToUuid.getAllPresent(usernames))

usernames.removeAll(map.keys)

usernames.windowed(10).forEach {
client.post("https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname") {
contentType(ContentType.Application.Json)
setBody(it)
}.let {
when (it.status) {
HttpStatusCode.OK -> {
val response = it.body<List<ProfileResponse>>()
for (profile in response) {
val username = profile.name.lowercase()
val uuid = profile.id
map[username] = uuid
usernameToUuid[username] = uuid
uuidToUsername[uuid] = username
}
}

else -> throw it.body<MojangException>()
}
}
}

names.forEach {
map.getOrPut(it) { null }
}

return map
}

suspend fun getUsernameFromUUID(uuid: UUID): String? {
return uuidToUsername.getIfPresent(uuid) ?: run {
makeMojangRequest("https://api.minecraftservices.com/minecraft/profile/lookup/${uuid}").let {
Expand All @@ -107,6 +162,19 @@ object MojangUtil {
fixedRateTimer("Mojang-Fake-Requests-Insert", startAt = Date((System.currentTimeMillis() / 60000) * 60000 + 48000), period = 60_000L) {
requestCount.set(0)
}

Skytils.IO.launch {
val usernames = ArrayDeque<Pair<String, Long>>(10)
usernameQueue.collect { name ->
usernames.add(name)
if (usernames.size >= 10 || usernames.isNotEmpty() && System.currentTimeMillis() - usernames.first().second >= 3000L) {
getUUIDsFromUsernames(usernames.map { it.first }).forEach {
uuidFlow.emit(it.toPair())
}
usernames.clear()
}
}
}
}

/**
Expand Down

0 comments on commit 1c6a3f3

Please sign in to comment.