diff options
Diffstat (limited to 'src/main/kotlin/features/texturepack')
25 files changed, 0 insertions, 1933 deletions
diff --git a/src/main/kotlin/features/texturepack/BakedModelExtra.kt b/src/main/kotlin/features/texturepack/BakedModelExtra.kt deleted file mode 100644 index 6305748..0000000 --- a/src/main/kotlin/features/texturepack/BakedModelExtra.kt +++ /dev/null @@ -1,30 +0,0 @@ -package moe.nea.firmament.features.texturepack - -import net.fabricmc.fabric.api.renderer.v1.model.WrapperBakedModel as WrapperBakedModelFabric -import net.minecraft.client.render.model.BakedModel -import net.minecraft.client.render.model.WrapperBakedModel -import moe.nea.firmament.util.ErrorUtil - -interface BakedModelExtra { - companion object { - @JvmStatic - fun cast(originalModel: BakedModel): BakedModelExtra? { - var p = originalModel - for (i in 0..256) { - p = when (p) { - is BakedModelExtra -> return p - is WrapperBakedModel -> p.wrapped - is WrapperBakedModelFabric -> WrapperBakedModelFabric.unwrap(p) - else -> break - } - } - ErrorUtil.softError("Could not find a baked model for $originalModel") - return null - } - } - - var tintOverrides_firmament: TintOverrides? - - fun getHeadModel_firmament(): BakedModel? - fun setHeadModel_firmament(headModel: BakedModel?) -} diff --git a/src/main/kotlin/features/texturepack/BakedOverrideData.kt b/src/main/kotlin/features/texturepack/BakedOverrideData.kt deleted file mode 100644 index e9391f1..0000000 --- a/src/main/kotlin/features/texturepack/BakedOverrideData.kt +++ /dev/null @@ -1,14 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import net.minecraft.client.render.model.json.ModelOverrideList - -interface BakedOverrideData { - fun getFirmamentOverrides(): Array<FirmamentModelPredicate>? - fun setFirmamentOverrides(overrides: Array<FirmamentModelPredicate>?) - companion object{ - @Suppress("CAST_NEVER_SUCCEEDS") - @JvmStatic - fun cast(bakedOverride: ModelOverrideList.BakedOverride): BakedOverrideData = bakedOverride as BakedOverrideData - } -} diff --git a/src/main/kotlin/features/texturepack/CustomBlockTextures.kt b/src/main/kotlin/features/texturepack/CustomBlockTextures.kt deleted file mode 100644 index 2f7f084..0000000 --- a/src/main/kotlin/features/texturepack/CustomBlockTextures.kt +++ /dev/null @@ -1,301 +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.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 { - val r = Class.forName("moe.nea.firmament.compat.sodium.SodiumChunkReloader") - .getConstructor() - .newInstance() as Runnable - r.run() - r - }.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, it.id) } - } - - 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.getOrThrow(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/features/texturepack/CustomGlobalArmorOverrides.kt b/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt deleted file mode 100644 index 54e9e11..0000000 --- a/src/main/kotlin/features/texturepack/CustomGlobalArmorOverrides.kt +++ /dev/null @@ -1,155 +0,0 @@ -@file:UseSerializers(IdentifierSerializer::class) - -package moe.nea.firmament.features.texturepack - -import java.util.Optional -import java.util.concurrent.atomic.AtomicInteger -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient -import kotlinx.serialization.UseSerializers -import net.minecraft.item.ItemStack -import net.minecraft.item.equipment.EquipmentModel -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.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 { - @Serializable - data class ArmorOverride( - @SerialName("item_ids") - val itemIds: List<String>, - val layers: List<ArmorOverrideLayer>? = null, - val model: Identifier? = null, - val overrides: List<ArmorOverrideOverride> = listOf(), - ) { - @Transient - lateinit var modelIdentifier: Identifier - fun bake() { - modelIdentifier = bakeModel(model, layers) - overrides.forEach { it.bake() } - } - - init { - require(layers != null || model != null) { "Either model or layers must be specified for armor override" } - require(layers == null || model == null) { "Can't specify both model and layers for armor override" } - } - } - - @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>? = null, - val model: Identifier? = null, - ) { - init { - require(layers != null || model != null) { "Either model or layers must be specified for armor override override" } - require(layers == null || model == null) { "Can't specify both model and layers for armor override override" } - } - - @Transient - lateinit var modelIdentifier: Identifier - fun bake() { - modelIdentifier = bakeModel(model, layers) - } - } - - - val overrideCache = WeakCache.memoize<ItemStack, Optional<Identifier>>("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.modelIdentifier) - } - } - return@memoize Optional.of(override.modelIdentifier) - } - - var overrides: Map<String, ArmorOverride> = mapOf() - private var bakedOverrides: MutableMap<Identifier, EquipmentModel> = mutableMapOf() - private val sentinelFirmRunning = AtomicInteger() - - private fun bakeModel(model: Identifier?, layers: List<ArmorOverrideLayer>?): Identifier { - require(model == null || layers == null) - if (model != null) { - return model - } else if (layers != null) { - val idNumber = sentinelFirmRunning.incrementAndGet() - val identifier = Identifier.of("firmament:sentinel/$idNumber") - val equipmentLayers = layers.map { - EquipmentModel.Layer( - it.identifier, if (it.tint) { - Optional.of(EquipmentModel.Dyeable(Optional.empty())) - } else { - Optional.empty() - }, - false - ) - } - bakedOverrides[identifier] = EquipmentModel( - mapOf( - EquipmentModel.LayerType.HUMANOID to equipmentLayers, - EquipmentModel.LayerType.HUMANOID_LEGGINGS to equipmentLayers, - ) - ) - return identifier - } else { - error("Either model or layers must be non null") - } - } - - - @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) { - bakedOverrides.clear() - prepared.forEach { it.value.bake() } - overrides = prepared - } - }) - } - - @JvmStatic - fun overrideArmor(itemStack: ItemStack): Optional<Identifier> { - return overrideCache.invoke(itemStack) - } - - @JvmStatic - fun overrideArmorLayer(id: Identifier): EquipmentModel? { - return bakedOverrides[id] - } - -} diff --git a/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt b/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt deleted file mode 100644 index 9ad8bc1..0000000 --- a/src/main/kotlin/features/texturepack/CustomGlobalTextures.kt +++ /dev/null @@ -1,164 +0,0 @@ -@file:UseSerializers(IdentifierSerializer::class, CustomModelOverrideParser.FirmamentRootPredicateSerializer::class) - -package moe.nea.firmament.features.texturepack - - -import java.util.Optional -import java.util.concurrent.CompletableFuture -import org.slf4j.LoggerFactory -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.MC -import moe.nea.firmament.util.collections.WeakCache -import moe.nea.firmament.util.intoOptional -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 = - WeakCache.memoize<ItemStack, ItemModels, Optional<BakedModel>>("CustomGlobalTextureModelOverrides") { stack, models -> - matchingOverrides - .firstNotNullOfOrNull { - it.overrides - .asSequence() - .filter { it.predicate.test(stack) } - .map { models.getModel(it.model) } - .firstOrNull() - } - .intoOptional() - } - - @JvmStatic - fun replaceGlobalModel( - models: ItemModels, - stack: ItemStack, - ): BakedModel? { - return overrideCache.invoke(stack, models).getOrNull() - } - - -} diff --git a/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt b/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt deleted file mode 100644 index c5fc20b..0000000 --- a/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt +++ /dev/null @@ -1,82 +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 moe.nea.firmament.features.texturepack.predicates.AndPredicate -import moe.nea.firmament.features.texturepack.predicates.DisplayNamePredicate -import moe.nea.firmament.features.texturepack.predicates.ExtraAttributesPredicate -import moe.nea.firmament.features.texturepack.predicates.ItemPredicate -import moe.nea.firmament.features.texturepack.predicates.LorePredicate -import moe.nea.firmament.features.texturepack.predicates.NotPredicate -import moe.nea.firmament.features.texturepack.predicates.OrPredicate -import moe.nea.firmament.features.texturepack.predicates.PetPredicate -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/features/texturepack/CustomSkyBlockTextures.kt b/src/main/kotlin/features/texturepack/CustomSkyBlockTextures.kt deleted file mode 100644 index 627d39a..0000000 --- a/src/main/kotlin/features/texturepack/CustomSkyBlockTextures.kt +++ /dev/null @@ -1,135 +0,0 @@ -package moe.nea.firmament.features.texturepack - -import com.mojang.authlib.minecraft.MinecraftProfileTexture -import com.mojang.authlib.properties.Property -import java.util.Optional -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable -import kotlin.jvm.optionals.getOrNull -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.FinalizeResourceManagerEvent -import moe.nea.firmament.events.TickEvent -import moe.nea.firmament.features.FirmamentFeature -import moe.nea.firmament.gui.config.ManagedConfig -import moe.nea.firmament.util.collections.WeakCache -import moe.nea.firmament.util.mc.decodeProfileTextureProperty -import moe.nea.firmament.util.skyBlockId - -object CustomSkyBlockTextures : FirmamentFeature { - override val identifier: String - get() = "custom-skyblock-textures" - - object TConfig : ManagedConfig(identifier, Category.INTEGRATIONS) { // TODO: should this be its own thing? - val enabled by toggle("enabled") { true } - val skullsEnabled by toggle("skulls-enabled") { true } - val cacheForever by toggle("cache-forever") { true } - val cacheDuration by integer("cache-duration", 0, 100) { 1 } - val enableModelOverrides by toggle("model-overrides") { true } - val enableArmorOverrides by toggle("armor-overrides") { true } - val enableBlockOverrides by toggle("block-overrides") { true } - val enableLegacyCIT by toggle("legacy-cit") { true } - val allowRecoloringUiText by toggle("recolor-text") { true } - } - - override val config: ManagedConfig - get() = TConfig - - val allItemCaches by lazy { - listOf( - CustomItemModelEvent.cache.cache, - skullTextureCache.cache, - CustomGlobalTextures.overrideCache.cache, - CustomGlobalArmorOverrides.overrideCache.cache - ) - } - - fun clearAllCaches() { - allItemCaches.forEach(WeakCache<*, *, *>::clear) - } - - @Subscribe - fun onTick(it: TickEvent) { - if (TConfig.cacheForever) return - if (TConfig.cacheDuration < 1 || it.tickCount % TConfig.cacheDuration == 0) { - clearAllCaches() - } - } - - @Subscribe - fun onStart(event: FinalizeResourceManagerEvent) { - event.registerOnApply("Clear firmament CIT caches") { - clearAllCaches() - } - } - - @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 = - WeakCache.memoize<ProfileComponent, Optional<Identifier>>("SkullTextureCache") { component -> - val id = getSkullTexture(component) ?: return@memoize Optional.empty() - if (!MinecraftClient.getInstance().resourceManager.getResource(id).isPresent) { - return@memoize Optional.empty() - } - return@memoize Optional.of(id) - } - - 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 n = skullTextureCache.invoke(component).getOrNull() ?: return - cir.returnValue = RenderLayer.getEntityTranslucent(n) - } -} diff --git a/src/main/kotlin/features/texturepack/CustomTextColors.kt b/src/main/kotlin/features/texturepack/CustomTextColors.kt deleted file mode 100644 index 4ca1796..0000000 --- a/src/main/kotlin/features/texturepack/CustomTextColors.kt +++ /dev/null @@ -1,66 +0,0 @@ -package moe.nea.firmament.features.texturepack - -import java.util.Optional -import kotlinx.serialization.Serializable -import kotlin.jvm.optionals.getOrNull -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.FinalizeResourceManagerEvent -import moe.nea.firmament.util.collections.WeakCache - -object CustomTextColors : SinglePreparationResourceReloader<CustomTextColors.TextOverrides?>() { - @Serializable - data class TextOverrides( - val defaultColor: Int, - val overrides: List<TextOverride> = listOf() - ) - - @Serializable - data class TextOverride( - val predicate: StringMatcher, - val override: Int, - ) - - @Subscribe - fun registerTextColorReloader(event: FinalizeResourceManagerEvent) { - event.resourceManager.registerReloader(this) - } - - val cache = WeakCache.memoize<Text, Optional<Int>>("CustomTextColor") { text -> - val override = textOverrides ?: return@memoize Optional.empty() - Optional.of(override.overrides.find { it.predicate.matches(text) }?.override ?: override.defaultColor) - } - - fun mapTextColor(text: Text, oldColor: Int): Int { - if (textOverrides == null) return oldColor - return cache(text).getOrNull() ?: oldColor - } - - override fun prepare( - manager: ResourceManager, - profiler: Profiler - ): TextOverrides? { - val resource = manager.getResource(Identifier.of("firmskyblock", "overrides/text_colors.json")).getOrNull() - ?: return null - return Firmament.tryDecodeJsonFromStream<TextOverrides>(resource.inputStream) - .getOrElse { - Firmament.logger.error("Could not parse text_colors.json", it) - null - } - } - - var textOverrides: TextOverrides? = null - - override fun apply( - prepared: TextOverrides?, - manager: ResourceManager, - profiler: Profiler - ) { - textOverrides = prepared - } -} diff --git a/src/main/kotlin/features/texturepack/FirmamentModelPredicate.kt b/src/main/kotlin/features/texturepack/FirmamentModelPredicate.kt deleted file mode 100644 index d11fec0..0000000 --- a/src/main/kotlin/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/features/texturepack/FirmamentModelPredicateParser.kt b/src/main/kotlin/features/texturepack/FirmamentModelPredicateParser.kt deleted file mode 100644 index 3ed0c67..0000000 --- a/src/main/kotlin/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/features/texturepack/JsonUnbakedModelFirmExtra.kt b/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt deleted file mode 100644 index 9f641b8..0000000 --- a/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt +++ /dev/null @@ -1,16 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import net.minecraft.client.render.model.Baker -import net.minecraft.util.Identifier - -interface JsonUnbakedModelFirmExtra { - fun storeExtraBaker_firmament(baker: Baker) - - fun setHeadModel_firmament(identifier: Identifier?) - fun getHeadModel_firmament(): Identifier? - - fun setTintOverrides_firmament(tintOverrides: TintOverrides?) - fun getTintOverrides_firmament(): TintOverrides - -} diff --git a/src/main/kotlin/features/texturepack/ModelOverrideData.kt b/src/main/kotlin/features/texturepack/ModelOverrideData.kt deleted file mode 100644 index 29d9192..0000000 --- a/src/main/kotlin/features/texturepack/ModelOverrideData.kt +++ /dev/null @@ -1,15 +0,0 @@ -package moe.nea.firmament.features.texturepack - -import net.minecraft.client.render.model.json.ModelOverride - -interface ModelOverrideData { - companion object { - - @JvmStatic - @Suppress("CAST_NEVER_SUCCEEDS") - fun cast(override: ModelOverride) = override as ModelOverrideData - } - - fun getFirmamentOverrides(): Array<FirmamentModelPredicate>? - fun setFirmamentOverrides(overrides: Array<FirmamentModelPredicate>?) -} diff --git a/src/main/kotlin/features/texturepack/RarityMatcher.kt b/src/main/kotlin/features/texturepack/RarityMatcher.kt deleted file mode 100644 index 634a171..0000000 --- a/src/main/kotlin/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/features/texturepack/StringMatcher.kt b/src/main/kotlin/features/texturepack/StringMatcher.kt deleted file mode 100644 index 5eb86ac..0000000 --- a/src/main/kotlin/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 - } - } -} diff --git a/src/main/kotlin/features/texturepack/TintOverrides.kt b/src/main/kotlin/features/texturepack/TintOverrides.kt deleted file mode 100644 index 85fcae4..0000000 --- a/src/main/kotlin/features/texturepack/TintOverrides.kt +++ /dev/null @@ -1,75 +0,0 @@ -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import moe.nea.firmament.util.ErrorUtil - -data class TintOverrides( - val layerMap: Map<Int, TintOverride> = mapOf() -) { - val hasOverrides by lazy { layerMap.values.any { it !is Reset } } - - companion object { - val EMPTY = TintOverrides() - private val threadLocal = object : ThreadLocal<TintOverrides>() {} - fun enter(overrides: TintOverrides?) { - ErrorUtil.softCheck("Double entered tintOverrides", - threadLocal.get() == null) - threadLocal.set(overrides ?: EMPTY) - } - - fun exit(overrides: TintOverrides?) { - ErrorUtil.softCheck("Exited with non matching enter tintOverrides", - threadLocal.get() == (overrides ?: EMPTY)) - threadLocal.remove() - } - - fun getCurrentOverrides(): TintOverrides { - return ErrorUtil.notNullOr(threadLocal.get(), "Got current tintOverrides without entering") { - EMPTY - } - } - - fun parse(jsonObject: JsonObject): TintOverrides { - val map = mutableMapOf<Int, TintOverride>() - for ((key, value) in jsonObject.entrySet()) { - val layerIndex = - ErrorUtil.notNullOr(key.toIntOrNull(), - "Unknown layer index $value. Should be integer") { continue } - if (value.isJsonNull) { - map[layerIndex] = Reset - continue - } - val override = (value as? JsonPrimitive) - ?.takeIf(JsonPrimitive::isNumber) - ?.asInt - ?.let(::Fixed) - if (override == null) { - ErrorUtil.softError("Invalid tint override for a layer: $value") - continue - } - map[layerIndex] = override - } - return TintOverrides(map) - } - } - - fun mergeWithParent(parent: TintOverrides): TintOverrides { - val mergedMap = parent.layerMap.toMutableMap() - mergedMap.putAll(this.layerMap) - return TintOverrides(mergedMap) - } - - fun hasOverrides(): Boolean = hasOverrides - fun getOverride(tintIndex: Int): Int? { - return when (val tint = layerMap[tintIndex]) { - is Reset -> null - is Fixed -> tint.color - null -> null - } - } - - sealed interface TintOverride - data object Reset : TintOverride - data class Fixed(val color: Int) : TintOverride -} diff --git a/src/main/kotlin/features/texturepack/predicates/AlwaysPredicate.kt b/src/main/kotlin/features/texturepack/predicates/AlwaysPredicate.kt deleted file mode 100644 index 7e0ddb1..0000000 --- a/src/main/kotlin/features/texturepack/predicates/AlwaysPredicate.kt +++ /dev/null @@ -1,19 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonElement -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -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/features/texturepack/predicates/AndPredicate.kt b/src/main/kotlin/features/texturepack/predicates/AndPredicate.kt deleted file mode 100644 index 99abaaa..0000000 --- a/src/main/kotlin/features/texturepack/predicates/AndPredicate.kt +++ /dev/null @@ -1,28 +0,0 @@ -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import moe.nea.firmament.features.texturepack.CustomModelOverrideParser -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -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/features/texturepack/predicates/DisplayNamePredicate.kt b/src/main/kotlin/features/texturepack/predicates/DisplayNamePredicate.kt deleted file mode 100644 index 04c7a2b..0000000 --- a/src/main/kotlin/features/texturepack/predicates/DisplayNamePredicate.kt +++ /dev/null @@ -1,22 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonElement -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -import moe.nea.firmament.features.texturepack.StringMatcher -import net.minecraft.item.ItemStack -import moe.nea.firmament.util.mc.displayNameAccordingToNbt - -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/features/texturepack/predicates/ExtraAttributesPredicate.kt b/src/main/kotlin/features/texturepack/predicates/ExtraAttributesPredicate.kt deleted file mode 100644 index 3c8023d..0000000 --- a/src/main/kotlin/features/texturepack/predicates/ExtraAttributesPredicate.kt +++ /dev/null @@ -1,271 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import com.google.gson.JsonPrimitive -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -import moe.nea.firmament.features.texturepack.StringMatcher -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/features/texturepack/predicates/ItemPredicate.kt b/src/main/kotlin/features/texturepack/predicates/ItemPredicate.kt deleted file mode 100644 index 3cb80c7..0000000 --- a/src/main/kotlin/features/texturepack/predicates/ItemPredicate.kt +++ /dev/null @@ -1,34 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonElement -import com.google.gson.JsonPrimitive -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -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/features/texturepack/predicates/LorePredicate.kt b/src/main/kotlin/features/texturepack/predicates/LorePredicate.kt deleted file mode 100644 index f0b4737..0000000 --- a/src/main/kotlin/features/texturepack/predicates/LorePredicate.kt +++ /dev/null @@ -1,22 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonElement -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -import moe.nea.firmament.features.texturepack.StringMatcher -import net.minecraft.item.ItemStack -import moe.nea.firmament.util.mc.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/features/texturepack/predicates/NotPredicate.kt b/src/main/kotlin/features/texturepack/predicates/NotPredicate.kt deleted file mode 100644 index 4986ad9..0000000 --- a/src/main/kotlin/features/texturepack/predicates/NotPredicate.kt +++ /dev/null @@ -1,21 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import moe.nea.firmament.features.texturepack.CustomModelOverrideParser -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -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/features/texturepack/predicates/NumberMatcher.kt b/src/main/kotlin/features/texturepack/predicates/NumberMatcher.kt deleted file mode 100644 index b0d5178..0000000 --- a/src/main/kotlin/features/texturepack/predicates/NumberMatcher.kt +++ /dev/null @@ -1,124 +0,0 @@ -package moe.nea.firmament.features.texturepack.predicates - -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? { - return operatorPattern.useMatch(string) { - val operatorName = group("operator") - val operator = Operator.entries.find { it.operator == operatorName }!! - val value = group("value").toDouble() - OperatorMatcher(operator, value) - } - } - - 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/features/texturepack/predicates/OrPredicate.kt b/src/main/kotlin/features/texturepack/predicates/OrPredicate.kt deleted file mode 100644 index e3093cd..0000000 --- a/src/main/kotlin/features/texturepack/predicates/OrPredicate.kt +++ /dev/null @@ -1,29 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonArray -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import moe.nea.firmament.features.texturepack.CustomModelOverrideParser -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -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/features/texturepack/predicates/PetPredicate.kt b/src/main/kotlin/features/texturepack/predicates/PetPredicate.kt deleted file mode 100644 index b30b7c9..0000000 --- a/src/main/kotlin/features/texturepack/predicates/PetPredicate.kt +++ /dev/null @@ -1,66 +0,0 @@ - -package moe.nea.firmament.features.texturepack.predicates - -import com.google.gson.JsonElement -import com.google.gson.JsonObject -import moe.nea.firmament.features.texturepack.FirmamentModelPredicate -import moe.nea.firmament.features.texturepack.FirmamentModelPredicateParser -import moe.nea.firmament.features.texturepack.RarityMatcher -import moe.nea.firmament.features.texturepack.StringMatcher -import net.minecraft.item.ItemStack -import moe.nea.firmament.repo.ExpLadders -import moe.nea.firmament.util.petData - -data 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, - ) - } - } -} |