@@ -8,7 +8,9 @@ package kr.toxicity.model.manager
88
99import com.github.benmanes.caffeine.cache.Caffeine
1010import com.github.benmanes.caffeine.cache.RemovalCause
11+ import com.google.gson.Gson
1112import com.google.gson.JsonParser
13+ import com.google.gson.annotations.SerializedName
1214import kr.toxicity.library.dynamicuv.*
1315import kr.toxicity.model.api.BetterModel
1416import kr.toxicity.model.api.event.CreatePlayerSkinEvent
@@ -559,6 +561,25 @@ object SkinManagerImpl : SkinManager, GlobalManager {
559561 )
560562 )
561563 )
564+ private val CAPE = UVModel (
565+ { uvNamespace },
566+ " cape"
567+ ).addElement(
568+ UVElement (
569+ ElementVector (10f , 16f , 1f ).div(DIV_FACTOR ),
570+ ElementVector (0f , - 8f , 0.5f ).div(DIV_FACTOR ),
571+ UVSpace (10 , 16 , 1 ),
572+ UVElement .ColorType .RGB ,
573+ mapOf (
574+ UVFace .NORTH to UVPos (12 , 1 ),
575+ UVFace .SOUTH to UVPos (1 , 1 ),
576+ UVFace .EAST to UVPos (11 , 1 ),
577+ UVFace .WEST to UVPos (0 , 1 ),
578+ UVFace .UP to UVPos (1 , 0 ),
579+ UVFace .DOWN to UVPos (11 , 0 )
580+ )
581+ )
582+ )
562583
563584 private fun UVModel.asItem (image : BufferedImage ): TransformedItemStack {
564585 val data = write(image)
@@ -597,10 +618,13 @@ object SkinManagerImpl : SkinManager, GlobalManager {
597618 SLIM_LEFT_FOREARM .write()
598619 SLIM_RIGHT_ARM .write()
599620 SLIM_RIGHT_FOREARM .write()
621+ CAPE .write()
600622
601623 block(UVByteBuilder .emptyImage(uvNamespace, " one_pixel" ))
602624 }
603625
626+ private val gson = Gson ()
627+
604628 private val profileCache = Caffeine .newBuilder()
605629 .expireAfterAccess(5 , TimeUnit .MINUTES )
606630 .removalListener<UUID , SkinDataImpl > { key, value, cause ->
@@ -612,7 +636,7 @@ object SkinManagerImpl : SkinManager, GlobalManager {
612636
613637 private val fallback by lazy {
614638 PLUGIN .getResource(" fallback_skin.png" )!! .use {
615- SkinDataImpl (false , ImageIO .read(it))
639+ SkinDataImpl (false , ImageIO .read(it), null )
616640 }
617641 }
618642
@@ -646,6 +670,21 @@ object SkinManagerImpl : SkinManager, GlobalManager {
646670 }.getOrDefault(false )
647671 }
648672
673+ private data class Skin (
674+ val textures : SkinTextures
675+ )
676+
677+ private data class SkinTextures (
678+ @SerializedName(" SKIN" ) val skin : SkinUrl ,
679+ @SerializedName(" CAPE" ) val cape : SkinUrl ?
680+ )
681+
682+ private data class SkinUrl (
683+ val url : String
684+ ) {
685+ fun toURI (): URI = URI .create(url)
686+ }
687+
649688 override fun getOrRequest (profile : SkinProfile ): SkinData {
650689 return profileCache.get(profile.id) { id ->
651690 skinProvider.provide(profile).thenApply { provided ->
@@ -655,24 +694,22 @@ object SkinManagerImpl : SkinManager, GlobalManager {
655694 }
656695 }.thenCompose { selected ->
657696 httpClient {
658- sendAsync(HttpRequest .newBuilder()
659- .uri(
660- URI .create(
661- JsonParser .parseString(String (Base64 .getDecoder().decode(selected.textures.first().value)))
662- .asJsonObject
663- .getAsJsonObject(" textures" )
664- .getAsJsonObject(" SKIN" )
665- .getAsJsonPrimitive(" url" )
666- .asString
667- ))
668- .GET ()
669- .build(),
670- HttpResponse .BodyHandlers .ofInputStream()
671- ).thenAccept {
672- it.body().use { stream ->
697+ gson.fromJson(
698+ String (Base64 .getDecoder().decode(selected.textures.first().value)),
699+ Skin ::class .java
700+ ).textures.run {
701+ fun SkinUrl.toFuture () = sendAsync(HttpRequest .newBuilder()
702+ .uri(toURI())
703+ .GET ()
704+ .build(), HttpResponse .BodyHandlers .ofInputStream())
705+ .thenComposeAsync { request ->
706+ CompletableFuture .supplyAsync { request.body().use { ImageIO .read(it) } }
707+ }
708+ skin.toFuture().thenCombine(cape?.toFuture() ? : CompletableFuture .completedFuture(null )) { skin, cape ->
673709 profileCache.put(id, SkinDataImpl (
674710 isSlim(selected),
675- ImageIO .read(stream).convertLegacy(),
711+ skin.convertLegacy(),
712+ cape,
676713 selected
677714 ))
678715 BetterModel .registryOrNull(id)?.trackers()?.forEach { tracker ->
@@ -730,22 +767,24 @@ object SkinManagerImpl : SkinManager, GlobalManager {
730767
731768 private class SkinDataImpl (
732769 private val isSlim : Boolean ,
733- private val image : BufferedImage ,
770+ private val skinImage : BufferedImage ,
771+ private val capeImage : BufferedImage ? ,
734772 val original : SkinProfile ? = null
735773 ) : SkinData {
736774
737- private val head = HEAD .asItem(image)
738- private val hip = HIP .asItem(image)
739- private val waist = WAIST .asItem(image)
740- private val chest = CHEST .asItem(image)
741- private val leftArm = (if (isSlim) SLIM_LEFT_ARM else LEFT_ARM ).asItem(image)
742- private val leftForeArm = (if (isSlim) SLIM_LEFT_FOREARM else LEFT_FOREARM ).asItem(image)
743- private val rightArm = (if (isSlim) SLIM_RIGHT_ARM else RIGHT_ARM ).asItem(image)
744- private val rightForeArm = (if (isSlim) SLIM_RIGHT_FOREARM else RIGHT_FOREARM ).asItem(image)
745- private val leftLeg = LEFT_LEG .asItem(image)
746- private val leftForeLeg = LEFT_FORELEG .asItem(image)
747- private val rightLeg = RIGHT_LEG .asItem(image)
748- private val rightForeLeg = RIGHT_FORELEG .asItem(image)
775+ private val head = HEAD .asItem(skinImage)
776+ private val hip = HIP .asItem(skinImage)
777+ private val waist = WAIST .asItem(skinImage)
778+ private val chest = CHEST .asItem(skinImage)
779+ private val leftArm = (if (isSlim) SLIM_LEFT_ARM else LEFT_ARM ).asItem(skinImage)
780+ private val leftForeArm = (if (isSlim) SLIM_LEFT_FOREARM else LEFT_FOREARM ).asItem(skinImage)
781+ private val rightArm = (if (isSlim) SLIM_RIGHT_ARM else RIGHT_ARM ).asItem(skinImage)
782+ private val rightForeArm = (if (isSlim) SLIM_RIGHT_FOREARM else RIGHT_FOREARM ).asItem(skinImage)
783+ private val leftLeg = LEFT_LEG .asItem(skinImage)
784+ private val leftForeLeg = LEFT_FORELEG .asItem(skinImage)
785+ private val rightLeg = RIGHT_LEG .asItem(skinImage)
786+ private val rightForeLeg = RIGHT_FORELEG .asItem(skinImage)
787+ private val cape = capeImage?.let { CAPE .asItem(it) }
749788
750789 override fun head (): TransformedItemStack = head
751790 override fun hip (): TransformedItemStack = hip
@@ -759,8 +798,9 @@ object SkinManagerImpl : SkinManager, GlobalManager {
759798 override fun leftForeLeg (): TransformedItemStack = leftForeLeg
760799 override fun rightLeg (): TransformedItemStack = rightLeg
761800 override fun rightForeLeg (): TransformedItemStack = rightForeLeg
801+ override fun cape (): TransformedItemStack ? = cape
762802
763- fun refresh () = SkinDataImpl (isSlim, image , original)
803+ fun refresh () = SkinDataImpl (isSlim, skinImage, capeImage , original)
764804 }
765805
766806 override fun reload (pipeline : ReloadPipeline , zipper : PackZipper ) {
0 commit comments