diff options
Diffstat (limited to 'src')
23 files changed, 605 insertions, 3 deletions
| diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/BakedOverrideDataHolder.java b/src/main/java/moe/nea/firmament/mixins/custommodels/BakedOverrideDataHolder.java new file mode 100644 index 0000000..5e5f863 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/BakedOverrideDataHolder.java @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.mixins.custommodels; + +import moe.nea.firmament.features.texturepack.BakedOverrideData; +import moe.nea.firmament.features.texturepack.FirmamentModelPredicate; +import net.minecraft.client.render.model.json.ModelOverrideList; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(ModelOverrideList.BakedOverride.class) +public class BakedOverrideDataHolder implements BakedOverrideData { + +    @Unique +    private FirmamentModelPredicate[] firmamentOverrides; + +    @Nullable +    @Override +    public FirmamentModelPredicate[] getFirmamentOverrides() { +        return firmamentOverrides; +    } + +    @Override +    public void setFirmamentOverrides(@NotNull FirmamentModelPredicate[] overrides) { +        this.firmamentOverrides = overrides; +    } +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ModelOverrideDataHolder.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ModelOverrideDataHolder.java new file mode 100644 index 0000000..8a476db --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ModelOverrideDataHolder.java @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.mixins.custommodels; + +import moe.nea.firmament.features.texturepack.FirmamentModelPredicate; +import moe.nea.firmament.features.texturepack.ModelOverrideData; +import net.minecraft.client.render.model.json.ModelOverride; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(ModelOverride.class) +public class ModelOverrideDataHolder implements ModelOverrideData { + +    @Unique +    private FirmamentModelPredicate[] overrides; + +    @Nullable +    @Override +    public FirmamentModelPredicate[] getFirmamentOverrides() { +        return overrides; +    } + +    @Override +    public void setFirmamentOverrides(@NotNull FirmamentModelPredicate[] overrides) { +        this.overrides = overrides; +    } +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java new file mode 100644 index 0000000..e85bff0 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchOverrideDeserializer.java @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.mixins.custommodels; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.sugar.Local; +import moe.nea.firmament.features.texturepack.CustomModelOverrideParser; +import moe.nea.firmament.features.texturepack.ModelOverrideData; +import net.minecraft.client.render.model.json.ModelOverride; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; +import java.util.Map; + +@Mixin(ModelOverride.Deserializer.class) +public class PatchOverrideDeserializer { + +    @ModifyReturnValue( +        method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/ModelOverride;", +        at = @At(value = "RETURN")) +    private ModelOverride addCustomOverrides(ModelOverride original, @Local JsonObject jsonObject) { +        var originalData = (ModelOverrideData) original; +        originalData.setFirmamentOverrides(CustomModelOverrideParser.parseCustomModelOverrides(jsonObject)); +        return original; +    } + +    @ModifyExpressionValue( +        method = "deserializeMinPropertyValues(Lcom/google/gson/JsonObject;)Ljava/util/List;", +        at = @At(value = "INVOKE", target = "Ljava/util/Map$Entry;getValue()Ljava/lang/Object;")) +    private Object removeFirmamentPredicatesFromJsonIteration(Object original, @Local Map.Entry<String, JsonElement> entry) { +        if (entry.getKey().startsWith("firmament:")) return new JsonPrimitive(0F); +        return original; +    } + +    @Inject( +        method = "deserializeMinPropertyValues", +        at = @At(value = "INVOKE", target = "Ljava/util/Map;entrySet()Ljava/util/Set;") +    ) +    private void whatever(JsonObject object, CallbackInfoReturnable<List<ModelOverride.Condition>> cir, +                          @Local Map<Identifier, Float> maps) { +        maps.entrySet().removeIf(it -> it.getKey().getNamespace().equals("firmament")); +    } +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java new file mode 100644 index 0000000..4db9fc0 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/TestForFirmamentOverridePredicatesPatch.java @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.mixins.custommodels; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; +import moe.nea.firmament.features.texturepack.BakedOverrideData; +import moe.nea.firmament.features.texturepack.FirmamentModelPredicate; +import moe.nea.firmament.features.texturepack.ModelOverrideData; +import net.minecraft.client.render.model.json.ModelOverride; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +@Mixin(ModelOverrideList.class) +public class TestForFirmamentOverridePredicatesPatch { + +    @ModifyArg(method = "<init>(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/List;)V", +        at = @At( +            value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z" +        )) +    public Object onInit( +        Object element, +        @Local ModelOverride modelOverride +    ) { +        var bakedOverride = (ModelOverrideList.BakedOverride) element; +        ((BakedOverrideData) bakedOverride) +            .setFirmamentOverrides(((ModelOverrideData) modelOverride).getFirmamentOverrides()); +        return element; +    } + +    @ModifyExpressionValue(method = "apply", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;test([F)Z")) +    public boolean testFirmamentOverrides(boolean originalValue, +                                          @Local ModelOverrideList.BakedOverride bakedOverride, +                                          @Local ItemStack stack) { +        if (!originalValue) return false; +        var overrideData = (BakedOverrideData) bakedOverride; +        var overrides = overrideData.getFirmamentOverrides(); +        if (overrides == null) return true; +        for (FirmamentModelPredicate firmamentOverride : overrides) { +            if (!firmamentOverride.test(stack)) +                return false; +        } +        return true; +    } +} diff --git a/src/main/kotlin/moe/nea/firmament/events/FeaturesInitializedEvent.kt b/src/main/kotlin/moe/nea/firmament/events/FeaturesInitializedEvent.kt new file mode 100644 index 0000000..da18568 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/events/FeaturesInitializedEvent.kt @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.events + +import moe.nea.firmament.features.FirmamentFeature + +data class FeaturesInitializedEvent(val features: List<FirmamentFeature>) : FirmamentEvent() { +    companion object : FirmamentEventBus<FeaturesInitializedEvent>() +} diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt index 99f84e6..5e7f612 100644 --- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt +++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt @@ -1,5 +1,6 @@  /*   * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>   *   * SPDX-License-Identifier: GPL-3.0-or-later   */ @@ -9,6 +10,7 @@ package moe.nea.firmament.features  import kotlinx.serialization.Serializable  import kotlinx.serialization.serializer  import moe.nea.firmament.Firmament +import moe.nea.firmament.events.FeaturesInitializedEvent  import moe.nea.firmament.features.chat.AutoCompletions  import moe.nea.firmament.features.chat.ChatLinks  import moe.nea.firmament.features.chat.QuickCommands @@ -76,6 +78,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature                  loadFeature(DebugView)              }              allFeatures.forEach { it.config } +            FeaturesInitializedEvent.publish(FeaturesInitializedEvent(allFeatures.toList()))              hasAutoloaded = true          }      } diff --git a/src/main/kotlin/moe/nea/firmament/features/notifications/Notifications.kt b/src/main/kotlin/moe/nea/firmament/features/notifications/Notifications.kt new file mode 100644 index 0000000..1f3a572 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/notifications/Notifications.kt @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.features.notifications + +import moe.nea.firmament.features.FirmamentFeature + +object Notifications  { +} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt new file mode 100644 index 0000000..5ad023e --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/AndPredicate.kt @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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/BakedOverrideData.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt new file mode 100644 index 0000000..8ed8402 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/BakedOverrideData.kt @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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/CustomModelOverrideParser.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt new file mode 100644 index 0000000..ac62eaa --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomModelOverrideParser.kt @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.features.texturepack + +import com.google.gson.JsonObject +import net.minecraft.util.Identifier + +object CustomModelOverrideParser { + +    val predicateParsers = mutableMapOf<Identifier, FirmamentModelPredicateParser>() + + +    fun registerPredicateParser(name: String, parser: FirmamentModelPredicateParser) { +        predicateParsers[Identifier("firmament", name)] = parser +    } + +    init { +        registerPredicateParser("display_name", DisplayNamePredicate.Parser) +        registerPredicateParser("lore", LorePredicate.Parser) +        registerPredicateParser("all", AndPredicate.Parser) +        registerPredicateParser("any", OrPredicate.Parser) +    } + +    fun parsePredicates(predicates: JsonObject): List<FirmamentModelPredicate> { +        val parsedPredicates = mutableListOf<FirmamentModelPredicate>() +        for (predicateName in predicates.keySet()) { +            if (!predicateName.startsWith("firmament:")) continue +            val identifier = Identifier(predicateName) +            val parser = predicateParsers[identifier] ?: continue +            val parsedPredicate = parser.parse(predicates[predicateName]) +            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 index 64dec99..66c0036 100644 --- a/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/CustomSkyBlockTextures.kt @@ -13,7 +13,6 @@ 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.texture.PlayerSkinProvider  import net.minecraft.client.util.ModelIdentifier  import net.minecraft.util.Identifier  import moe.nea.firmament.events.CustomItemModelEvent @@ -33,6 +32,7 @@ object CustomSkyBlockTextures : FirmamentFeature {          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 }      }      override val config: ManagedConfig diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt new file mode 100644 index 0000000..373910a --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/DisplayNamePredicate.kt @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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 + +data class DisplayNamePredicate(val stringMatcher: StringMatcher) : FirmamentModelPredicate { +    override fun test(stack: ItemStack): Boolean { +        val display = stack.getOrCreateSubNbt(ItemStack.DISPLAY_KEY) +        return if (display.contains(ItemStack.NAME_KEY, NbtElement.STRING_TYPE.toInt())) +            stringMatcher.matches(display.get(ItemStack.NAME_KEY) as NbtString) +        else +            false +    } + +    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/FirmamentModelPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt new file mode 100644 index 0000000..8dcdaf3 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicate.kt @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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 new file mode 100644 index 0000000..de7557a --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/FirmamentModelPredicateParser.kt @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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/LorePredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt new file mode 100644 index 0000000..604d29c --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/LorePredicate.kt @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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 + +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 display = stack.getOrCreateSubNbt(ItemStack.DISPLAY_KEY) +        if (!display.contains(ItemStack.LORE_KEY, NbtElement.LIST_TYPE.toInt())) +            return false +        val lore = display.getList(ItemStack.LORE_KEY, NbtElement.STRING_TYPE.toInt()) +        return lore.any { matcher.matches(it as NbtString)} +    } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt new file mode 100644 index 0000000..ff68c94 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideData.kt @@ -0,0 +1,12 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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 new file mode 100644 index 0000000..c8cacbd --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/ModelOverrideFilterSet.kt @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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/OrPredicate.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt new file mode 100644 index 0000000..c171367 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/OrPredicate.kt @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +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 AndPredicate(children) +        } + +    } +} diff --git a/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt b/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt new file mode 100644 index 0000000..0fb8e00 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/features/texturepack/StringMatcher.kt @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.features.texturepack + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import java.util.function.Predicate +import net.minecraft.nbt.NbtString +import net.minecraft.text.Text +import moe.nea.firmament.util.removeColorCodes + +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) ?: 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) +        } +    } + +    class Pattern(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) +        } +    } + +    companion object { +        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["text"] 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") +        } +    } +} diff --git a/src/main/kotlin/moe/nea/firmament/util/filter/IteratorFilterSet.kt b/src/main/kotlin/moe/nea/firmament/util/filter/IteratorFilterSet.kt new file mode 100644 index 0000000..61d6524 --- /dev/null +++ b/src/main/kotlin/moe/nea/firmament/util/filter/IteratorFilterSet.kt @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.util.filter + +abstract class IteratorFilterSet<K>(val original: java.util.Set<K>) : java.util.Set<K> by original { +    abstract fun shouldKeepElement(element: K): Boolean + +    override fun iterator(): MutableIterator<K> { +        val parentIterator = original.iterator() +        return object : MutableIterator<K> { +            var lastEntry: K? = null +            override fun hasNext(): Boolean { +                while (lastEntry == null) { +                    if (!parentIterator.hasNext()) +                        break +                    val element = parentIterator.next() +                    if (!shouldKeepElement(element)) continue +                    lastEntry = element +                } +                return lastEntry != null +            } + +            override fun next(): K { +                if (!hasNext()) throw NoSuchElementException() +                return lastEntry ?: throw NoSuchElementException() +            } + +            override fun remove() { +                TODO("Not yet implemented") +            } +        } +    } +} + diff --git a/src/main/kotlin/moe/nea/firmament/util/textutil.kt b/src/main/kotlin/moe/nea/firmament/util/textutil.kt index f811bd8..1d61332 100644 --- a/src/main/kotlin/moe/nea/firmament/util/textutil.kt +++ b/src/main/kotlin/moe/nea/firmament/util/textutil.kt @@ -1,5 +1,6 @@  /*   * SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe> + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>   *   * SPDX-License-Identifier: GPL-3.0-or-later   */ @@ -69,9 +70,30 @@ class TextMatcher(text: Text) {      }  } +val formattingChars = "kmolnrKMOLNR".toSet() +fun CharSequence.removeColorCodes(keepNonColorCodes: Boolean = false): String { +    var nextParagraph = indexOf('§') +    if (nextParagraph < 0) return this.toString() +    val stringBuffer = StringBuilder(this.length) +    var readIndex = 0 +    while (nextParagraph >= 0) { +        stringBuffer.append(this, readIndex, nextParagraph) +        if (keepNonColorCodes && nextParagraph + 1 < length && this[nextParagraph + 1] in formattingChars) { +            readIndex = nextParagraph +            nextParagraph = indexOf('§', startIndex = readIndex + 1) +        } else { +            readIndex = nextParagraph + 2 +            nextParagraph = indexOf('§', startIndex = readIndex) +        } +        if (readIndex > this.length) +            readIndex = this.length +    } +    stringBuffer.append(this, readIndex, this.length) +    return stringBuffer.toString() +} -val Text.unformattedString -    get() = string.replace("§.".toRegex(), "") +val Text.unformattedString: String +    get() = string.removeColorCodes().toString()  fun Text.transformEachRecursively(function: (Text) -> Text): Text { diff --git a/src/main/resources/firmament.accesswidener b/src/main/resources/firmament.accesswidener index 9f1b44b..92f4fe4 100644 --- a/src/main/resources/firmament.accesswidener +++ b/src/main/resources/firmament.accesswidener @@ -8,3 +8,5 @@ accessible method net/minecraft/client/render/model/ModelLoader$BakerImpl <init>  accessible field net/minecraft/client/network/ClientPlayNetworkHandler lastSeenMessagesCollector Lnet/minecraft/network/message/LastSeenMessagesCollector;  accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator; +accessible class net/minecraft/client/render/model/json/ModelOverride$Deserializer +accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride diff --git a/src/test/kotlin/moe/nea/firmament/test/ColorCode.kt b/src/test/kotlin/moe/nea/firmament/test/ColorCode.kt new file mode 100644 index 0000000..737534e --- /dev/null +++ b/src/test/kotlin/moe/nea/firmament/test/ColorCode.kt @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe> + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +package moe.nea.firmament.test + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import moe.nea.firmament.util.removeColorCodes + + +class ColorCode { +    @Test +    fun testWhatever() { +        Assertions.assertEquals("", "".removeColorCodes().toString()) +        Assertions.assertEquals("", "§".removeColorCodes().toString()) +        Assertions.assertEquals("", "§a".removeColorCodes().toString()) +        Assertions.assertEquals("ab", "a§ab".removeColorCodes().toString()) +        Assertions.assertEquals("ab", "a§ab§§".removeColorCodes().toString()) +        Assertions.assertEquals("abc", "a§ab§§c".removeColorCodes().toString()) +        Assertions.assertEquals("bc", "§ab§§c".removeColorCodes().toString()) +        Assertions.assertEquals("b§lc", "§ab§l§§c".removeColorCodes(true).toString()) +        Assertions.assertEquals("b§lc§l", "§ab§l§§c§l".removeColorCodes(true).toString()) +        Assertions.assertEquals("§lb§lc", "§l§ab§l§§c".removeColorCodes(true).toString()) +    } +} | 
