Add custom model predicates
Add regex support Add and and or predicates
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
* SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
import moe.nea.licenseextractificator.LicenseDiscoveryTask
|
import moe.nea.licenseextractificator.LicenseDiscoveryTask
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
@@ -149,8 +153,14 @@ dependencies {
|
|||||||
transInclude.resolvedConfiguration.resolvedArtifacts.forEach {
|
transInclude.resolvedConfiguration.resolvedArtifacts.forEach {
|
||||||
include(it.moduleVersion.id.toString())
|
include(it.moduleVersion.id.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
version = rootProject.property("mod_version").toString()
|
version = rootProject.property("mod_version").toString()
|
||||||
group = rootProject.property("maven_group").toString()
|
group = rootProject.property("maven_group").toString()
|
||||||
@@ -187,11 +197,6 @@ tasks.jar {
|
|||||||
tasks.shadowJar {
|
tasks.shadowJar {
|
||||||
configurations = listOf(shadowMe)
|
configurations = listOf(shadowMe)
|
||||||
archiveClassifier.set("dev")
|
archiveClassifier.set("dev")
|
||||||
doLast {
|
|
||||||
configurations.forEach {
|
|
||||||
println("Copying files into jar: ${it.files}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
relocate("io.github.moulberry.repo", "moe.nea.firmament.deps.repo")
|
relocate("io.github.moulberry.repo", "moe.nea.firmament.deps.repo")
|
||||||
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
|
destinationDirectory.set(layout.buildDirectory.dir("badjars"))
|
||||||
}
|
}
|
||||||
@@ -205,10 +210,10 @@ tasks.remapJar {
|
|||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
val replacements = listOf(
|
val replacements = listOf(
|
||||||
"version" to project.version,
|
"version" to project.version.toString(),
|
||||||
"minecraft_version" to libs.versions.minecraft.get(),
|
"minecraft_version" to libs.versions.minecraft.get(),
|
||||||
"fabric_kotlin_version" to libs.versions.fabric.kotlin.get()
|
"fabric_kotlin_version" to libs.versions.fabric.kotlin.get()
|
||||||
).map { (k, v) -> k to v.toString() }
|
)
|
||||||
replacements.forEach { (key, value) -> inputs.property(key, value) }
|
replacements.forEach { (key, value) -> inputs.property(key, value) }
|
||||||
filesMatching("**/fabric.mod.json") {
|
filesMatching("**/fabric.mod.json") {
|
||||||
expand(*replacements.toTypedArray())
|
expand(*replacements.toTypedArray())
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>()
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* 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
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
@@ -9,6 +10,7 @@ package moe.nea.firmament.features
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import moe.nea.firmament.Firmament
|
import moe.nea.firmament.Firmament
|
||||||
|
import moe.nea.firmament.events.FeaturesInitializedEvent
|
||||||
import moe.nea.firmament.features.chat.AutoCompletions
|
import moe.nea.firmament.features.chat.AutoCompletions
|
||||||
import moe.nea.firmament.features.chat.ChatLinks
|
import moe.nea.firmament.features.chat.ChatLinks
|
||||||
import moe.nea.firmament.features.chat.QuickCommands
|
import moe.nea.firmament.features.chat.QuickCommands
|
||||||
@@ -76,6 +78,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
|||||||
loadFeature(DebugView)
|
loadFeature(DebugView)
|
||||||
}
|
}
|
||||||
allFeatures.forEach { it.config }
|
allFeatures.forEach { it.config }
|
||||||
|
FeaturesInitializedEvent.publish(FeaturesInitializedEvent(allFeatures.toList()))
|
||||||
hasAutoloaded = true
|
hasAutoloaded = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>?)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
|
|||||||
import net.minecraft.block.SkullBlock
|
import net.minecraft.block.SkullBlock
|
||||||
import net.minecraft.client.MinecraftClient
|
import net.minecraft.client.MinecraftClient
|
||||||
import net.minecraft.client.render.RenderLayer
|
import net.minecraft.client.render.RenderLayer
|
||||||
import net.minecraft.client.texture.PlayerSkinProvider
|
|
||||||
import net.minecraft.client.util.ModelIdentifier
|
import net.minecraft.client.util.ModelIdentifier
|
||||||
import net.minecraft.util.Identifier
|
import net.minecraft.util.Identifier
|
||||||
import moe.nea.firmament.events.CustomItemModelEvent
|
import moe.nea.firmament.events.CustomItemModelEvent
|
||||||
@@ -33,6 +32,7 @@ object CustomSkyBlockTextures : FirmamentFeature {
|
|||||||
val enabled by toggle("enabled") { true }
|
val enabled by toggle("enabled") { true }
|
||||||
val skullsEnabled by toggle("skulls-enabled") { true }
|
val skullsEnabled by toggle("skulls-enabled") { true }
|
||||||
val cacheDuration by integer("cache-duration", 0, 20) { 1 }
|
val cacheDuration by integer("cache-duration", 0, 20) { 1 }
|
||||||
|
val enableModelOverrides by toggle("model-overrides") { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val config: ManagedConfig
|
override val config: ManagedConfig
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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)}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>?)
|
||||||
|
}
|
||||||
@@ -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:")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
|
* 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
|
* 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
|
val Text.unformattedString: String
|
||||||
get() = string.replace("§.".toRegex(), "")
|
get() = string.removeColorCodes().toString()
|
||||||
|
|
||||||
|
|
||||||
fun Text.transformEachRecursively(function: (Text) -> Text): Text {
|
fun Text.transformEachRecursively(function: (Text) -> Text): Text {
|
||||||
|
|||||||
@@ -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/network/ClientPlayNetworkHandler lastSeenMessagesCollector Lnet/minecraft/network/message/LastSeenMessagesCollector;
|
||||||
accessible field net/minecraft/client/gui/hud/InGameHud SCOREBOARD_ENTRY_COMPARATOR Ljava/util/Comparator;
|
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
|
||||||
|
|||||||
28
src/test/kotlin/moe/nea/firmament/test/ColorCode.kt
Normal file
28
src/test/kotlin/moe/nea/firmament/test/ColorCode.kt
Normal file
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user