aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin/moe/nea/firmament/features/texturepack
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-08-28 19:04:24 +0200
committerLinnea Gräf <nea@nea.moe>2024-08-28 19:04:24 +0200
commitd2f240ff0ca0d27f417f837e706c781a98c31311 (patch)
tree0db7aff6cc14deaf36eed83889d59fd6b3a6f599 /src/main/kotlin/moe/nea/firmament/features/texturepack
parenta6906308163aa3b2d18fa1dc1aa71ac9bbcc83ab (diff)
downloadfirmament-d2f240ff0ca0d27f417f837e706c781a98c31311.tar.gz
firmament-d2f240ff0ca0d27f417f837e706c781a98c31311.tar.bz2
firmament-d2f240ff0ca0d27f417f837e706c781a98c31311.zip
Refactor source layout
Introduce compat source sets and move all kotlin sources to the main directory [no changelog]
Diffstat (limited to 'src/main/kotlin/moe/nea/firmament/features/texturepack')
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt17
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt26
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt9
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt8
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt296
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt106
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt167
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt74
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt114
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt22
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt268
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt8
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt8
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt32
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt10
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt19
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt7
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt19
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt18
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt125
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt26
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt66
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt69
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt159
24 files changed, 0 insertions, 1673 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt
deleted file mode 100644
index 4dd28df..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/AlwaysPredicate.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import net.minecraft.item.ItemStack
-
-object AlwaysPredicate : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- return true
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate {
- return AlwaysPredicate
- }
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt
deleted file mode 100644
index 55a4f32..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonArray
-import com.google.gson.JsonElement
-import com.google.gson.JsonObject
-import net.minecraft.item.ItemStack
-
-class AndPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- return children.all { it.test(stack) }
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate {
- val children =
- (jsonElement as JsonArray)
- .flatMap {
- CustomModelOverrideParser.parsePredicates(it as JsonObject)
- }
- .toTypedArray()
- return AndPredicate(children)
- }
-
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt
deleted file mode 100644
index ae1f6d5..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedModelExtra.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import net.minecraft.client.render.model.BakedModel
-
-interface BakedModelExtra {
- fun getHeadModel_firmament(): BakedModel?
- fun setHeadModel_firmament(headModel: BakedModel?)
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt
deleted file mode 100644
index c012883..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-interface BakedOverrideData {
- fun getFirmamentOverrides(): Array<FirmamentModelPredicate>?
- fun setFirmamentOverrides(overrides: Array<FirmamentModelPredicate>?)
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
deleted file mode 100644
index 18da54c..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomBlockTextures.kt
+++ /dev/null
@@ -1,296 +0,0 @@
-@file:UseSerializers(BlockPosSerializer::class, IdentifierSerializer::class)
-
-package moe.nea.firmament.features.texturepack
-
-import java.util.concurrent.CompletableFuture
-import net.fabricmc.loader.api.FabricLoader
-import kotlinx.serialization.ExperimentalSerializationApi
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.Transient
-import kotlinx.serialization.UseSerializers
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.json.JsonDecoder
-import kotlinx.serialization.json.JsonElement
-import kotlinx.serialization.json.JsonPrimitive
-import kotlinx.serialization.serializer
-import kotlin.jvm.optionals.getOrNull
-import net.minecraft.block.Block
-import net.minecraft.block.BlockState
-import net.minecraft.client.render.model.BakedModel
-import net.minecraft.client.util.ModelIdentifier
-import net.minecraft.registry.RegistryKey
-import net.minecraft.registry.RegistryKeys
-import net.minecraft.resource.ResourceManager
-import net.minecraft.resource.SinglePreparationResourceReloader
-import net.minecraft.util.Identifier
-import net.minecraft.util.math.BlockPos
-import net.minecraft.util.profiler.Profiler
-import moe.nea.firmament.Firmament
-import moe.nea.firmament.annotations.Subscribe
-import moe.nea.firmament.compat.SodiumChunkReloader
-import moe.nea.firmament.events.BakeExtraModelsEvent
-import moe.nea.firmament.events.EarlyResourceReloadEvent
-import moe.nea.firmament.events.FinalizeResourceManagerEvent
-import moe.nea.firmament.events.SkyblockServerUpdateEvent
-import moe.nea.firmament.features.texturepack.CustomGlobalTextures.logger
-import moe.nea.firmament.util.IdentifierSerializer
-import moe.nea.firmament.util.MC
-import moe.nea.firmament.util.SBData
-import moe.nea.firmament.util.SkyBlockIsland
-import moe.nea.firmament.util.json.BlockPosSerializer
-import moe.nea.firmament.util.json.SingletonSerializableList
-
-
-object CustomBlockTextures {
- @Serializable
- data class CustomBlockOverride(
- val modes: @Serializable(SingletonSerializableList::class) List<String>,
- val area: List<Area>? = null,
- val replacements: Map<Identifier, Replacement>,
- )
-
- @Serializable(with = Replacement.Serializer::class)
- data class Replacement(
- val block: Identifier,
- val sound: Identifier?,
- ) {
-
- @Transient
- val blockModelIdentifier get() = ModelIdentifier(block.withPrefixedPath("block/"), "firmament")
-
- @Transient
- val bakedModel: BakedModel by lazy(LazyThreadSafetyMode.NONE) {
- MC.instance.bakedModelManager.getModel(blockModelIdentifier)
- }
-
- @OptIn(ExperimentalSerializationApi::class)
- @kotlinx.serialization.Serializer(Replacement::class)
- object DefaultSerializer : KSerializer<Replacement>
-
- object Serializer : KSerializer<Replacement> {
- val delegate = serializer<JsonElement>()
- override val descriptor: SerialDescriptor
- get() = delegate.descriptor
-
- override fun deserialize(decoder: Decoder): Replacement {
- val jsonElement = decoder.decodeSerializableValue(delegate)
- if (jsonElement is JsonPrimitive) {
- require(jsonElement.isString)
- return Replacement(Identifier.tryParse(jsonElement.content)!!, null)
- }
- return (decoder as JsonDecoder).json.decodeFromJsonElement(DefaultSerializer, jsonElement)
- }
-
- override fun serialize(encoder: Encoder, value: Replacement) {
- encoder.encodeSerializableValue(DefaultSerializer, value)
- }
- }
- }
-
- @Serializable
- data class Area(
- val min: BlockPos,
- val max: BlockPos,
- ) {
- @Transient
- val realMin = BlockPos(
- minOf(min.x, max.x),
- minOf(min.y, max.y),
- minOf(min.z, max.z),
- )
-
- @Transient
- val realMax = BlockPos(
- maxOf(min.x, max.x),
- maxOf(min.y, max.y),
- maxOf(min.z, max.z),
- )
-
- fun roughJoin(other: Area): Area {
- return Area(
- BlockPos(
- minOf(realMin.x, other.realMin.x),
- minOf(realMin.y, other.realMin.y),
- minOf(realMin.z, other.realMin.z),
- ),
- BlockPos(
- maxOf(realMax.x, other.realMax.x),
- maxOf(realMax.y, other.realMax.y),
- maxOf(realMax.z, other.realMax.z),
- )
- )
- }
-
- fun contains(blockPos: BlockPos): Boolean {
- return (blockPos.x in realMin.x..realMax.x) &&
- (blockPos.y in realMin.y..realMax.y) &&
- (blockPos.z in realMin.z..realMax.z)
- }
- }
-
- data class LocationReplacements(
- val lookup: Map<Block, List<BlockReplacement>>
- )
-
- data class BlockReplacement(
- val checks: List<Area>?,
- val replacement: Replacement,
- ) {
- val roughCheck by lazy(LazyThreadSafetyMode.NONE) {
- if (checks == null || checks.size < 3) return@lazy null
- checks.reduce { acc, next -> acc.roughJoin(next) }
- }
- }
-
- data class BakedReplacements(val data: Map<SkyBlockIsland, LocationReplacements>)
-
- var allLocationReplacements: BakedReplacements = BakedReplacements(mapOf())
- var currentIslandReplacements: LocationReplacements? = null
-
- fun refreshReplacements() {
- val location = SBData.skyblockLocation
- val replacements =
- if (CustomSkyBlockTextures.TConfig.enableBlockOverrides) location?.let(allLocationReplacements.data::get)
- else null
- val lastReplacements = currentIslandReplacements
- currentIslandReplacements = replacements
- if (lastReplacements != replacements) {
- MC.nextTick {
- MC.worldRenderer.chunks?.chunks?.forEach {
- // false schedules rebuilds outside a 27 block radius to happen async
- it.scheduleRebuild(false)
- }
- sodiumReloadTask?.run()
- }
- }
- }
-
- private val sodiumReloadTask = runCatching {
- SodiumChunkReloader()
- }.getOrElse {
- if (FabricLoader.getInstance().isModLoaded("sodium"))
- logger.error("Could not create sodium chunk reloader")
- null
- }
-
-
- fun matchesPosition(replacement: BlockReplacement, blockPos: BlockPos?): Boolean {
- if (blockPos == null) return true
- val rc = replacement.roughCheck
- if (rc != null && !rc.contains(blockPos)) return false
- val areas = replacement.checks
- if (areas != null && !areas.any { it.contains(blockPos) }) return false
- return true
- }
-
- @JvmStatic
- fun getReplacementModel(block: BlockState, blockPos: BlockPos?): BakedModel? {
- return getReplacement(block, blockPos)?.bakedModel
- }
-
- @JvmStatic
- fun getReplacement(block: BlockState, blockPos: BlockPos?): Replacement? {
- if (isInFallback() && blockPos == null) return null
- val replacements = currentIslandReplacements?.lookup?.get(block.block) ?: return null
- for (replacement in replacements) {
- if (replacement.checks == null || matchesPosition(replacement, blockPos))
- return replacement.replacement
- }
- return null
- }
-
-
- @Subscribe
- fun onLocation(event: SkyblockServerUpdateEvent) {
- refreshReplacements()
- }
-
- @Volatile
- var preparationFuture: CompletableFuture<BakedReplacements> = CompletableFuture.completedFuture(BakedReplacements(
- mapOf()))
-
- val insideFallbackCall = ThreadLocal.withInitial { 0 }
-
- @JvmStatic
- fun enterFallbackCall() {
- insideFallbackCall.set(insideFallbackCall.get() + 1)
- }
-
- fun isInFallback() = insideFallbackCall.get() > 0
-
- @JvmStatic
- fun exitFallbackCall() {
- insideFallbackCall.set(insideFallbackCall.get() - 1)
- }
-
- @Subscribe
- fun onEarlyReload(event: EarlyResourceReloadEvent) {
- preparationFuture = CompletableFuture
- .supplyAsync(
- { prepare(event.resourceManager) }, event.preparationExecutor)
- }
-
- @Subscribe
- fun bakeExtraModels(event: BakeExtraModelsEvent) {
- preparationFuture.join().data.values
- .flatMap { it.lookup.values }
- .flatten()
- .mapTo(mutableSetOf()) { it.replacement.blockModelIdentifier }
- .forEach { event.addNonItemModel(it) }
- }
-
- private fun prepare(manager: ResourceManager): BakedReplacements {
- val resources = manager.findResources("overrides/blocks") {
- it.namespace == "firmskyblock" && it.path.endsWith(".json")
- }
- val map = mutableMapOf<SkyBlockIsland, MutableMap<Block, MutableList<BlockReplacement>>>()
- for ((file, resource) in resources) {
- val json =
- Firmament.tryDecodeJsonFromStream<CustomBlockOverride>(resource.inputStream)
- .getOrElse { ex ->
- logger.error("Failed to load block texture override at $file", ex)
- continue
- }
- for (mode in json.modes) {
- val island = SkyBlockIsland.forMode(mode)
- val islandMpa = map.getOrPut(island, ::mutableMapOf)
- for ((blockId, replacement) in json.replacements) {
- val block = MC.defaultRegistries.getWrapperOrThrow(RegistryKeys.BLOCK)
- .getOptional(RegistryKey.of(RegistryKeys.BLOCK, blockId))
- .getOrNull()
- if (block == null) {
- logger.error("Failed to load block texture override at ${file}: unknown block '$blockId'")
- continue
- }
- val replacements = islandMpa.getOrPut(block.value(), ::mutableListOf)
- replacements.add(BlockReplacement(json.area, replacement))
- }
- }
- }
-
- return BakedReplacements(map.mapValues { LocationReplacements(it.value) })
- }
-
- @JvmStatic
- fun patchIndigo(orig: BakedModel, pos: BlockPos, state: BlockState): BakedModel {
- return getReplacementModel(state, pos) ?: orig
- }
-
- @Subscribe
- fun onStart(event: FinalizeResourceManagerEvent) {
- event.resourceManager.registerReloader(object :
- SinglePreparationResourceReloader<BakedReplacements>() {
- override fun prepare(manager: ResourceManager, profiler: Profiler): BakedReplacements {
- return preparationFuture.join()
- }
-
- override fun apply(prepared: BakedReplacements, manager: ResourceManager, profiler: Profiler?) {
- allLocationReplacements = prepared
- refreshReplacements()
- }
- })
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt
deleted file mode 100644
index 23577ee..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalArmorOverrides.kt
+++ /dev/null
@@ -1,106 +0,0 @@
-
-@file:UseSerializers(IdentifierSerializer::class)
-
-package moe.nea.firmament.features.texturepack
-
-import kotlinx.serialization.SerialName
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.Transient
-import kotlinx.serialization.UseSerializers
-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.IdentityCharacteristics
-import moe.nea.firmament.util.computeNullableFunction
-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 = mutableMapOf<IdentityCharacteristics<ItemStack>, Any>()
-
- @JvmStatic
- fun overrideArmor(stack: ItemStack): List<ArmorMaterial.Layer>? {
- if (!CustomSkyBlockTextures.TConfig.enableArmorOverrides) return null
- return overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) {
- val id = stack.skyBlockId ?: return@computeNullableFunction null
- val override = overrides[id.neuItem] ?: return@computeNullableFunction null
- for (suboverride in override.overrides) {
- if (suboverride.predicate.test(stack)) {
- return@computeNullableFunction suboverride.bakedLayers
- }
- }
- return@computeNullableFunction override.bakedLayers
- }
- }
-
- 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
- }
- })
- }
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt
deleted file mode 100644
index d64c844..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomGlobalTextures.kt
+++ /dev/null
@@ -1,167 +0,0 @@
-
-@file:UseSerializers(IdentifierSerializer::class, CustomModelOverrideParser.FirmamentRootPredicateSerializer::class)
-
-package moe.nea.firmament.features.texturepack
-
-
-import java.util.concurrent.CompletableFuture
-import org.slf4j.LoggerFactory
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.UseSerializers
-import kotlin.jvm.optionals.getOrNull
-import net.minecraft.client.render.item.ItemModels
-import net.minecraft.client.render.model.BakedModel
-import net.minecraft.client.util.ModelIdentifier
-import net.minecraft.item.ItemStack
-import net.minecraft.resource.ResourceManager
-import net.minecraft.resource.SinglePreparationResourceReloader
-import net.minecraft.text.Text
-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.BakeExtraModelsEvent
-import moe.nea.firmament.events.EarlyResourceReloadEvent
-import moe.nea.firmament.events.FinalizeResourceManagerEvent
-import moe.nea.firmament.events.ScreenChangeEvent
-import moe.nea.firmament.events.subscription.SubscriptionOwner
-import moe.nea.firmament.features.FirmamentFeature
-import moe.nea.firmament.util.IdentifierSerializer
-import moe.nea.firmament.util.IdentityCharacteristics
-import moe.nea.firmament.util.MC
-import moe.nea.firmament.util.computeNullableFunction
-import moe.nea.firmament.util.json.SingletonSerializableList
-import moe.nea.firmament.util.runNull
-
-object CustomGlobalTextures : SinglePreparationResourceReloader<CustomGlobalTextures.CustomGuiTextureOverride>(),
- SubscriptionOwner {
- override val delegateFeature: FirmamentFeature
- get() = CustomSkyBlockTextures
-
- class CustomGuiTextureOverride(
- val classes: List<ItemOverrideCollection>
- )
-
- @Serializable
- data class GlobalItemOverride(
- val screen: @Serializable(SingletonSerializableList::class) List<Identifier>,
- val model: Identifier,
- val predicate: FirmamentModelPredicate,
- )
-
- @Serializable
- data class ScreenFilter(
- val title: StringMatcher,
- )
-
- data class ItemOverrideCollection(
- val screenFilter: ScreenFilter,
- val overrides: List<GlobalItemOverride>,
- )
-
- @Subscribe
- fun onStart(event: FinalizeResourceManagerEvent) {
- MC.resourceManager.registerReloader(this)
- }
-
- @Subscribe
- fun onEarlyReload(event: EarlyResourceReloadEvent) {
- preparationFuture = CompletableFuture
- .supplyAsync(
- {
- prepare(event.resourceManager)
- }, event.preparationExecutor)
- }
-
- @Subscribe
- fun onBakeModels(event: BakeExtraModelsEvent) {
- for (guiClassOverride in preparationFuture.join().classes) {
- for (override in guiClassOverride.overrides) {
- event.addItemModel(ModelIdentifier(override.model, "inventory"))
- }
- }
- }
-
- @Volatile
- var preparationFuture: CompletableFuture<CustomGuiTextureOverride> = CompletableFuture.completedFuture(
- CustomGuiTextureOverride(listOf()))
-
- override fun prepare(manager: ResourceManager?, profiler: Profiler?): CustomGuiTextureOverride {
- return preparationFuture.join()
- }
-
- override fun apply(prepared: CustomGuiTextureOverride, manager: ResourceManager?, profiler: Profiler?) {
- this.guiClassOverrides = prepared
- }
-
- val logger = LoggerFactory.getLogger(CustomGlobalTextures::class.java)
- fun prepare(manager: ResourceManager): CustomGuiTextureOverride {
- val overrideResources =
- manager.findResources("overrides/item") { it.namespace == "firmskyblock" && it.path.endsWith(".json") }
- .mapNotNull {
- Firmament.tryDecodeJsonFromStream<GlobalItemOverride>(it.value.inputStream).getOrElse { ex ->
- logger.error("Failed to load global item override at ${it.key}", ex)
- null
- }
- }
-
- val byGuiClass = overrideResources.flatMap { override -> override.screen.toSet().map { it to override } }
- .groupBy { it.first }
- val guiClasses = byGuiClass.entries
- .mapNotNull {
- val key = it.key
- val guiClassResource =
- manager.getResource(Identifier.of(key.namespace, "filters/screen/${key.path}.json"))
- .getOrNull()
- ?: return@mapNotNull runNull {
- logger.error("Failed to locate screen filter at $key")
- }
- val screenFilter =
- Firmament.tryDecodeJsonFromStream<ScreenFilter>(guiClassResource.inputStream)
- .getOrElse { ex ->
- logger.error("Failed to load screen filter at $key", ex)
- return@mapNotNull null
- }
- ItemOverrideCollection(screenFilter, it.value.map { it.second })
- }
- logger.info("Loaded ${overrideResources.size} global item overrides")
- return CustomGuiTextureOverride(guiClasses)
- }
-
- var guiClassOverrides = CustomGuiTextureOverride(listOf())
-
- var matchingOverrides: Set<ItemOverrideCollection> = setOf()
-
- @Subscribe
- fun onOpenGui(event: ScreenChangeEvent) {
- val newTitle = event.new?.title ?: Text.empty()
- matchingOverrides = guiClassOverrides.classes
- .filterTo(mutableSetOf()) { it.screenFilter.title.matches(newTitle) }
- }
-
- val overrideCache = mutableMapOf<IdentityCharacteristics<ItemStack>, Any>()
-
- @JvmStatic
- fun replaceGlobalModel(
- models: ItemModels,
- stack: ItemStack,
- cir: CallbackInfoReturnable<BakedModel>
- ) {
- val value = overrideCache.computeNullableFunction(IdentityCharacteristics(stack)) {
- for (guiClassOverride in matchingOverrides) {
- for (override in guiClassOverride.overrides) {
- if (override.predicate.test(stack)) {
- return@computeNullableFunction models.modelManager.getModel(
- ModelIdentifier(override.model, "inventory"))
- }
- }
- }
- null
- }
- if (value != null)
- cir.returnValue = value
- }
-
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt
deleted file mode 100644
index a4e7c02..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonObject
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import net.minecraft.item.ItemStack
-import net.minecraft.util.Identifier
-
-object CustomModelOverrideParser {
- object FirmamentRootPredicateSerializer : KSerializer<FirmamentModelPredicate> {
- val delegateSerializer = kotlinx.serialization.json.JsonObject.serializer()
- override val descriptor: SerialDescriptor
- get() = SerialDescriptor("FirmamentModelRootPredicate", delegateSerializer.descriptor)
-
- override fun deserialize(decoder: Decoder): FirmamentModelPredicate {
- val json = decoder.decodeSerializableValue(delegateSerializer).intoGson() as JsonObject
- return AndPredicate(parsePredicates(json).toTypedArray())
- }
-
- override fun serialize(encoder: Encoder, value: FirmamentModelPredicate) {
- TODO("Cannot serialize firmament predicates")
- }
- }
-
- val predicateParsers = mutableMapOf<Identifier, FirmamentModelPredicateParser>()
-
-
- fun registerPredicateParser(name: String, parser: FirmamentModelPredicateParser) {
- predicateParsers[Identifier.of("firmament", name)] = parser
- }
-
- init {
- registerPredicateParser("display_name", DisplayNamePredicate.Parser)
- registerPredicateParser("lore", LorePredicate.Parser)
- registerPredicateParser("all", AndPredicate.Parser)
- registerPredicateParser("any", OrPredicate.Parser)
- registerPredicateParser("not", NotPredicate.Parser)
- registerPredicateParser("item", ItemPredicate.Parser)
- registerPredicateParser("extra_attributes", ExtraAttributesPredicate.Parser)
- registerPredicateParser("pet", PetPredicate.Parser)
- }
-
- private val neverPredicate = listOf(
- object : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- return false
- }
- }
- )
-
- fun parsePredicates(predicates: JsonObject): List<FirmamentModelPredicate> {
- val parsedPredicates = mutableListOf<FirmamentModelPredicate>()
- for (predicateName in predicates.keySet()) {
- if (!predicateName.startsWith("firmament:")) continue
- val identifier = Identifier.of(predicateName)
- val parser = predicateParsers[identifier] ?: return neverPredicate
- val parsedPredicate = parser.parse(predicates[predicateName]) ?: return neverPredicate
- parsedPredicates.add(parsedPredicate)
- }
- return parsedPredicates
- }
-
- @JvmStatic
- fun parseCustomModelOverrides(jsonObject: JsonObject): Array<FirmamentModelPredicate>? {
- val predicates = (jsonObject["predicate"] as? JsonObject) ?: return null
- val parsedPredicates = parsePredicates(predicates)
- if (parsedPredicates.isEmpty())
- return null
- return parsedPredicates.toTypedArray()
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt
deleted file mode 100644
index dec6046..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-package moe.nea.firmament.features.texturepack
-
-import com.mojang.authlib.minecraft.MinecraftProfileTexture
-import com.mojang.authlib.properties.Property
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
-import net.minecraft.block.SkullBlock
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.render.RenderLayer
-import net.minecraft.client.util.ModelIdentifier
-import net.minecraft.component.type.ProfileComponent
-import net.minecraft.util.Identifier
-import moe.nea.firmament.annotations.Subscribe
-import moe.nea.firmament.events.BakeExtraModelsEvent
-import moe.nea.firmament.events.CustomItemModelEvent
-import moe.nea.firmament.events.TickEvent
-import moe.nea.firmament.features.FirmamentFeature
-import moe.nea.firmament.gui.config.ManagedConfig
-import moe.nea.firmament.util.IdentityCharacteristics
-import moe.nea.firmament.util.item.decodeProfileTextureProperty
-import moe.nea.firmament.util.skyBlockId
-
-object CustomSkyBlockTextures : FirmamentFeature {
- override val identifier: String
- get() = "custom-skyblock-textures"
-
- object TConfig : ManagedConfig(identifier) {
- val enabled by toggle("enabled") { true }
- val skullsEnabled by toggle("skulls-enabled") { true }
- val cacheDuration by integer("cache-duration", 0, 20) { 1 }
- val enableModelOverrides by toggle("model-overrides") { true }
- val enableArmorOverrides by toggle("armor-overrides") { true }
- val enableBlockOverrides by toggle("block-overrides") { true }
- }
-
- override val config: ManagedConfig
- get() = TConfig
-
- @Subscribe
- fun onTick(it: TickEvent) {
- if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) {
- // TODO: unify all of those caches somehow
- CustomItemModelEvent.clearCache()
- skullTextureCache.clear()
- CustomGlobalTextures.overrideCache.clear()
- CustomGlobalArmorOverrides.overrideCache.clear()
- }
- }
-
- @Subscribe
- fun bakeCustomFirmModels(event: BakeExtraModelsEvent) {
- val resources =
- MinecraftClient.getInstance().resourceManager.findResources("models/item"
- ) { it: Identifier ->
- "firmskyblock" == it.namespace && it.path
- .endsWith(".json")
- }
- for (identifier in resources.keys) {
- val modelId = ModelIdentifier.ofInventoryVariant(
- Identifier.of(
- "firmskyblock",
- identifier.path.substring(
- "models/item/".length,
- identifier.path.length - ".json".length),
- ))
- event.addItemModel(modelId)
- }
- }
-
- @Subscribe
- fun onCustomModelId(it: CustomItemModelEvent) {
- if (!TConfig.enabled) return
- val id = it.itemStack.skyBlockId ?: return
- it.overrideModel = ModelIdentifier.ofInventoryVariant(Identifier.of("firmskyblock", id.identifier.path))
- }
-
- private val skullTextureCache = mutableMapOf<IdentityCharacteristics<ProfileComponent>, Any>()
- private val sentinelPresentInvalid = Object()
-
- private val mcUrlRegex = "https?://textures.minecraft.net/texture/([a-fA-F0-9]+)".toRegex()
-
- fun getSkullId(textureProperty: Property): String? {
- val texture = decodeProfileTextureProperty(textureProperty) ?: return null
- val textureUrl =
- texture.textures[MinecraftProfileTexture.Type.SKIN]?.url ?: return null
- val mcUrlData = mcUrlRegex.matchEntire(textureUrl) ?: return null
- return mcUrlData.groupValues[1]
- }
-
- fun getSkullTexture(profile: ProfileComponent): Identifier? {
- val id = getSkullId(profile.properties["textures"].firstOrNull() ?: return null) ?: return null
- return Identifier.of("firmskyblock", "textures/placedskull/$id.png")
- }
-
- fun modifySkullTexture(
- type: SkullBlock.SkullType?,
- component: ProfileComponent?,
- cir: CallbackInfoReturnable<RenderLayer>
- ) {
- if (type != SkullBlock.Type.PLAYER) return
- if (!TConfig.skullsEnabled) return
- if (component == null) return
- val ic = IdentityCharacteristics(component)
-
- val n = skullTextureCache.getOrPut(ic) {
- val id = getSkullTexture(component) ?: return@getOrPut sentinelPresentInvalid
- if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) {
- return@getOrPut sentinelPresentInvalid
- }
- return@getOrPut id
- }
- if (n === sentinelPresentInvalid) return
- cir.returnValue = RenderLayer.getEntityTranslucent(n as Identifier)
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt
deleted file mode 100644
index c89931e..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import net.minecraft.item.ItemStack
-import net.minecraft.nbt.NbtElement
-import net.minecraft.nbt.NbtString
-import moe.nea.firmament.util.item.displayNameAccordingToNbt
-import moe.nea.firmament.util.item.loreAccordingToNbt
-
-data class DisplayNamePredicate(val stringMatcher: StringMatcher) : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- val display = stack.displayNameAccordingToNbt
- return stringMatcher.matches(display)
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate {
- return DisplayNamePredicate(StringMatcher.parse(jsonElement))
- }
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt
deleted file mode 100644
index 4114f45..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ExtraAttributesPredicate.kt
+++ /dev/null
@@ -1,268 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonArray
-import com.google.gson.JsonElement
-import com.google.gson.JsonObject
-import com.google.gson.JsonPrimitive
-import net.minecraft.item.ItemStack
-import net.minecraft.nbt.NbtByte
-import net.minecraft.nbt.NbtCompound
-import net.minecraft.nbt.NbtDouble
-import net.minecraft.nbt.NbtElement
-import net.minecraft.nbt.NbtFloat
-import net.minecraft.nbt.NbtInt
-import net.minecraft.nbt.NbtList
-import net.minecraft.nbt.NbtLong
-import net.minecraft.nbt.NbtShort
-import net.minecraft.nbt.NbtString
-import moe.nea.firmament.util.extraAttributes
-
-fun interface NbtMatcher {
- fun matches(nbt: NbtElement): Boolean
-
- object Parser {
- fun parse(jsonElement: JsonElement): NbtMatcher? {
- if (jsonElement is JsonPrimitive) {
- if (jsonElement.isString) {
- val string = jsonElement.asString
- return MatchStringExact(string)
- }
- if (jsonElement.isNumber) {
- return MatchNumberExact(jsonElement.asLong) //TODO: parse generic number
- }
- }
- if (jsonElement is JsonObject) {
- var encounteredParser: NbtMatcher? = null
- for (entry in ExclusiveParserType.entries) {
- val data = jsonElement[entry.key] ?: continue
- if (encounteredParser != null) {
- // TODO: warn
- return null
- }
- encounteredParser = entry.parse(data) ?: return null
- }
- return encounteredParser
- }
- return null
- }
-
- enum class ExclusiveParserType(val key: String) {
- STRING("string") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return MatchString(StringMatcher.parse(element))
- }
- },
- INT("int") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return parseGenericNumber(element,
- { it.asInt },
- { (it as? NbtInt)?.intValue() },
- { a, b ->
- if (a == b) Comparison.EQUAL
- else if (a < b) Comparison.LESS_THAN
- else Comparison.GREATER
- })
- }
- },
- FLOAT("float") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return parseGenericNumber(element,
- { it.asFloat },
- { (it as? NbtFloat)?.floatValue() },
- { a, b ->
- if (a == b) Comparison.EQUAL
- else if (a < b) Comparison.LESS_THAN
- else Comparison.GREATER
- })
- }
- },
- DOUBLE("double") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return parseGenericNumber(element,
- { it.asDouble },
- { (it as? NbtDouble)?.doubleValue() },
- { a, b ->
- if (a == b) Comparison.EQUAL
- else if (a < b) Comparison.LESS_THAN
- else Comparison.GREATER
- })
- }
- },
- LONG("long") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return parseGenericNumber(element,
- { it.asLong },
- { (it as? NbtLong)?.longValue() },
- { a, b ->
- if (a == b) Comparison.EQUAL
- else if (a < b) Comparison.LESS_THAN
- else Comparison.GREATER
- })
- }
- },
- SHORT("short") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return parseGenericNumber(element,
- { it.asShort },
- { (it as? NbtShort)?.shortValue() },
- { a, b ->
- if (a == b) Comparison.EQUAL
- else if (a < b) Comparison.LESS_THAN
- else Comparison.GREATER
- })
- }
- },
- BYTE("byte") {
- override fun parse(element: JsonElement): NbtMatcher? {
- return parseGenericNumber(element,
- { it.asByte },
- { (it as? NbtByte)?.byteValue() },
- { a, b ->
- if (a == b) Comparison.EQUAL
- else if (a < b) Comparison.LESS_THAN
- else Comparison.GREATER
- })
- }
- },
- ;
-
- abstract fun parse(element: JsonElement): NbtMatcher?
- }
-
- enum class Comparison {
- LESS_THAN, EQUAL, GREATER
- }
-
- inline fun <T : Any> parseGenericNumber(
- jsonElement: JsonElement,
- primitiveExtractor: (JsonPrimitive) -> T?,
- crossinline nbtExtractor: (NbtElement) -> T?,
- crossinline compare: (T, T) -> Comparison
- ): NbtMatcher? {
- if (jsonElement is JsonPrimitive) {
- val expected = primitiveExtractor(jsonElement) ?: return null
- return NbtMatcher {
- val actual = nbtExtractor(it) ?: return@NbtMatcher false
- compare(actual, expected) == Comparison.EQUAL
- }
- }
- if (jsonElement is JsonObject) {
- val minElement = jsonElement.getAsJsonPrimitive("min")
- val min = if (minElement != null) primitiveExtractor(minElement) ?: return null else null
- val minExclusive = jsonElement.get("minExclusive")?.asBoolean ?: false
- val maxElement = jsonElement.getAsJsonPrimitive("max")
- val max = if (maxElement != null) primitiveExtractor(maxElement) ?: return null else null
- val maxExclusive = jsonElement.get("maxExclusive")?.asBoolean ?: true
- if (min == null && max == null) return null
- return NbtMatcher {
- val actual = nbtExtractor(it) ?: return@NbtMatcher false
- if (max != null) {
- val comp = compare(actual, max)
- if (comp == Comparison.GREATER) return@NbtMatcher false
- if (comp == Comparison.EQUAL && maxExclusive) return@NbtMatcher false
- }
- if (min != null) {
- val comp = compare(actual, min)
- if (comp == Comparison.LESS_THAN) return@NbtMatcher false
- if (comp == Comparison.EQUAL && minExclusive) return@NbtMatcher false
- }
- return@NbtMatcher true
- }
- }
- return null
-
- }
- }
-
- class MatchNumberExact(val number: Long) : NbtMatcher {
- override fun matches(nbt: NbtElement): Boolean {
- return when (nbt) {
- is NbtByte -> nbt.byteValue().toLong() == number
- is NbtInt -> nbt.intValue().toLong() == number
- is NbtShort -> nbt.shortValue().toLong() == number
- is NbtLong -> nbt.longValue().toLong() == number
- else -> false
- }
- }
-
- }
-
- class MatchStringExact(val string: String) : NbtMatcher {
- override fun matches(nbt: NbtElement): Boolean {
- return nbt is NbtString && nbt.asString() == string
- }
-
- override fun toString(): String {
- return "MatchNbtStringExactly($string)"
- }
- }
-
- class MatchString(val string: StringMatcher) : NbtMatcher {
- override fun matches(nbt: NbtElement): Boolean {
- return nbt is NbtString && string.matches(nbt.asString())
- }
-
- override fun toString(): String {
- return "MatchNbtString($string)"
- }
- }
-}
-
-data class ExtraAttributesPredicate(
- val path: NbtPrism,
- val matcher: NbtMatcher,
-) : FirmamentModelPredicate {
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate? {
- if (jsonElement !is JsonObject) return null
- val path = jsonElement.get("path") ?: return null
- val pathSegments = if (path is JsonArray) {
- path.map { (it as JsonPrimitive).asString }
- } else if (path is JsonPrimitive && path.isString) {
- path.asString.split(".")
- } else return null
- val matcher = NbtMatcher.Parser.parse(jsonElement.get("match") ?: jsonElement)
- ?: return null
- return ExtraAttributesPredicate(NbtPrism(pathSegments), matcher)
- }
- }
-
- override fun test(stack: ItemStack): Boolean {
- return path.access(stack.extraAttributes)
- .any { matcher.matches(it) }
- }
-}
-
-class NbtPrism(val path: List<String>) {
- override fun toString(): String {
- return "Prism($path)"
- }
- fun access(root: NbtElement): Collection<NbtElement> {
- var rootSet = mutableListOf(root)
- var switch = mutableListOf<NbtElement>()
- for (pathSegment in path) {
- if (pathSegment == ".") continue
- for (element in rootSet) {
- if (element is NbtList) {
- if (pathSegment == "*")
- switch.addAll(element)
- val index = pathSegment.toIntOrNull() ?: continue
- if (index !in element.indices) continue
- switch.add(element[index])
- }
- if (element is NbtCompound) {
- if (pathSegment == "*")
- element.keys.mapTo(switch) { element.get(it)!! }
- switch.add(element.get(pathSegment) ?: continue)
- }
- }
- val temp = switch
- switch = rootSet
- rootSet = temp
- switch.clear()
- }
- return rootSet
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt
deleted file mode 100644
index d11fec0..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import net.minecraft.item.ItemStack
-
-interface FirmamentModelPredicate {
- fun test(stack: ItemStack): Boolean
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt
deleted file mode 100644
index 3ed0c67..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-
-interface FirmamentModelPredicateParser {
- fun parse(jsonElement: JsonElement): FirmamentModelPredicate?
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt
deleted file mode 100644
index 4302b53..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ItemPredicate.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import com.google.gson.JsonPrimitive
-import kotlin.jvm.optionals.getOrNull
-import net.minecraft.item.Item
-import net.minecraft.item.ItemStack
-import net.minecraft.registry.RegistryKey
-import net.minecraft.registry.RegistryKeys
-import net.minecraft.util.Identifier
-import moe.nea.firmament.util.MC
-
-class ItemPredicate(
- val item: Item
-) : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- return stack.item == item
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): ItemPredicate? {
- if (jsonElement is JsonPrimitive && jsonElement.isString) {
- val itemKey = RegistryKey.of(RegistryKeys.ITEM,
- Identifier.tryParse(jsonElement.asString)
- ?: return null)
- return ItemPredicate(MC.defaultItems.getOptional(itemKey).getOrNull()?.value() ?: return null)
- }
- return null
- }
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt
deleted file mode 100644
index ab9e27d..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/JsonUnbakedModelFirmExtra.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import net.minecraft.util.Identifier
-
-interface JsonUnbakedModelFirmExtra {
-
- fun setHeadModel_firmament(identifier: Identifier?)
- fun getHeadModel_firmament(): Identifier?
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt
deleted file mode 100644
index 13e3974..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import net.minecraft.item.ItemStack
-import moe.nea.firmament.util.item.loreAccordingToNbt
-
-class LorePredicate(val matcher: StringMatcher) : FirmamentModelPredicate {
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate {
- return LorePredicate(StringMatcher.parse(jsonElement))
- }
- }
-
- override fun test(stack: ItemStack): Boolean {
- val lore = stack.loreAccordingToNbt
- return lore.any { matcher.matches(it) }
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt
deleted file mode 100644
index 1585bd7..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-interface ModelOverrideData {
- fun getFirmamentOverrides(): Array<FirmamentModelPredicate>?
- fun setFirmamentOverrides(overrides: Array<FirmamentModelPredicate>?)
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt
deleted file mode 100644
index 4ef8d06..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import moe.nea.firmament.util.filter.IteratorFilterSet
-
-class ModelOverrideFilterSet(original: java.util.Set<Map.Entry<String, JsonElement>>) :
- IteratorFilterSet<Map.Entry<String, JsonElement>>(original) {
- companion object {
- @JvmStatic
- fun createFilterSet(set: java.util.Set<*>): java.util.Set<*> {
- return ModelOverrideFilterSet(set as java.util.Set<Map.Entry<String, JsonElement>>) as java.util.Set<*>
- }
- }
-
- override fun shouldKeepElement(element: Map.Entry<String, JsonElement>): Boolean {
- return !element.key.startsWith("firmament:")
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt
deleted file mode 100644
index ecd67c3..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/NotPredicate.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import com.google.gson.JsonObject
-import net.minecraft.item.ItemStack
-
-class NotPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- return children.none { it.test(stack) }
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate {
- return NotPredicate(CustomModelOverrideParser.parsePredicates(jsonElement as JsonObject).toTypedArray())
- }
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt
deleted file mode 100644
index 7e6665f..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/NumberMatcher.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import com.google.gson.JsonPrimitive
-import moe.nea.firmament.util.useMatch
-
-abstract class NumberMatcher {
- abstract fun test(number: Number): Boolean
-
-
- companion object {
- fun parse(jsonElement: JsonElement): NumberMatcher? {
- if (jsonElement is JsonPrimitive) {
- if (jsonElement.isString) {
- val string = jsonElement.asString
- return parseRange(string) ?: parseOperator(string)
- }
- if (jsonElement.isNumber) {
- val number = jsonElement.asNumber
- val hasDecimals = (number.toString().contains("."))
- return MatchNumberExact(if (hasDecimals) number.toLong() else number.toDouble())
- }
- }
- return null
- }
-
- private val intervalSpec =
- "(?<beginningOpen>[\\[\\(])(?<beginning>[0-9.]+)?,(?<ending>[0-9.]+)?(?<endingOpen>[\\]\\)])"
- .toPattern()
-
- fun parseRange(string: String): RangeMatcher? {
- intervalSpec.useMatch<Nothing>(string) {
- // Open in the set-theory sense, meaning does not include its end.
- val beginningOpen = group("beginningOpen") == "("
- val endingOpen = group("endingOpen") == ")"
- val beginning = group("beginning")?.toDouble()
- val ending = group("ending")?.toDouble()
- return RangeMatcher(beginning, !beginningOpen, ending, !endingOpen)
- }
- return null
- }
-
- enum class Operator(val operator: String) {
- LESS("<") {
- override fun matches(comparisonResult: Int): Boolean {
- return comparisonResult < 0
- }
- },
- LESS_EQUALS("<=") {
- override fun matches(comparisonResult: Int): Boolean {
- return comparisonResult <= 0
- }
- },
- GREATER(">") {
- override fun matches(comparisonResult: Int): Boolean {
- return comparisonResult > 0
- }
- },
- GREATER_EQUALS(">=") {
- override fun matches(comparisonResult: Int): Boolean {
- return comparisonResult >= 0
- }
- },
- ;
-
- abstract fun matches(comparisonResult: Int): Boolean
- }
-
- private val operatorPattern = "(?<operator>${Operator.entries.joinToString("|") {it.operator}})(?<value>[0-9.]+)".toPattern()
-
- fun parseOperator(string: String): OperatorMatcher? {
- operatorPattern.useMatch<Nothing>(string) {
- val operatorName = group("operator")
- val operator = Operator.entries.find { it.operator == operatorName }!!
- val value = group("value").toDouble()
- return OperatorMatcher(operator, value)
- }
- return null
- }
-
- data class OperatorMatcher(val operator: Operator, val value: Double) : NumberMatcher() {
- override fun test(number: Number): Boolean {
- return operator.matches(number.toDouble().compareTo(value))
- }
- }
-
-
- data class MatchNumberExact(val number: Number) : NumberMatcher() {
- override fun test(number: Number): Boolean {
- return when (this.number) {
- is Double -> number.toDouble() == this.number.toDouble()
- else -> number.toLong() == this.number.toLong()
- }
- }
- }
-
- data class RangeMatcher(
- val beginning: Double?,
- val beginningInclusive: Boolean,
- val ending: Double?,
- val endingInclusive: Boolean,
- ) : NumberMatcher() {
- override fun test(number: Number): Boolean {
- val value = number.toDouble()
- if (beginning != null) {
- if (beginningInclusive) {
- if (value < beginning) return false
- } else {
- if (value <= beginning) return false
- }
- }
- if (ending != null) {
- if (endingInclusive) {
- if (value > ending) return false
- } else {
- if (value >= ending) return false
- }
- }
- return true
- }
- }
- }
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt
deleted file mode 100644
index 32f556b..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonArray
-import com.google.gson.JsonElement
-import com.google.gson.JsonObject
-import net.minecraft.item.ItemStack
-
-class OrPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModelPredicate {
- override fun test(stack: ItemStack): Boolean {
- return children.any { it.test(stack) }
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate {
- val children =
- (jsonElement as JsonArray)
- .flatMap {
- CustomModelOverrideParser.parsePredicates(it as JsonObject)
- }
- .toTypedArray()
- return OrPredicate(children)
- }
-
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt
deleted file mode 100644
index 5e5d750..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/PetPredicate.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import com.google.gson.JsonObject
-import net.minecraft.item.ItemStack
-import moe.nea.firmament.repo.ExpLadders
-import moe.nea.firmament.util.petData
-
-class PetPredicate(
- val petId: StringMatcher?,
- val tier: RarityMatcher?,
- val exp: NumberMatcher?,
- val candyUsed: NumberMatcher?,
- val level: NumberMatcher?,
-) : FirmamentModelPredicate {
-
- override fun test(stack: ItemStack): Boolean {
- val petData = stack.petData ?: return false
- if (petId != null) {
- if (!petId.matches(petData.type)) return false
- }
- if (exp != null) {
- if (!exp.test(petData.exp)) return false
- }
- if (candyUsed != null) {
- if (!candyUsed.test(petData.candyUsed)) return false
- }
- if (tier != null) {
- if (!tier.match(petData.tier)) return false
- }
- val levelData by lazy(LazyThreadSafetyMode.NONE) {
- ExpLadders.getExpLadder(petData.type, petData.tier)
- .getPetLevel(petData.exp)
- }
- if (level != null) {
- if (!level.test(levelData.currentLevel)) return false
- }
- return true
- }
-
- object Parser : FirmamentModelPredicateParser {
- override fun parse(jsonElement: JsonElement): FirmamentModelPredicate? {
- if (jsonElement.isJsonPrimitive) {
- return PetPredicate(StringMatcher.Equals(jsonElement.asString, false), null, null, null, null)
- }
- if (jsonElement !is JsonObject) return null
- val idMatcher = jsonElement["id"]?.let(StringMatcher::parse)
- val expMatcher = jsonElement["exp"]?.let(NumberMatcher::parse)
- val levelMatcher = jsonElement["level"]?.let(NumberMatcher::parse)
- val candyMatcher = jsonElement["candyUsed"]?.let(NumberMatcher::parse)
- val tierMatcher = jsonElement["tier"]?.let(RarityMatcher::parse)
- return PetPredicate(
- idMatcher,
- tierMatcher,
- expMatcher,
- candyMatcher,
- levelMatcher,
- )
- }
- }
-
- override fun toString(): String {
- return super.toString()
- }
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt
deleted file mode 100644
index 634a171..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/RarityMatcher.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonElement
-import io.github.moulberry.repo.data.Rarity
-import moe.nea.firmament.util.useMatch
-
-abstract class RarityMatcher {
- abstract fun match(rarity: Rarity): Boolean
-
- companion object {
- fun parse(jsonElement: JsonElement): RarityMatcher {
- val string = jsonElement.asString
- val range = parseRange(string)
- if (range != null) return range
- return Exact(Rarity.valueOf(string))
- }
-
- private val allRarities = Rarity.entries.joinToString("|", "(?:", ")")
- private val intervalSpec =
- "(?<beginningOpen>[\\[\\(])(?<beginning>$allRarities)?,(?<ending>$allRarities)?(?<endingOpen>[\\]\\)])"
- .toPattern()
-
- fun parseRange(string: String): RangeMatcher? {
- intervalSpec.useMatch<Nothing>(string) {
- // Open in the set-theory sense, meaning does not include its end.
- val beginningOpen = group("beginningOpen") == "("
- val endingOpen = group("endingOpen") == ")"
- val beginning = group("beginning")?.let(Rarity::valueOf)
- val ending = group("ending")?.let(Rarity::valueOf)
- return RangeMatcher(beginning, !beginningOpen, ending, !endingOpen)
- }
- return null
- }
-
- }
-
- data class Exact(val expected: Rarity) : RarityMatcher() {
- override fun match(rarity: Rarity): Boolean {
- return rarity == expected
- }
- }
-
- data class RangeMatcher(
- val beginning: Rarity?,
- val beginningInclusive: Boolean,
- val ending: Rarity?,
- val endingInclusive: Boolean,
- ) : RarityMatcher() {
- override fun match(rarity: Rarity): Boolean {
- if (beginning != null) {
- if (beginningInclusive) {
- if (rarity < beginning) return false
- } else {
- if (rarity <= beginning) return false
- }
- }
- if (ending != null) {
- if (endingInclusive) {
- if (rarity > ending) return false
- } else {
- if (rarity >= ending) return false
- }
- }
- return true
- }
- }
-
-}
diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt
deleted file mode 100644
index 5eb86ac..0000000
--- a/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt
+++ /dev/null
@@ -1,159 +0,0 @@
-
-package moe.nea.firmament.features.texturepack
-
-import com.google.gson.JsonArray
-import com.google.gson.JsonElement
-import com.google.gson.JsonNull
-import com.google.gson.JsonObject
-import com.google.gson.JsonPrimitive
-import com.google.gson.internal.LazilyParsedNumber
-import java.util.function.Predicate
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.Serializable
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import net.minecraft.nbt.NbtString
-import net.minecraft.text.Text
-import moe.nea.firmament.util.MC
-import moe.nea.firmament.util.removeColorCodes
-
-@Serializable(with = StringMatcher.Serializer::class)
-interface StringMatcher {
- fun matches(string: String): Boolean
- fun matches(text: Text): Boolean {
- return matches(text.string)
- }
-
- fun matches(nbt: NbtString): Boolean {
- val string = nbt.asString()
- val jsonStart = string.indexOf('{')
- val stringStart = string.indexOf('"')
- val isString = stringStart >= 0 && string.subSequence(0, stringStart).isBlank()
- val isJson = jsonStart >= 0 && string.subSequence(0, jsonStart).isBlank()
- if (isString || isJson)
- return matches(Text.Serialization.fromJson(string, MC.defaultRegistries) ?: return false)
- return matches(string)
- }
-
- class Equals(input: String, val stripColorCodes: Boolean) : StringMatcher {
- private val expected = if (stripColorCodes) input.removeColorCodes() else input
- override fun matches(string: String): Boolean {
- return expected == (if (stripColorCodes) string.removeColorCodes() else string)
- }
-
- override fun toString(): String {
- return "Equals($expected, stripColorCodes = $stripColorCodes)"
- }
- }
-
- class Pattern(val patternWithColorCodes: String, val stripColorCodes: Boolean) : StringMatcher {
- private val regex: Predicate<String> = patternWithColorCodes.toPattern().asMatchPredicate()
- override fun matches(string: String): Boolean {
- return regex.test(if (stripColorCodes) string.removeColorCodes() else string)
- }
-
- override fun toString(): String {
- return "Pattern($patternWithColorCodes, stripColorCodes = $stripColorCodes)"
- }
- }
-
- object Serializer : KSerializer<StringMatcher> {
- val delegateSerializer = kotlinx.serialization.json.JsonElement.serializer()
- override val descriptor: SerialDescriptor
- get() = SerialDescriptor("StringMatcher", delegateSerializer.descriptor)
-
- override fun deserialize(decoder: Decoder): StringMatcher {
- val delegate = decoder.decodeSerializableValue(delegateSerializer)
- val gsonDelegate = delegate.intoGson()
- return parse(gsonDelegate)
- }
-
- override fun serialize(encoder: Encoder, value: StringMatcher) {
- encoder.encodeSerializableValue(delegateSerializer, Companion.serialize(value).intoKotlinJson())
- }
-
- }
-
- companion object {
- fun serialize(stringMatcher: StringMatcher): JsonElement {
- TODO("Cannot serialize string matchers rn")
- }
-
- fun parse(jsonElement: JsonElement): StringMatcher {
- if (jsonElement is JsonPrimitive) {
- return Equals(jsonElement.asString, true)
- }
- if (jsonElement is JsonObject) {
- val regex = jsonElement["regex"] as JsonPrimitive?
- val text = jsonElement["equals"] as JsonPrimitive?
- val shouldStripColor = when (val color = (jsonElement["color"] as JsonPrimitive?)?.asString) {
- "preserve" -> false
- "strip", null -> true
- else -> error("Unknown color preservation mode: $color")
- }
- if ((regex == null) == (text == null)) error("Could not parse $jsonElement as string matcher")
- if (regex != null)
- return Pattern(regex.asString, shouldStripColor)
- if (text != null)
- return Equals(text.asString, shouldStripColor)
- }
- error("Could not parse $jsonElement as a string matcher")
- }
- }
-}
-
-fun JsonElement.intoKotlinJson(): kotlinx.serialization.json.JsonElement {
- when (this) {
- is JsonNull -> return kotlinx.serialization.json.JsonNull
- is JsonObject -> {
- return kotlinx.serialization.json.JsonObject(this.entrySet()
- .associate { it.key to it.value.intoKotlinJson() })
- }
-
- is JsonArray -> {
- return kotlinx.serialization.json.JsonArray(this.map { it.intoKotlinJson() })
- }
-
- is JsonPrimitive -> {
- if (this.isString)
- return kotlinx.serialization.json.JsonPrimitive(this.asString)
- if (this.isBoolean)
- return kotlinx.serialization.json.JsonPrimitive(this.asBoolean)
- return kotlinx.serialization.json.JsonPrimitive(this.asNumber)
- }
-
- else -> error("Unknown json variant $this")
- }
-}
-
-fun kotlinx.serialization.json.JsonElement.intoGson(): JsonElement {
- when (this) {
- is kotlinx.serialization.json.JsonNull -> return JsonNull.INSTANCE
- is kotlinx.serialization.json.JsonPrimitive -> {
- if (this.isString)
- return JsonPrimitive(this.content)
- if (this.content == "true")
- return JsonPrimitive(true)
- if (this.content == "false")
- return JsonPrimitive(false)
- return JsonPrimitive(LazilyParsedNumber(this.content))
- }
-
- is kotlinx.serialization.json.JsonObject -> {
- val obj = JsonObject()
- for ((k, v) in this) {
- obj.add(k, v.intoGson())
- }
- return obj
- }
-
- is kotlinx.serialization.json.JsonArray -> {
- val arr = JsonArray()
- for (v in this) {
- arr.add(v.intoGson())
- }
- return arr
- }
- }
-}