aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt
blob: 7b6e62b0a2f14bc09887714d265b15da84ca5a46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
@file:UseSerializers(IdentifierSerializer::class)

package moe.nea.firmament.features.texturepack

import java.util.Optional
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import kotlinx.serialization.UseSerializers
import kotlin.jvm.optionals.getOrNull
import net.minecraft.item.ArmorMaterial
import net.minecraft.item.ItemStack
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.SinglePreparationResourceReloader
import net.minecraft.util.Identifier
import net.minecraft.util.profiler.Profiler
import moe.nea.firmament.Firmament
import moe.nea.firmament.annotations.Subscribe
import moe.nea.firmament.events.FinalizeResourceManagerEvent
import moe.nea.firmament.events.subscription.SubscriptionOwner
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger
import moe.nea.firmament.util.IdentifierSerializer
import moe.nea.firmament.util.collections.WeakCache
import moe.nea.firmament.util.skyBlockId

object CustomGlobalArmorOverrides : SubscriptionOwner {
    @Serializable
    data class ArmorOverride(
        @SerialName("item_ids")
        val itemIds: List<String>,
        val layers: List<ArmorOverrideLayer>,
        val overrides: List<ArmorOverrideOverride> = listOf(),
    ) {
        @Transient
        val bakedLayers = bakeLayers(layers)
    }

    fun bakeLayers(layers: List<ArmorOverrideLayer>): List<ArmorMaterial.Layer> {
        return layers.map { ArmorMaterial.Layer(it.identifier, it.suffix, it.tint) }
    }

    @Serializable
    data class ArmorOverrideLayer(
        val tint: Boolean = false,
        val identifier: Identifier,
        val suffix: String = "",
    )

    @Serializable
    data class ArmorOverrideOverride(
        val predicate: FirmamentModelPredicate,
        val layers: List<ArmorOverrideLayer>,
    ) {
        @Transient
        val bakedLayers = bakeLayers(layers)
    }

    override val delegateFeature: FirmamentFeature
        get() = CustomSkyBlockTextures

    val overrideCache = WeakCache.memoize<ItemStack, Optional<List<ArmorMaterial.Layer>>>("ArmorOverrides") { stack ->
        val id = stack.skyBlockId ?: return@memoize Optional.empty()
        val override = overrides[id.neuItem] ?: return@memoize Optional.empty()
        for (suboverride in override.overrides) {
            if (suboverride.predicate.test(stack)) {
                return@memoize Optional.of(suboverride.bakedLayers)
            }
        }
        return@memoize Optional.of(override.bakedLayers)
    }

    @JvmStatic
    fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? {
        if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null
        return overrideCache.invoke(stack).getOrNull()
    }

    var overrides: Map<String, ArmorOverride> = mapOf()

    @Subscribe
    fun onStart(event: FinalizeResourceManagerEvent) {
        event.resourceManager.registerReloader(object :
                                                   SinglePreparationResourceReloader<Map<String, ArmorOverride>>() {
            override fun prepare(manager: ResourceManager, profiler: Profiler): Map<String, ArmorOverride> {
                val overrideFiles = manager.findResources("overrides/armor_models") {
                    it.namespace == "firmskyblock" && it.path.endsWith(".json")
                }
                val overrides = overrideFiles.mapNotNull {
                    Firmament.tryDecodeJsonFromStream<ArmorOverride>(it.value.inputStream).getOrElse { ex ->
                        logger.error("Failed to load armor texture override at ${it.key}", ex)
                        null
                    }
                }
                val associatedMap = overrides.flatMap { obj -> obj.itemIds.map { it to obj } }
                    .toMap()
                return associatedMap
            }

            override fun apply(prepared: Map<String, ArmorOverride>, manager: ResourceManager, profiler: Profiler) {
                overrides = prepared
            }
        })
    }

}