Skip to content

Commit bb3f189

Browse files
committed
Merge branch 'main' of https://github.com/Polyfrost/PolyPlus into refactor/clean-up
2 parents 0fb94e6 + 30ef556 commit bb3f189

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package org.polyfrost.polyplus.network.plus.cache
2+
3+
import net.minecraft.client.renderer.texture.DynamicTexture
4+
import net.minecraft.util.ResourceLocation
5+
import org.polyfrost.oneconfig.utils.v1.dsl.mc
6+
import java.awt.image.BufferedImage
7+
8+
sealed class CachedCosmetic {
9+
class Cape(image: BufferedImage) : CachedCosmetic() {
10+
val resource: ResourceLocation? = mc.textureManager.getDynamicTextureLocation("polyplus/cape", DynamicTexture(image))
11+
}
12+
object InvalidType : CachedCosmetic()
13+
14+
fun asResource(): ResourceLocation? {
15+
return when (this) {
16+
is Cape -> resource
17+
is InvalidType -> null
18+
}
19+
}
20+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.polyfrost.polyplus.network.plus.cache
2+
3+
import io.ktor.client.request.get
4+
import io.ktor.client.statement.bodyAsBytes
5+
import kotlinx.coroutines.CompletableDeferred
6+
import kotlinx.coroutines.Deferred
7+
import kotlinx.coroutines.Dispatchers
8+
import kotlinx.coroutines.async
9+
import kotlinx.coroutines.launch
10+
import kotlinx.coroutines.withContext
11+
import net.minecraft.util.ResourceLocation
12+
import org.polyfrost.oneconfig.utils.v1.dsl.mc
13+
import org.polyfrost.polyplus.PolyPlus
14+
import org.polyfrost.polyplus.network.plus.Cosmetics.players
15+
import org.polyfrost.polyplus.network.plus.cache.CachedCosmetic
16+
import org.polyfrost.polyplus.network.plus.responses.Cosmetic
17+
import org.polyfrost.polyplus.utils.HashManager
18+
import java.io.File
19+
import java.io.FileOutputStream
20+
import java.util.UUID
21+
import javax.imageio.ImageIO
22+
import kotlin.uuid.Uuid
23+
24+
object CosmeticCache {
25+
val cache = HashMap<String, HashMap<Int, CachedCosmetic>>()
26+
val hashManager = HashManager("${DIRECTORY}hashes.txt")
27+
const val DIRECTORY = "./polyplus/cosmetics/"
28+
29+
suspend fun put(cosmetics: List<Cosmetic>) = withContext(Dispatchers.IO) {
30+
hashManager.awaitHashes()
31+
try {
32+
val directory = File(DIRECTORY)
33+
if (!directory.exists()) directory.mkdirs()
34+
for (cosmetic in cosmetics) {
35+
val cosmeticName = "${cosmetic.type}_${cosmetic.id}"
36+
val file = File("${DIRECTORY}$cosmeticName")
37+
38+
val cached = !hashManager.updateHash(cosmeticName, cosmetic.hash) && !file.createNewFile()
39+
40+
val cosmeticStream = if (cached) file.inputStream() else {
41+
val bytes = PolyPlus.client.get(cosmetic.url).bodyAsBytes()
42+
val outputStream = FileOutputStream(file)
43+
bytes.inputStream().use { input ->
44+
outputStream.use { output ->
45+
input.copyTo(output)
46+
}
47+
}
48+
49+
bytes.inputStream()
50+
}
51+
52+
mc.addScheduledTask { // we need a thread with opengl context to create textures
53+
cache.getOrPut(cosmetic.type) { HashMap() }[cosmetic.id] = when (cosmetic.type) {
54+
"cape" -> CachedCosmetic.Cape(ImageIO.read(cosmeticStream))
55+
else -> CachedCosmetic.InvalidType
56+
}
57+
}
58+
}
59+
hashManager.saveHashes()
60+
} catch (e: Exception) {
61+
PolyPlus.logger.warning("Failed to cache cosmetics: ${e.message}")
62+
}
63+
}
64+
65+
@JvmStatic
66+
fun getCosmetic(Uuid: UUID, type: String): ResourceLocation? {
67+
val id = players[Uuid]?.get(type) ?: return null
68+
return cache[type]?.get(id)?.asResource().also { if (it == null) println("no cached cosmetic with type $type for id $id") }
69+
}
70+
71+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.polyfrost.polyplus.network.plus.responses
2+
3+
import kotlinx.serialization.ExperimentalSerializationApi
4+
import kotlinx.serialization.SerialName
5+
import kotlinx.serialization.Serializable
6+
import kotlinx.serialization.json.JsonClassDiscriminator
7+
8+
@OptIn(ExperimentalSerializationApi::class)
9+
object WebSocketPacket {
10+
object ClientBound {
11+
@Serializable
12+
@JsonClassDiscriminator("type")
13+
sealed class FallibleResponse {
14+
@Serializable
15+
@SerialName("Error")
16+
data class Error(
17+
@SerialName("error_code") val code: String,
18+
@SerialName("message") val message: String
19+
) : FallibleResponse()
20+
21+
@Serializable
22+
@SerialName("CosmeticsInfo")
23+
data class CosmeticsInfo(
24+
@SerialName("cosmetics") val cosmetics: HashMap<String, List<Int>>
25+
) : FallibleResponse()
26+
}
27+
}
28+
29+
object ServerBound {
30+
@Serializable
31+
@JsonClassDiscriminator("type")
32+
sealed class Packet {
33+
@Serializable
34+
@SerialName("GetActiveCosmetics")
35+
data class GetActiveCosmetics(
36+
@SerialName("players") val players: List<String>
37+
) : Packet()
38+
}
39+
}
40+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.polyfrost.polyplus.utils
2+
3+
import dev.deftu.omnicore.api.client.client
4+
import java.util.UUID
5+
6+
object PlayerUtils {
7+
//#if MC >= 1.20.4
8+
//$$ val uuid: UUID = client.uuid
9+
//#else
10+
val uuid: UUID = client.session.profile.id
11+
//#endif
12+
13+
14+
}

0 commit comments

Comments
 (0)