diff options
29 files changed, 466 insertions, 156 deletions
diff --git a/docs/Texture Pack Format.md b/docs/Texture Pack Format.md index 23dd7a1..b52c038 100644 --- a/docs/Texture Pack Format.md +++ b/docs/Texture Pack Format.md @@ -40,6 +40,41 @@ head model. } ``` +## Tint Overrides + +Some items get naturally tinted by Minecraft's rendering. Examples include leather armour, spawn eggs, potions and more. +If you want to avoid your textures getting tinted, one thing you can do is use a higher texture layer: + +```json +{ + "parent": "minecraft:item/generated", + "textures": { + // Notice the layer1 instead of layer0 here + "layer1": "firmskyblock:item/regular_texture" + } +} +``` + +Some items, however, tint *all* layers. For those items you can instead specify a tint override: + +```json +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "firmskyblock:item/regular_texture" + }, + "firmament:tint_overrides": { + "0": -1 + } +} +``` + +This forces layer 0 to be tinted with the color `-1` (pure white, aka no tint). This property is inherited, so if you +attach it to one of your root models that you `"parent"` other models to, all those models will have their tints +overridden. When the property is inherited, only layers specified in the child actually overwrite the parent layers. +You can use `"0": null` to remove the tint override in a child, which will cause a fallback to the vanilla tinting +behaviour. + ## Predicates Firmament adds the ability for more complex [item model predicates](https://minecraft.wiki/w/Tutorials/Models#Item_predicates). diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d3842d4..c11d939 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -129,7 +129,7 @@ runtime_required = [ runtime_optional = [ "devauth", # "freecammod", - "sodium", +# "sodium", # "qolify", "ncr", "citresewn", diff --git a/src/main/java/moe/nea/firmament/init/EarlyRiser.java b/src/main/java/moe/nea/firmament/init/EarlyRiser.java index 5eab563..9734e94 100644 --- a/src/main/java/moe/nea/firmament/init/EarlyRiser.java +++ b/src/main/java/moe/nea/firmament/init/EarlyRiser.java @@ -7,5 +7,6 @@ public class EarlyRiser implements Runnable { new ClientPlayerRiser().addTinkerers(); new HandledScreenRiser().addTinkerers(); new SectionBuilderRiser().addTinkerers(); + new ItemColorsSodiumRiser().addTinkerers(); } } diff --git a/src/main/java/moe/nea/firmament/init/ItemColorsSodiumRiser.java b/src/main/java/moe/nea/firmament/init/ItemColorsSodiumRiser.java new file mode 100644 index 0000000..80ee9aa --- /dev/null +++ b/src/main/java/moe/nea/firmament/init/ItemColorsSodiumRiser.java @@ -0,0 +1,64 @@ +package moe.nea.firmament.init; + +import me.shedaniel.mm.api.ClassTinkerers; +import moe.nea.firmament.util.ErrorUtil; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.client.color.item.ItemColors; +import net.minecraft.item.ItemStack; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.VarInsnNode; + +public class ItemColorsSodiumRiser extends RiserUtils { + @IntermediaryName(ItemColors.class) + String ItemColors; + @IntermediaryName(ItemColorProvider.class) + String ItemColorProvider; + @IntermediaryName(ItemStack.class) + String ItemStack; + String getColorProvider = "sodium$getColorProvider"; + Type getColorProviderDesc = Type.getMethodType(getTypeForClassName(ItemColorProvider), + getTypeForClassName(ItemStack)); + + @Override + public void addTinkerers() { + ClassTinkerers.addTransformation(ItemColors, this::addSodiumOverride, true); + } + + private void addSodiumOverride(ClassNode classNode) { + var node = findMethod(classNode, getColorProvider, getColorProviderDesc); + if (node == null) { + if (!FabricLoader.getInstance().isModLoaded("sodium")) + ErrorUtil.INSTANCE.softError("Sodium is present, but sodium color override could not be injected."); + return; + } + var p = node.instructions.getFirst(); + while (p != null) { + if (p.getOpcode() == Opcodes.ARETURN) { + node.instructions.insertBefore( + p, + mkOverrideSodiumCall() + ); + } + p = p.getNext(); + } + } + + private InsnList mkOverrideSodiumCall() { + var insnList = new InsnList(); + insnList.add(new VarInsnNode(Opcodes.ALOAD, 0)); + insnList.add(new InsnNode(Opcodes.SWAP)); + insnList.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, + getTypeForClassName(ItemColors).getInternalName(), + "overrideSodium_firmament", + Type.getMethodType(getTypeForClassName(ItemColorProvider), + getTypeForClassName(ItemColorProvider)).getDescriptor(), + false)); + return insnList; + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBasic.java b/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBasic.java index 7bf3732..3ed2177 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBasic.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBasic.java @@ -2,6 +2,7 @@ package moe.nea.firmament.mixins.custommodels; import moe.nea.firmament.features.texturepack.BakedModelExtra; +import moe.nea.firmament.features.texturepack.TintOverrides; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BasicBakedModel; import org.jetbrains.annotations.Nullable; @@ -11,18 +12,31 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(BasicBakedModel.class) public class BakedModelDataHolderBasic implements BakedModelExtra { - @Unique - private BakedModel headModel; + @Unique + private BakedModel headModel; + @Unique + @Nullable + private TintOverrides tintOverrides; - @Nullable - @Override - public BakedModel getHeadModel_firmament() { - return headModel; - } + @Nullable + @Override + public BakedModel getHeadModel_firmament() { + return headModel; + } - @Override - public void setHeadModel_firmament(@Nullable BakedModel headModel) { - this.headModel = headModel; - } + @Override + public void setHeadModel_firmament(@Nullable BakedModel headModel) { + this.headModel = headModel; + } + + @Override + public @Nullable TintOverrides getTintOverrides_firmament() { + return tintOverrides; + } + + @Override + public void setTintOverrides_firmament(@Nullable TintOverrides tintOverrides) { + this.tintOverrides = tintOverrides; + } } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBuiltin.java b/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBuiltin.java index 76300a1..87aecb1 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBuiltin.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/BakedModelDataHolderBuiltin.java @@ -2,6 +2,7 @@ package moe.nea.firmament.mixins.custommodels; import moe.nea.firmament.features.texturepack.BakedModelExtra; +import moe.nea.firmament.features.texturepack.TintOverrides; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.BuiltinBakedModel; import org.jetbrains.annotations.Nullable; @@ -11,18 +12,32 @@ import org.spongepowered.asm.mixin.Unique; @Mixin(BuiltinBakedModel.class) public class BakedModelDataHolderBuiltin implements BakedModelExtra { - @Unique - private BakedModel headModel; + @Unique + @Nullable + private BakedModel headModel; + @Unique + @Nullable + private TintOverrides tintOverrides; - @Nullable - @Override - public BakedModel getHeadModel_firmament() { - return headModel; - } + @Override + public @Nullable TintOverrides getTintOverrides_firmament() { + return tintOverrides; + } - @Override - public void setHeadModel_firmament(@Nullable BakedModel headModel) { - this.headModel = headModel; - } + @Override + public void setTintOverrides_firmament(@Nullable TintOverrides tintOverrides) { + this.tintOverrides = tintOverrides; + } + + @Nullable + @Override + public BakedModel getHeadModel_firmament() { + return headModel; + } + + @Override + public void setHeadModel_firmament(@Nullable BakedModel headModel) { + this.headModel = headModel; + } } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemColorRemovalPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemColorRemovalPatch.java new file mode 100644 index 0000000..8c76c60 --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemColorRemovalPatch.java @@ -0,0 +1,39 @@ +package moe.nea.firmament.mixins.custommodels; + +import moe.nea.firmament.features.texturepack.TintOverrides; +import moe.nea.firmament.init.ItemColorsSodiumRiser; +import net.minecraft.client.color.item.ItemColorProvider; +import net.minecraft.client.color.item.ItemColors; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; +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; + +@Mixin(ItemColors.class) +public class ItemColorRemovalPatch { + + /** + * @see ItemColorsSodiumRiser + */ + private @Nullable ItemColorProvider overrideSodium_firmament(@Nullable ItemColorProvider original) { + var tintOverrides = TintOverrides.Companion.getCurrentOverrides(); + if (!tintOverrides.hasOverrides()) return original; + return (stack, tintIndex) -> { + var override = tintOverrides.getOverride(tintIndex); + if (override != null) return override; + if (original != null) return original.getColor(stack, tintIndex); + return -1; + }; + } + + + @Inject(method = "getColor", at = @At("HEAD"), cancellable = true) + private void overrideGetColorCall(ItemStack item, int tintIndex, CallbackInfoReturnable<Integer> cir) { + var tintOverrides = TintOverrides.Companion.getCurrentOverrides(); + var override = tintOverrides.getOverride(tintIndex); + if (override != null) + cir.setReturnValue(override); + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemModelGeneratorJsonUnbakedModelCopy.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemModelGeneratorJsonUnbakedModelCopy.java index c897441..89d0411 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemModelGeneratorJsonUnbakedModelCopy.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemModelGeneratorJsonUnbakedModelCopy.java @@ -12,8 +12,11 @@ import org.spongepowered.asm.mixin.injection.At; @Mixin(ItemModelGenerator.class) public class ItemModelGeneratorJsonUnbakedModelCopy { @ModifyReturnValue(method = "create", at = @At("RETURN")) - private JsonUnbakedModel copyHeadModel(JsonUnbakedModel original, @Local(argsOnly = true) JsonUnbakedModel oldModel) { - ((JsonUnbakedModelFirmExtra) original).setHeadModel_firmament(((JsonUnbakedModelFirmExtra) oldModel).getHeadModel_firmament()); + private JsonUnbakedModel copyExtraModelData(JsonUnbakedModel original, @Local(argsOnly = true) JsonUnbakedModel oldModel) { + var extra = ((JsonUnbakedModelFirmExtra) original); + var oldExtra = ((JsonUnbakedModelFirmExtra) oldModel); + extra.setHeadModel_firmament(oldExtra.getHeadModel_firmament()); + extra.setTintOverrides_firmament(oldExtra.getTintOverrides_firmament()); return original; } } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java new file mode 100644 index 0000000..5ed0fbe --- /dev/null +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/ItemRendererTintContextPatch.java @@ -0,0 +1,33 @@ +package moe.nea.firmament.mixins.custommodels; + +import moe.nea.firmament.features.texturepack.BakedModelExtra; +import moe.nea.firmament.features.texturepack.TintOverrides; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelTransformationMode; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +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.CallbackInfo; + +@Mixin(ItemRenderer.class) +public class ItemRendererTintContextPatch { + @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/BakedModel;getTransformation()Lnet/minecraft/client/render/model/json/ModelTransformation;"), allow = 1) + private void onStartRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { + if (model instanceof BakedModelExtra extra) { + TintOverrides.Companion.enter(extra.getTintOverrides_firmament()); + } + } + + @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformationMode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V"), allow = 1) + private void onEndRendering(ItemStack stack, ModelTransformationMode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) { + if (model instanceof BakedModelExtra extra) { + TintOverrides.Companion.exit(extra.getTintOverrides_firmament()); + } + } +} diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java b/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java index 5fe3dec..20c69e2 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/JsonUnbakedModelDataHolder.java @@ -1,4 +1,3 @@ - package moe.nea.firmament.mixins.custommodels; import com.google.gson.annotations.SerializedName; @@ -6,12 +5,14 @@ import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.sugar.Local; import moe.nea.firmament.features.texturepack.BakedModelExtra; import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra; +import moe.nea.firmament.features.texturepack.TintOverrides; import net.minecraft.client.render.model.BakedModel; import net.minecraft.client.render.model.Baker; import net.minecraft.client.render.model.ModelRotation; import net.minecraft.client.render.model.UnbakedModel; import net.minecraft.client.render.model.json.JsonUnbakedModel; import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -23,46 +24,74 @@ import java.util.Objects; @Mixin(JsonUnbakedModel.class) public class JsonUnbakedModelDataHolder implements JsonUnbakedModelFirmExtra { - @Shadow - @Nullable - protected JsonUnbakedModel parent; - @Unique - @Nullable - public Identifier headModel; + @Shadow + @Nullable + protected JsonUnbakedModel parent; + @Unique + @Nullable + public Identifier headModel; + @Unique + @Nullable + public TintOverrides tintOverrides; + @Unique + @Nullable + public TintOverrides mergedTintOverrides; + + @Override + public void setTintOverrides_firmament(@Nullable TintOverrides tintOverrides) { + this.tintOverrides = tintOverrides; + this.mergedTintOverrides = null; + } + + @Override + public @NotNull TintOverrides getTintOverrides_firmament() { + if (mergedTintOverrides != null) + return mergedTintOverrides; + var mergedTintOverrides = parent == null ? new TintOverrides() + : ((JsonUnbakedModelFirmExtra) parent).getTintOverrides_firmament(); + if (tintOverrides != null) + mergedTintOverrides = tintOverrides.mergeWithParent(mergedTintOverrides); + this.mergedTintOverrides = mergedTintOverrides; + return mergedTintOverrides; + } - @Override - public void setHeadModel_firmament(@Nullable Identifier identifier) { - this.headModel = identifier; - } + @Override + public void setHeadModel_firmament(@Nullable Identifier identifier) { + this.headModel = identifier; + } - @Override - public @Nullable Identifier getHeadModel_firmament() { - if (this.headModel != null) return this.headModel; - if (this.parent == null) return null; - return ((JsonUnbakedModelFirmExtra) this.parent).getHeadModel_firmament(); - } + @Override + public @Nullable Identifier getHeadModel_firmament() { + if (this.headModel != null) return this.headModel; + if (this.parent == null) return null; + return ((JsonUnbakedModelFirmExtra) this.parent).getHeadModel_firmament(); + } - @ModifyReturnValue(method = "getModelDependencies", at = @At("RETURN")) - private Collection<Identifier> addDependencies(Collection<Identifier> original) { - var headModel = getHeadModel_firmament(); - if (headModel != null) { - original.add(headModel); - } - return original; - } + @ModifyReturnValue(method = "getModelDependencies", at = @At("RETURN")) + private Collection<Identifier> addDependencies(Collection<Identifier> original) { + var headModel = getHeadModel_firmament(); + if (headModel != null) { + original.add(headModel); + } + return original; + } - @ModifyReturnValue( - method = "bake(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;", - at = @At(value = "RETURN")) - private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) { - var headModel = getHeadModel_firmament(); - if (headModel != null && original instanceof BakedModelExtra extra) { - UnbakedModel unbakedModel = baker.getOrLoadModel(headModel); - extra.setHeadModel_firmament( - Objects.equals(unbakedModel, parent) - ? null - : baker.bake(headModel, ModelRotation.X0_Y0)); - } - return original; - } + @ModifyReturnValue( + method = "bake(Lnet/minecraft/client/render/model/Baker;Lnet/minecraft/client/render/model/json/JsonUnbakedModel;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Z)Lnet/minecraft/client/render/model/BakedModel;", + at = @At(value = "RETURN")) + private BakedModel bakeExtraInfo(BakedModel original, @Local(argsOnly = true) Baker baker) { + if (original instanceof BakedModelExtra extra) { + var headModel = getHeadModel_firmament(); + if (headModel != null) { + UnbakedModel unbakedModel = baker.getOrLoadModel(headModel); + extra.setHeadModel_firmament( + Objects.equals(unbakedModel, parent) + ? null + : baker.bake(headModel, ModelRotation.X0_Y0)); + } + if (getTintOverrides_firmament().hasOverrides()) + extra.setTintOverrides_firmament(getTintOverrides_firmament()); + } + return original; + } } diff --git a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchJsonUnbakedModelDeserializer.java b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchJsonUnbakedModelDeserializer.java index cd6fb17..d6c25b5 100644 --- a/src/main/java/moe/nea/firmament/mixins/custommodels/PatchJsonUnbakedModelDeserializer.java +++ b/src/main/java/moe/nea/firmament/mixins/custommodels/PatchJsonUnbakedModelDeserializer.java @@ -6,6 +6,7 @@ import com.google.gson.JsonPrimitive; import com.llamalad7.mixinextras.injector.ModifyReturnValue; import com.llamalad7.mixinextras.sugar.Local; import moe.nea.firmament.features.texturepack.JsonUnbakedModelFirmExtra; +import moe.nea.firmament.features.texturepack.TintOverrides; import net.minecraft.client.render.model.json.JsonUnbakedModel; import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; @@ -13,13 +14,18 @@ import org.spongepowered.asm.mixin.injection.At; @Mixin(JsonUnbakedModel.Deserializer.class) public class PatchJsonUnbakedModelDeserializer { - @ModifyReturnValue(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/JsonUnbakedModel;", - at = @At("RETURN")) - private JsonUnbakedModel addHeadModel(JsonUnbakedModel original, @Local JsonObject jsonObject) { - var headModel = jsonObject.get("firmament:head_model"); - if (headModel instanceof JsonPrimitive prim && prim.isString()) { - ((JsonUnbakedModelFirmExtra) original).setHeadModel_firmament(Identifier.of(prim.getAsString())); - } - return original; - } + @ModifyReturnValue(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/render/model/json/JsonUnbakedModel;", + at = @At("RETURN")) + private JsonUnbakedModel addHeadModel(JsonUnbakedModel original, @Local JsonObject jsonObject) { + var headModel = jsonObject.get("firmament:head_model"); + var extra = ((JsonUnbakedModelFirmExtra) original); + if (headModel instanceof JsonPrimitive prim && prim.isString()) { + extra.setHeadModel_firmament(Identifier.of(prim.getAsString())); + } + var tintOverrides = jsonObject.get("firmament:tint_overrides"); + if (tintOverrides instanceof JsonObject object) { + extra.setTintOverrides_firmament(TintOverrides.Companion.parse(object)); + } + return original; + } } diff --git a/src/main/kotlin/features/texturepack/BakedModelExtra.kt b/src/main/kotlin/features/texturepack/BakedModelExtra.kt index ae1f6d5..32f419a 100644 --- a/src/main/kotlin/features/texturepack/BakedModelExtra.kt +++ b/src/main/kotlin/features/texturepack/BakedModelExtra.kt @@ -4,6 +4,8 @@ package moe.nea.firmament.features.texturepack import net.minecraft.client.render.model.BakedModel interface BakedModelExtra { - fun getHeadModel_firmament(): BakedModel? + var tintOverrides_firmament: TintOverrides? + + fun getHeadModel_firmament(): BakedModel? fun setHeadModel_firmament(headModel: BakedModel?) } diff --git a/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt b/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt index a4e7c02..c5fc20b 100644 --- a/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt +++ b/src/main/kotlin/features/texturepack/CustomModelOverrideParser.kt @@ -6,6 +6,14 @@ 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 diff --git a/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt b/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt index ab9e27d..0d0f8f2 100644 --- a/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt +++ b/src/main/kotlin/features/texturepack/JsonUnbakedModelFirmExtra.kt @@ -7,4 +7,8 @@ interface JsonUnbakedModelFirmExtra { 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/ModelOverrideFilterSet.kt b/src/main/kotlin/features/texturepack/ModelOverrideFilterSet.kt deleted file mode 100644 index 4ef8d06..0000000 --- a/src/main/kotlin/features/texturepack/ModelOverrideFilterSet.kt +++ /dev/null @@ -1,19 +0,0 @@ - -package moe.nea.firmament.features.texturepack - -import com.google.gson.JsonElement -import moe.nea.firmament.util.filter.IteratorFilterSet - -class ModelOverrideFilterSet(original: java.util.Set<Map.Entry<String, JsonElement>>) : - IteratorFilterSet<Map.Entry<String, JsonElement>>(original) { - companion object { - @JvmStatic - fun createFilterSet(set: java.util.Set<*>): java.util.Set<*> { - return ModelOverrideFilterSet(set as java.util.Set<Map.Entry<String, JsonElement>>) as java.util.Set<*> - } - } - - override fun shouldKeepElement(element: Map.Entry<String, JsonElement>): Boolean { - return !element.key.startsWith("firmament:") - } -} diff --git a/src/main/kotlin/features/texturepack/TintOverrides.kt b/src/main/kotlin/features/texturepack/TintOverrides.kt new file mode 100644 index 0000000..8006db8 --- /dev/null +++ b/src/main/kotlin/features/texturepack/TintOverrides.kt @@ -0,0 +1,75 @@ +package moe.nea.firmament.features.texturepack + +import com.google.gson.JsonObject +import com.google.gson.JsonPrimitive +import moe.nea.firmament.util.ErrorUtil +import moe.nea.firmament.util.assertNotNullOr + +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() = + assertNotNullOr(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/AlwaysPredicate.kt b/src/main/kotlin/features/texturepack/predicates/AlwaysPredicate.kt index 4dd28df..7e0ddb1 100644 --- a/src/main/kotlin/features/texturepack/AlwaysPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/AlwaysPredicate.kt @@ -1,7 +1,9 @@ -package moe.nea.firmament.features.texturepack +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 { diff --git a/src/main/kotlin/features/texturepack/AndPredicate.kt b/src/main/kotlin/features/texturepack/predicates/AndPredicate.kt index dc8e852..99abaaa 100644 --- a/src/main/kotlin/features/texturepack/AndPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/AndPredicate.kt @@ -1,8 +1,11 @@ -package moe.nea.firmament.features.texturepack +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 { @@ -15,7 +18,7 @@ class AndPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentMode val children = (jsonElement as JsonArray) .flatMap { - CustomModelOverrideParser.parsePredicates(it as JsonObject) + CustomModelOverrideParser.parsePredicates(it as JsonObject) } .toTypedArray() return AndPredicate(children) diff --git a/src/main/kotlin/features/texturepack/DisplayNamePredicate.kt b/src/main/kotlin/features/texturepack/predicates/DisplayNamePredicate.kt index 100aaf4..04c7a2b 100644 --- a/src/main/kotlin/features/texturepack/DisplayNamePredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/DisplayNamePredicate.kt @@ -1,12 +1,12 @@ -package moe.nea.firmament.features.texturepack +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 net.minecraft.nbt.NbtElement -import net.minecraft.nbt.NbtString import moe.nea.firmament.util.mc.displayNameAccordingToNbt -import moe.nea.firmament.util.mc.loreAccordingToNbt data class DisplayNamePredicate(val stringMatcher: StringMatcher) : FirmamentModelPredicate { override fun test(stack: ItemStack): Boolean { diff --git a/src/main/kotlin/features/texturepack/ExtraAttributesPredicate.kt b/src/main/kotlin/features/texturepack/predicates/ExtraAttributesPredicate.kt index 4114f45..3c8023d 100644 --- a/src/main/kotlin/features/texturepack/ExtraAttributesPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/ExtraAttributesPredicate.kt @@ -1,10 +1,13 @@ -package moe.nea.firmament.features.texturepack +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 @@ -210,8 +213,8 @@ fun interface NbtMatcher { } data class ExtraAttributesPredicate( - val path: NbtPrism, - val matcher: NbtMatcher, + val path: NbtPrism, + val matcher: NbtMatcher, ) : FirmamentModelPredicate { object Parser : FirmamentModelPredicateParser { diff --git a/src/main/kotlin/features/texturepack/ItemPredicate.kt b/src/main/kotlin/features/texturepack/predicates/ItemPredicate.kt index 4302b53..3cb80c7 100644 --- a/src/main/kotlin/features/texturepack/ItemPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/ItemPredicate.kt @@ -1,8 +1,10 @@ -package moe.nea.firmament.features.texturepack +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 diff --git a/src/main/kotlin/features/texturepack/LorePredicate.kt b/src/main/kotlin/features/texturepack/predicates/LorePredicate.kt index f2b7e76..f0b4737 100644 --- a/src/main/kotlin/features/texturepack/LorePredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/LorePredicate.kt @@ -1,7 +1,10 @@ -package moe.nea.firmament.features.texturepack +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 diff --git a/src/main/kotlin/features/texturepack/NotPredicate.kt b/src/main/kotlin/features/texturepack/predicates/NotPredicate.kt index ecd67c3..4986ad9 100644 --- a/src/main/kotlin/features/texturepack/NotPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/NotPredicate.kt @@ -1,8 +1,11 @@ -package moe.nea.firmament.features.texturepack +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 { diff --git a/src/main/kotlin/features/texturepack/NumberMatcher.kt b/src/main/kotlin/features/texturepack/predicates/NumberMatcher.kt index e6f2d01..b0d5178 100644 --- a/src/main/kotlin/features/texturepack/NumberMatcher.kt +++ b/src/main/kotlin/features/texturepack/predicates/NumberMatcher.kt @@ -1,4 +1,4 @@ -package moe.nea.firmament.features.texturepack +package moe.nea.firmament.features.texturepack.predicates import com.google.gson.JsonElement import com.google.gson.JsonPrimitive diff --git a/src/main/kotlin/features/texturepack/OrPredicate.kt b/src/main/kotlin/features/texturepack/predicates/OrPredicate.kt index 32f556b..e3093cd 100644 --- a/src/main/kotlin/features/texturepack/OrPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/OrPredicate.kt @@ -1,9 +1,12 @@ -package moe.nea.firmament.features.texturepack +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 { @@ -16,7 +19,7 @@ class OrPredicate(val children: Array<FirmamentModelPredicate>) : FirmamentModel val children = (jsonElement as JsonArray) .flatMap { - CustomModelOverrideParser.parsePredicates(it as JsonObject) + CustomModelOverrideParser.parsePredicates(it as JsonObject) } .toTypedArray() return OrPredicate(children) diff --git a/src/main/kotlin/features/texturepack/PetPredicate.kt b/src/main/kotlin/features/texturepack/predicates/PetPredicate.kt index 5e5d750..b30b7c9 100644 --- a/src/main/kotlin/features/texturepack/PetPredicate.kt +++ b/src/main/kotlin/features/texturepack/predicates/PetPredicate.kt @@ -1,18 +1,22 @@ -package moe.nea.firmament.features.texturepack +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 -class PetPredicate( - val petId: StringMatcher?, - val tier: RarityMatcher?, - val exp: NumberMatcher?, - val candyUsed: NumberMatcher?, - val level: NumberMatcher?, +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 { @@ -59,8 +63,4 @@ class PetPredicate( ) } } - - override fun toString(): String { - return super.toString() - } } diff --git a/src/main/kotlin/repo/RepoManager.kt b/src/main/kotlin/repo/RepoManager.kt index 9f8f422..c052fb9 100644 --- a/src/main/kotlin/repo/RepoManager.kt +++ b/src/main/kotlin/repo/RepoManager.kt @@ -9,13 +9,13 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents import kotlinx.coroutines.launch import net.minecraft.client.MinecraftClient import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket -import net.minecraft.text.Text import moe.nea.firmament.Firmament import moe.nea.firmament.Firmament.logger import moe.nea.firmament.events.ReloadRegistrationEvent import moe.nea.firmament.gui.config.ManagedConfig import moe.nea.firmament.util.MinecraftDispatcher import moe.nea.firmament.util.SkyblockId +import moe.nea.firmament.util.tr object RepoManager { object Config : ManagedConfig("repo", Category.META) { @@ -108,12 +108,13 @@ object RepoManager { try { ItemCache.ReloadProgressHud.reportProgress("Reloading from Disk", 0, - -1) // TODO: replace with a proper boundy bar + -1) // TODO: replace with a proper bouncy bar ItemCache.ReloadProgressHud.isEnabled = true neuRepo.reload() } catch (exc: NEURepositoryException) { MinecraftClient.getInstance().player?.sendMessage( - Text.literal("Failed to reload repository. This will result in some mod features not working.") + tr("firmament.repo.reloadfail", + "Failed to reload repository. This will result in some mod features not working.") ) ItemCache.ReloadProgressHud.isEnabled = false exc.printStackTrace() diff --git a/src/main/kotlin/util/ErrorUtil.kt b/src/main/kotlin/util/ErrorUtil.kt index 4f229af..afecf25 100644 --- a/src/main/kotlin/util/ErrorUtil.kt +++ b/src/main/kotlin/util/ErrorUtil.kt @@ -7,10 +7,24 @@ object ErrorUtil { Thread.currentThread().stackTrace.any { it.className.startsWith("org.junit.") } || Firmament.DEBUG } + inline fun softCheck(message: String, func: () -> Boolean) { + if (!aggressiveErrors) return + if (func()) return + error(message) + } + @Suppress("NOTHING_TO_INLINE") // Suppressed since i want the logger to not pick up the ErrorUtil stack-frame inline fun softError(message: String) { if (aggressiveErrors) error(message) else Firmament.logger.error(message) } + inline fun <T : Any> notNullOr(nullable: T?, message: String, orElse: () -> T): T { + if (nullable == null) { + softError(message) + return orElse() + } + return nullable + } + } diff --git a/src/main/kotlin/util/filter/IteratorFilterSet.kt b/src/main/kotlin/util/filter/IteratorFilterSet.kt deleted file mode 100644 index 483b8d9..0000000 --- a/src/main/kotlin/util/filter/IteratorFilterSet.kt +++ /dev/null @@ -1,33 +0,0 @@ - -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") - } - } - } -} - |