aboutsummaryrefslogtreecommitdiff
path: root/defaults/src
diff options
context:
space:
mode:
Diffstat (limited to 'defaults/src')
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamage.java46
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamageMask.java38
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantmentLevels.java62
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantments.java59
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionHand.java49
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionItems.java75
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionNBT.java244
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionStackSize.java21
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeArmor.java111
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeElytra.java76
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeEnchantment.java528
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeItem.java520
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnItemModelIdentifier.java16
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnTextureIdentifier.java12
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfig.java50
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfigScreenFactory.java33
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsModMenu.java27
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/ModelLoaderMixin.java87
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/SpriteAtlasTextureMixin.java18
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ArmorFeatureRendererMixin.java51
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ItemStackMixin.java16
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ElytraFeatureRendererMixin.java42
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ItemStackMixin.java16
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ArmorFeatureRendererMixin.java30
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/BufferBuilderStorageAccessor.java15
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ElytraFeatureRendererMixin.java29
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemRendererMixin.java86
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemStackMixin.java25
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/MinecraftClientMixin.java16
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/RenderPhaseAccessor.java21
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/BakedModelManagerMixin.java29
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemRendererMixin.java68
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemStackMixin.java16
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/JsonUnbakedModelAccessor.java22
-rw-r--r--defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ModelLoaderMixin.java99
-rw-r--r--defaults/src/main/java/shcm/shsupercm/util/logic/Loops.java60
-rw-r--r--defaults/src/main/resources/assets/citresewn-defaults/lang/en_us.json7
-rw-r--r--defaults/src/main/resources/assets/citresewn-defaults/logo.pngbin0 -> 99334 bytes
-rw-r--r--defaults/src/main/resources/citresewn-defaults.accesswidener30
-rw-r--r--defaults/src/main/resources/citresewn-defaults.mixins.json9
-rw-r--r--defaults/src/main/resources/fabric.mod.json36
41 files changed, 2795 insertions, 0 deletions
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamage.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamage.java
new file mode 100644
index 0000000..c5c31f9
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamage.java
@@ -0,0 +1,46 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITCondition;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.IntegerCondition;
+
+import java.util.Set;
+
+public class ConditionDamage extends IntegerCondition {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionDamage> CONTAINER = new CITConditionContainer<>(ConditionDamage.class, ConditionDamage::new,
+ "damage");
+
+ protected Integer mask = null;
+
+ public ConditionDamage() {
+ super(true, false, true);
+ }
+
+ @Override
+ protected int getValue(CITContext context) {
+ int value = context.stack.isDamageable() ? context.stack.getDamage() : 0;
+ if (mask != null)
+ value &= mask;
+ return value;
+ }
+
+ @Override
+ protected int getPercentageTotalValue(CITContext context) {
+ return context.stack.isDamageable() ? context.stack.getItem().getMaxDamage() : 0;
+ }
+
+ @Override
+ public Set<Class<? extends CITCondition>> siblingConditions() {
+ return Set.of(ConditionDamageMask.class);
+ }
+
+ @Override
+ public <T extends CITCondition> T modifySibling(T sibling) {
+ if (sibling instanceof ConditionDamageMask damageMask)
+ this.mask = damageMask.getMask();
+ return null;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamageMask.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamageMask.java
new file mode 100644
index 0000000..6adde08
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionDamageMask.java
@@ -0,0 +1,38 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITCondition;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.IntegerCondition;
+
+import java.util.Set;
+
+public class ConditionDamageMask extends IntegerCondition {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionDamageMask> CONTAINER = new CITConditionContainer<>(ConditionDamageMask.class, ConditionDamageMask::new,
+ "damage_mask", "damageMask");
+
+ public ConditionDamageMask() {
+ super(false, false, false);
+ }
+
+ @Override
+ protected int getValue(CITContext context) {
+ return 0;
+ }
+
+ @Override
+ public boolean test(CITContext context) {
+ return true;
+ }
+
+ public int getMask() {
+ return this.min;
+ }
+
+ @Override
+ public Set<Class<? extends CITCondition>> siblingConditions() {
+ return Set.of(ConditionDamage.class);
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantmentLevels.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantmentLevels.java
new file mode 100644
index 0000000..da6b4f4
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantmentLevels.java
@@ -0,0 +1,62 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.util.Identifier;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITCondition;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.IntegerCondition;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.ListCondition;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class ConditionEnchantmentLevels extends ListCondition<ConditionEnchantmentLevels.EnchantmentLevelCondition> {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionEnchantmentLevels> CONTAINER = new CITConditionContainer<>(ConditionEnchantmentLevels.class, ConditionEnchantmentLevels::new,
+ "enchantment_levels", "enchantmentLevels");
+
+ protected Set<Identifier> enchantments = null;
+
+ public ConditionEnchantmentLevels() {
+ super(EnchantmentLevelCondition.class, EnchantmentLevelCondition::new);
+ }
+
+ @Override
+ public Set<Class<? extends CITCondition>> siblingConditions() {
+ return Set.of(ConditionEnchantments.class);
+ }
+
+ @Override
+ public <T extends CITCondition> T modifySibling(T sibling) {
+ if (sibling instanceof ConditionEnchantments conditionEnchantments) {
+ if (enchantments == null) {
+ enchantments = new HashSet<>();
+ for (EnchantmentLevelCondition subCondition : this.conditions)
+ subCondition.enchantments = enchantments;
+ }
+ enchantments.addAll(Arrays.asList(conditionEnchantments.getEnchantments()));
+ }
+
+ return sibling;
+ }
+
+ protected static class EnchantmentLevelCondition extends IntegerCondition {
+ protected Set<Identifier> enchantments = null;
+
+ protected EnchantmentLevelCondition() {
+ super(true, false, false);
+ }
+
+ @Override
+ public boolean test(CITContext context) {
+ for (Map.Entry<Identifier, Integer> entry : context.enchantments().entrySet())
+ if ((enchantments == null || enchantments.contains(entry.getKey())) && entry.getValue() != null && (range ? min <= entry.getValue() && entry.getValue() <= max : entry.getValue() == min))
+ return true;
+
+ return false;
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantments.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantments.java
new file mode 100644
index 0000000..301f9c1
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionEnchantments.java
@@ -0,0 +1,59 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.registry.Registry;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITCondition;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.IdentifierCondition;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.ListCondition;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyValue;
+
+import java.util.Set;
+
+public class ConditionEnchantments extends ListCondition<ConditionEnchantments.EnchantmentCondition> {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionEnchantments> CONTAINER = new CITConditionContainer<>(ConditionEnchantments.class, ConditionEnchantments::new,
+ "enchantments", "enchantmentIDs");
+
+ public ConditionEnchantments() {
+ super(EnchantmentCondition.class, EnchantmentCondition::new);
+ }
+
+ public Identifier[] getEnchantments() {
+ Identifier[] enchantments = new Identifier[this.conditions.length];
+
+ for (int i = 0; i < this.conditions.length; i++)
+ enchantments[i] = this.conditions[i].getValue(null);
+
+ return enchantments;
+ }
+
+ @Override
+ public Set<Class<? extends CITCondition>> siblingConditions() {
+ return Set.of(ConditionEnchantmentLevels.class);
+ }
+
+ protected static class EnchantmentCondition extends IdentifierCondition {
+ @Override
+ public void load(PropertyValue value, PropertyGroup properties) throws CITParsingException {
+ super.load(value, properties);
+
+ if (!Registry.ENCHANTMENT.containsId(this.value))
+ warn(this.value + " is not in the enchantment registry", value, properties);
+ }
+
+ @Override
+ public boolean test(CITContext context) {
+ return context.enchantments().containsKey(this.value);
+ }
+
+ @Override
+ protected Identifier getValue(CITContext context) {
+ return this.value;
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionHand.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionHand.java
new file mode 100644
index 0000000..0405cbc
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionHand.java
@@ -0,0 +1,49 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.EnumCondition;
+
+public class ConditionHand extends EnumCondition<ConditionHand.Hand> {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionHand> CONTAINER = new CITConditionContainer<>(ConditionHand.class, ConditionHand::new,
+ "hand");
+
+ public ConditionHand() {
+ super(ConditionHand.Hand::values);
+ }
+
+ @Override
+ protected Hand getValue(CITContext context) {
+ if (context.entity.getMainHandStack() == context.stack)
+ return Hand.MAINHAND;
+ if (context.entity.getOffHandStack() == context.stack)
+ return Hand.OFFHAND;
+
+ return null;
+ }
+
+ @Override
+ public boolean test(CITContext context) {
+ Hand hand = getValue(context);
+ return this.value == hand || (this.value == Hand.ANY && hand != null);
+ }
+
+ protected enum Hand implements EnumCondition.Aliased {
+ MAINHAND("main", "mainhand", "main_hand"),
+ OFFHAND("off", "offhand", "off_hand"),
+ ANY("any", "either", "*");
+
+ private final String[] aliases;
+
+ Hand(String... aliases) {
+ this.aliases = aliases;
+ }
+
+ @Override
+ public String[] getAliases() {
+ return this.aliases;
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionItems.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionItems.java
new file mode 100644
index 0000000..117aa47
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionItems.java
@@ -0,0 +1,75 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.item.Item;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.registry.Registry;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.IdentifierCondition;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.ListCondition;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyValue;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class ConditionItems extends ListCondition<ConditionItems.ItemCondition> {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionItems> CONTAINER = new CITConditionContainer<>(ConditionItems.class, ConditionItems::new,
+ "items", "matchItems");
+
+ public Item[] items = new Item[0];
+
+ public ConditionItems() {
+ super(ItemCondition.class, ItemCondition::new);
+ }
+
+ public ConditionItems(Item... items) {
+ this();
+ this.items = items;
+ }
+
+ @Override
+ public void load(PropertyValue value, PropertyGroup properties) throws CITParsingException {
+ super.load(value, properties);
+
+ Set<Item> items = new LinkedHashSet<>();
+
+ for (ItemCondition itemCondition : this.conditions)
+ items.add(itemCondition.item);
+
+ this.items = items.toArray(new Item[0]);
+ }
+
+ @Override
+ public boolean test(CITContext context) {
+ for (Item item : this.items)
+ if (context.stack.getItem() == item)
+ return true;
+
+ return false;
+ }
+
+ protected static class ItemCondition extends IdentifierCondition {
+ public Item item = null;
+
+ @Override
+ public void load(PropertyValue value, PropertyGroup properties) throws CITParsingException {
+ super.load(value, properties);
+
+ if (Registry.ITEM.containsId(this.value))
+ this.item = Registry.ITEM.get(this.value);
+ else {
+ this.item = null;
+ warn(this.value + " is not in the item registry", value, properties);
+ }
+ }
+
+ @Override
+ protected Identifier getValue(CITContext context) {
+ return this.value;
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionNBT.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionNBT.java
new file mode 100644
index 0000000..09ae08e
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionNBT.java
@@ -0,0 +1,244 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.nbt.*;
+import net.minecraft.text.Text;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITCondition;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyValue;
+
+import java.util.Locale;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class ConditionNBT extends CITCondition {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionNBT> CONTAINER = new CITConditionContainer<>(ConditionNBT.class, ConditionNBT::new,
+ "nbt");
+
+ protected String[] path;
+
+ protected StringMatcher matchString = null;
+ protected NbtInt matchInteger = null;
+ protected NbtByte matchByte = null;
+ protected NbtFloat matchFloat = null;
+ protected NbtDouble matchDouble = null;
+ protected NbtLong matchLong = null;
+ protected NbtShort matchShort = null;
+ protected NbtCompound matchCompound = null;
+
+ @Override
+ public void load(PropertyValue value, PropertyGroup properties) throws CITParsingException {
+ if (value.keyMetadata() == null || value.keyMetadata().isEmpty())
+ throw new CITParsingException("Missing nbt path", properties, value.position());
+
+ path = value.keyMetadata().split("\\.");
+ for (String s : path)
+ if (s.isEmpty())
+ throw new CITParsingException("Path segment cannot be empty", properties, value.position());
+
+ try {
+ if (value.value().startsWith("regex:"))
+ matchString = new StringMatcher.RegexMatcher(value.value().substring(6));
+ else if (value.value().startsWith("iregex:"))
+ matchString = new StringMatcher.IRegexMatcher(value.value().substring(7));
+ else if (value.value().startsWith("pattern:"))
+ matchString = new StringMatcher.PatternMatcher(value.value().substring(8));
+ else if (value.value().startsWith("ipattern:"))
+ matchString = new StringMatcher.IPatternMatcher(value.value().substring(9));
+ else
+ matchString = new StringMatcher.DirectMatcher(value.value());
+ } catch (PatternSyntaxException e) {
+ throw new CITParsingException("Malformatted regex expression", properties, value.position(), e);
+ } catch (Exception ignored) { }
+ try {
+ if (value.value().startsWith("#"))
+ matchInteger = NbtInt.of(Integer.parseInt(value.value().substring(1).toLowerCase(Locale.ENGLISH), 16));
+ else if (value.value().startsWith("0x"))
+ matchInteger = NbtInt.of(Integer.parseInt(value.value().substring(2).toLowerCase(Locale.ENGLISH), 16));
+ else
+ matchInteger = NbtInt.of(Integer.parseInt(value.value()));
+ } catch (Exception ignored) { }
+ try {
+ matchByte = NbtByte.of(Byte.parseByte(value.value()));
+ } catch (Exception ignored) { }
+ try {
+ matchFloat = NbtFloat.of(Float.parseFloat(value.value()));
+ } catch (Exception ignored) { }
+ try {
+ matchDouble = NbtDouble.of(Double.parseDouble(value.value()));
+ } catch (Exception ignored) { }
+ try {
+ matchLong = NbtLong.of(Long.parseLong(value.value()));
+ } catch (Exception ignored) { }
+ try {
+ matchShort = NbtShort.of(Short.parseShort(value.value()));
+ } catch (Exception ignored) { }
+ try {
+ matchCompound = StringNbtReader.parse(value.value());
+ } catch (Exception ignored) { }
+ }
+
+ @Override
+ public boolean test(CITContext context) {
+ return testPath(context.stack.getNbt(), 0);
+ }
+
+ protected boolean testPath(NbtElement element, int pathIndex) {
+ if (element == null)
+ return false;
+
+ if (pathIndex >= path.length)
+ return testValue(element);
+
+ final String path = this.path[pathIndex];
+ if (path.equals("*")) {
+ if (element instanceof NbtCompound compound) {
+ for (NbtElement subElement : compound.entries.values())
+ if (testPath(subElement, pathIndex + 1))
+ return true;
+ } else if (element instanceof NbtList list) {
+ for (NbtElement subElement : list)
+ if (testPath(subElement, pathIndex + 1))
+ return true;
+ }
+ } else {
+ if (element instanceof NbtCompound compound)
+ return testPath(compound.get(path), pathIndex + 1);
+ else if (element instanceof NbtList list)
+ try {
+ return testPath(list.get(Integer.parseInt(path)), pathIndex + 1);
+ } catch (NumberFormatException | IndexOutOfBoundsException ignored) { }
+ }
+
+ return false;
+ }
+
+ private boolean testValue(NbtElement element) {
+ try {
+ if (element instanceof NbtString nbtString) //noinspection ConstantConditions
+ return matchString.matches(nbtString.asString()) || matchString.matches(Text.Serializer.fromJson(nbtString.asString()).getString());
+ else if (element instanceof NbtInt nbtInt)
+ return nbtInt.equals(matchInteger);
+ else if (element instanceof NbtByte nbtByte)
+ return nbtByte.equals(matchByte);
+ else if (element instanceof NbtFloat nbtFloat)
+ return nbtFloat.equals(matchFloat);
+ else if (element instanceof NbtDouble nbtDouble)
+ return nbtDouble.equals(matchDouble);
+ else if (element instanceof NbtLong nbtLong)
+ return nbtLong.equals(matchLong);
+ else if (element instanceof NbtShort nbtShort)
+ return nbtShort.equals(matchShort);
+ else if (element instanceof NbtCompound nbtCompound)
+ return NbtHelper.matches(matchCompound, nbtCompound, true);
+ } catch (Exception ignored) { }
+ return false;
+ }
+
+ protected static abstract class StringMatcher {
+ public abstract boolean matches(String value);
+
+ public static class DirectMatcher extends StringMatcher {
+ protected final String pattern;
+
+ public DirectMatcher(String pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override
+ public boolean matches(String value) {
+ return pattern.equals(value);
+ }
+ }
+
+ public static class RegexMatcher extends StringMatcher {
+ protected final Pattern pattern;
+
+ public RegexMatcher(String pattern) {
+ this(Pattern.compile(pattern));
+ }
+
+ protected RegexMatcher(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override
+ public boolean matches(String value) {
+ return this.pattern.matcher(value).matches();
+ }
+ }
+
+ public static class PatternMatcher extends StringMatcher {
+ protected final String pattern;
+
+ public PatternMatcher(String pattern) {
+ this.pattern = pattern;
+ }
+
+ @Override
+ public boolean matches(String value) {
+ return matchesPattern(value, this.pattern, 0, value.length(), 0, pattern.length());
+ }
+
+ /**
+ * Author: Paul "prupe" Rupe<br>
+ * Taken and modified from MCPatcher under public domain licensing.<br>
+ * https://bitbucket.org/prupe/mcpatcher/src/1aa45839b2cd029143809edfa60ec59e5ef75f80/newcode/src/com/prupe/mcpatcher/mal/nbt/NBTRule.java#lines-269:301
+ */
+ protected boolean matchesPattern(String value, String pattern, int curV, int maxV, int curG, int maxG) {
+ for (; curG < maxG; curG++, curV++) {
+ char g = pattern.charAt(curG);
+ if (g == '*') {
+ while (true) {
+ if (matchesPattern(value, pattern, curV, maxV, curG + 1, maxG)) {
+ return true;
+ }
+ if (curV >= maxV) {
+ break;
+ }
+ curV++;
+ }
+ return false;
+ } else if (curV >= maxV) {
+ break;
+ } else if (g == '?') {
+ continue;
+ }
+ if (g == '\\' && curG + 1 < maxG) {
+ curG++;
+ g = pattern.charAt(curG);
+ }
+
+ if (!charsEqual(g, value.charAt(curV)))
+ return false;
+ }
+ return curG == maxG && curV == maxV;
+ }
+
+ protected boolean charsEqual(char p, char v) {
+ return p == v;
+ }
+ }
+
+ public static class IRegexMatcher extends RegexMatcher {
+ public IRegexMatcher(String pattern) {
+ super(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
+ }
+ }
+
+ public static class IPatternMatcher extends PatternMatcher {
+ public IPatternMatcher(String pattern) {
+ super(pattern.toLowerCase(Locale.ROOT));
+ }
+
+ @Override
+ protected boolean charsEqual(char p, char v) {
+ return p == v || p == Character.toLowerCase(v);
+ }
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionStackSize.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionStackSize.java
new file mode 100644
index 0000000..1d22a53
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/conditions/ConditionStackSize.java
@@ -0,0 +1,21 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.conditions;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import shcm.shsupercm.fabric.citresewn.api.CITConditionContainer;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.cit.builtin.conditions.IntegerCondition;
+
+public class ConditionStackSize extends IntegerCondition {
+ @Entrypoint(CITConditionContainer.ENTRYPOINT)
+ public static final CITConditionContainer<ConditionStackSize> CONTAINER = new CITConditionContainer<>(ConditionStackSize.class, ConditionStackSize::new,
+ "stack_size", "stackSize", "amount");
+
+ public ConditionStackSize() {
+ super(true, false, false);
+ }
+
+ @Override
+ protected int getValue(CITContext context) {
+ return context.stack.getCount();
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeArmor.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeArmor.java
new file mode 100644
index 0000000..d97bf67
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeArmor.java
@@ -0,0 +1,111 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.types;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.item.ArmorItem;
+import net.minecraft.item.Item;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.registry.Registry;
+import shcm.shsupercm.fabric.citresewn.api.CITTypeContainer;
+import shcm.shsupercm.fabric.citresewn.cit.*;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.conditions.ConditionItems;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyKey;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyValue;
+
+import java.util.*;
+
+public class TypeArmor extends CITType {
+ @Entrypoint(CITTypeContainer.ENTRYPOINT)
+ public static final Container CONTAINER = new Container();
+
+ public final Map<String, Identifier> textures = new HashMap<>();
+
+ @Override
+ public Set<PropertyKey> typeProperties() {
+ return Set.of(PropertyKey.of("texture"));
+ }
+
+ @Override
+ public void load(List<CITCondition> conditions, PropertyGroup properties, ResourceManager resourceManager) throws CITParsingException {
+ boolean itemsConditionPresent = false;
+ for (CITCondition condition : conditions)
+ if (condition instanceof ConditionItems conditionItems)
+ for (Item item : conditionItems.items)
+ if (item instanceof ArmorItem)
+ itemsConditionPresent = true;
+ else
+ throw new CITParsingException("This type only accepts armor items for the items condition", properties, -1);
+
+ if (!itemsConditionPresent)
+ try {
+ Identifier propertiesName = new Identifier(properties.stripName());
+ if (!Registry.ITEM.containsId(propertiesName))
+ throw new Exception();
+ Item item = Registry.ITEM.get(propertiesName);
+ if (!(item instanceof ArmorItem))
+ throw new Exception();
+ conditions.add(new ConditionItems(item));
+ } catch (Exception ignored) {
+ throw new CITParsingException("Not targeting any item type", properties, -1);
+ }
+
+ for (PropertyValue propertyValue : properties.get("citresewn", "texture")) {
+ Identifier identifier = resolveAsset(properties.identifier, propertyValue, "textures", ".png", resourceManager);
+ if (identifier == null)
+ throw new CITParsingException("Could not resolve texture", properties, propertyValue.position());
+
+ textures.put(propertyValue.keyMetadata(), identifier);
+ }
+ if (textures.size() == 0)
+ throw new CITParsingException("Texture not specified", properties, -1);
+ }
+
+ public static class Container extends CITTypeContainer<TypeArmor> {
+ public Container() {
+ super(TypeArmor.class, TypeArmor::new, "armor");
+ }
+
+ public Set<CIT<TypeArmor>> loaded = new HashSet<>();
+ public Map<ArmorItem, Set<CIT<TypeArmor>>> loadedTyped = new IdentityHashMap<>();
+
+ @Override
+ public void load(List<CIT<TypeArmor>> parsedCITs) {
+ loaded.addAll(parsedCITs);
+ for (CIT<TypeArmor> cit : parsedCITs)
+ for (CITCondition condition : cit.conditions)
+ if (condition instanceof ConditionItems items)
+ for (Item item : items.items)
+ if (item instanceof ArmorItem armorItem)
+ loadedTyped.computeIfAbsent(armorItem, i -> new LinkedHashSet<>()).add(cit);
+ }
+
+ @Override
+ public void dispose() {
+ loaded.clear();
+ loadedTyped.clear();
+ }
+
+ public CIT<TypeArmor> getCIT(CITContext context) {
+ return ((CITCacheArmor) (Object) context.stack).citresewn$getCacheTypeArmor().get(context).get();
+ }
+
+ public CIT<TypeArmor> getRealTimeCIT(CITContext context) {
+ if (!(context.stack.getItem() instanceof ArmorItem))
+ return null;
+
+ Set<CIT<TypeArmor>> loadedForItemType = loadedTyped.get(context.stack.getItem());
+ if (loadedForItemType != null)
+ for (CIT<TypeArmor> cit : loadedForItemType)
+ if (cit.test(context))
+ return cit;
+
+ return null;
+ }
+ }
+
+ public interface CITCacheArmor {
+ CITCache.Single<TypeArmor> citresewn$getCacheTypeArmor();
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeElytra.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeElytra.java
new file mode 100644
index 0000000..40e6fbe
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeElytra.java
@@ -0,0 +1,76 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.types;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.item.ElytraItem;
+import net.minecraft.item.Item;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.util.Identifier;
+import shcm.shsupercm.fabric.citresewn.api.CITTypeContainer;
+import shcm.shsupercm.fabric.citresewn.cit.*;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.conditions.ConditionItems;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyKey;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class TypeElytra extends CITType {
+ @Entrypoint(CITTypeContainer.ENTRYPOINT)
+ public static final Container CONTAINER = new Container();
+
+ public Identifier texture;
+
+ @Override
+ public Set<PropertyKey> typeProperties() {
+ return Set.of(PropertyKey.of("texture"));
+ }
+
+ @Override
+ public void load(List<CITCondition> conditions, PropertyGroup properties, ResourceManager resourceManager) throws CITParsingException {
+ for (CITCondition condition : conditions)
+ if (condition instanceof ConditionItems items)
+ for (Item item : items.items)
+ if (!(item instanceof ElytraItem))
+ warn("Non elytra item type condition", null, properties);
+
+ texture = resolveAsset(properties.identifier, properties.getLastWithoutMetadata("citresewn", "texture"), "textures", ".png", resourceManager);
+ if (texture == null)
+ throw new CITParsingException("Texture not specified", properties, -1);
+ }
+
+ public static class Container extends CITTypeContainer<TypeElytra> {
+ public Container() {
+ super(TypeElytra.class, TypeElytra::new, "elytra");
+ }
+
+ public Set<CIT<TypeElytra>> loaded = new HashSet<>();
+
+ @Override
+ public void load(List<CIT<TypeElytra>> parsedCITs) {
+ loaded.addAll(parsedCITs);
+ }
+
+ @Override
+ public void dispose() {
+ loaded.clear();
+ }
+
+ public CIT<TypeElytra> getCIT(CITContext context) {
+ return ((CITCacheElytra) (Object) context.stack).citresewn$getCacheTypeElytra().get(context).get();
+ }
+
+ public CIT<TypeElytra> getRealTimeCIT(CITContext context) {
+ for (CIT<TypeElytra> cit : loaded)
+ if (cit.test(context))
+ return cit;
+
+ return null;
+ }
+ }
+
+ public interface CITCacheElytra {
+ CITCache.Single<TypeElytra> citresewn$getCacheTypeElytra();
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeEnchantment.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeEnchantment.java
new file mode 100644
index 0000000..0bd29e7
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeEnchantment.java
@@ -0,0 +1,528 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.types;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.*;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.Util;
+import net.minecraft.util.math.Matrix4f;
+import net.minecraft.util.math.Vec3f;
+import org.lwjgl.opengl.GL11;
+import shcm.shsupercm.fabric.citresewn.api.CITGlobalProperties;
+import shcm.shsupercm.fabric.citresewn.api.CITTypeContainer;
+import shcm.shsupercm.fabric.citresewn.cit.*;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.conditions.ConditionEnchantments;
+import shcm.shsupercm.fabric.citresewn.defaults.config.CITResewnDefaultsConfig;
+import shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment.BufferBuilderStorageAccessor;
+import shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment.RenderPhaseAccessor;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyKey;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyValue;
+import shcm.shsupercm.util.logic.Loops;
+
+import javax.annotation.Nullable;
+import java.lang.ref.WeakReference;
+import java.util.*;
+import java.util.function.Consumer;
+
+import static com.mojang.blaze3d.systems.RenderSystem.*;
+import static org.lwjgl.opengl.GL11.*;
+
+public class TypeEnchantment extends CITType {
+ @Entrypoint(CITGlobalProperties.ENTRYPOINT)
+ @Entrypoint(CITTypeContainer.ENTRYPOINT)
+ public static final Container CONTAINER = new Container();
+
+ @Override
+ public Set<PropertyKey> typeProperties() {
+ return Set.of(
+ PropertyKey.of("texture"),
+ PropertyKey.of("layer"),
+ PropertyKey.of("speed"),
+ PropertyKey.of("rotation"),
+ PropertyKey.of("duration"),
+ PropertyKey.of("r"),
+ PropertyKey.of("g"),
+ PropertyKey.of("b"),
+ PropertyKey.of("a"),
+ PropertyKey.of("useGlint"),
+ PropertyKey.of("blur"),
+ PropertyKey.of("blend"));
+ }
+
+ public Identifier texture;
+ public int layer;
+ public float speed, rotation, duration, r, g, b, a;
+ public boolean useGlint, blur;
+ public Blend blend;
+
+ public final Map<GlintRenderLayer, RenderLayer> renderLayers = new EnumMap<>(GlintRenderLayer.class);
+ private final MergeMethodIntensity methodIntensity = new MergeMethodIntensity();
+ private Set<Identifier> enchantmentChecks = null;
+
+ @Override
+ public void load(List<CITCondition> conditions, PropertyGroup properties, ResourceManager resourceManager) throws CITParsingException {
+ PropertyValue textureProp = properties.getLastWithoutMetadata("citresewn", "texture");
+ this.texture = resolveAsset(properties.identifier, textureProp, "textures", ".png", resourceManager);
+ if (this.texture == null)
+ throw textureProp == null ? new CITParsingException("No texture specified", properties, -1) : new CITParsingException("Could not resolve texture", properties, textureProp.position());
+
+ PropertyValue layerProp = properties.getLastWithoutMetadataOrDefault("0", "citresewn", "layer");
+ try {
+ this.layer = Integer.parseInt(layerProp.value());
+ } catch (Exception e) {
+ throw new CITParsingException("Could not parse integer", properties, layerProp.position(), e);
+ }
+
+ this.speed = parseFloatOrDefault(1f, "speed", properties);
+ this.rotation = parseFloatOrDefault(10f, "rotation", properties);
+ this.duration = Math.max(0f, parseFloatOrDefault(0f, "duration", properties));
+ this.r = Math.max(0f, parseFloatOrDefault(1f, "r", properties));
+ this.g = Math.max(0f, parseFloatOrDefault(1f, "g", properties));
+ this.b = Math.max(0f, parseFloatOrDefault(1f, "b", properties));
+ this.a = Math.max(0f, parseFloatOrDefault(1f, "a", properties));
+
+ this.useGlint = Boolean.parseBoolean(properties.getLastWithoutMetadataOrDefault("false", "citresewn", "useGlint").value());
+ this.blur = Boolean.parseBoolean(properties.getLastWithoutMetadataOrDefault("true", "citresewn", "blur").value());
+
+ PropertyValue blendProp = properties.getLastWithoutMetadataOrDefault("add", "citresewn", "blend");
+ try {
+ this.blend = Blend.getBlend(blendProp.value());
+ } catch (Exception e) {
+ throw new CITParsingException("Could not parse blending method", properties, blendProp.position(), e);
+ }
+
+ for (CITCondition condition : conditions)
+ if (condition instanceof ConditionEnchantments enchantments) {
+ if (enchantmentChecks == null && enchantments.getEnchantments().length > 0)
+ enchantmentChecks = new HashSet<>();
+
+ enchantmentChecks.addAll(Arrays.asList(enchantments.getEnchantments()));
+ }
+ }
+
+ private float parseFloatOrDefault(float defaultValue, String propertyName, PropertyGroup properties) throws CITParsingException {
+ PropertyValue property = properties.getLastWithoutMetadata("citresewn", propertyName);
+ if (property == null)
+ return defaultValue;
+ try {
+ return Float.parseFloat(property.value());
+ } catch (Exception e) {
+ throw new CITParsingException("Could not parse float", properties, property.position(), e);
+ }
+ }
+
+ public static class Container extends CITTypeContainer<TypeEnchantment> implements CITGlobalProperties {
+ public Container() {
+ super(TypeEnchantment.class, TypeEnchantment::new, "enchantment");
+ }
+
+ public boolean globalUseGlint = true;
+ public int globalCap = Integer.MAX_VALUE;
+ public MergeMethodIntensity.MergeMethod globalMergeMethod = MergeMethodIntensity.MergeMethod.AVERAGE;
+ public float globalFade = 0.5f;
+
+ public List<CIT<TypeEnchantment>> loaded = new ArrayList<>();
+ public List<List<CIT<TypeEnchantment>>> loadedLayered = new ArrayList<>();
+
+ private List<CIT<TypeEnchantment>> appliedContext = null;
+ private boolean apply = false, defaultGlint = false;
+
+ @Override
+ public void load(List<CIT<TypeEnchantment>> parsedCITs) {
+ loaded.addAll(parsedCITs);
+
+ Map<Integer, List<CIT<TypeEnchantment>>> layers = new HashMap<>();
+ for (CIT<TypeEnchantment> cit : loaded)
+ layers.computeIfAbsent(cit.type.layer, i -> new ArrayList<>()).add(cit);
+ loadedLayered.clear();
+ layers.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .forEachOrdered(layer -> loadedLayered.add(layer.getValue()));
+
+ for (CIT<TypeEnchantment> cit : loaded)
+ for (GlintRenderLayer glintLayer : GlintRenderLayer.values()) {
+ RenderLayer renderLayer = glintLayer.build(cit.type, cit.propertiesIdentifier);
+
+ cit.type.renderLayers.put(glintLayer, renderLayer);
+ ((BufferBuilderStorageAccessor) MinecraftClient.getInstance().getBufferBuilders()).getEntityBuilders().put(renderLayer, new BufferBuilder(renderLayer.getExpectedBufferSize()));
+ }
+ }
+
+ @Override
+ public void globalProperty(String key, @Nullable PropertyValue value) throws Exception {
+ switch (key) {
+ case "useGlint" -> {
+ globalUseGlint = value == null ? true : Boolean.parseBoolean(value.value());
+ if (!globalUseGlint && !"false".equalsIgnoreCase(value.value()))
+ throw new Exception("Could not parse boolean");
+ }
+ case "cap" -> {
+ globalCap = value == null ? Integer.MAX_VALUE : Integer.parseInt(value.value());
+ }
+ case "method" -> {
+ globalMergeMethod = value == null ? MergeMethodIntensity.MergeMethod.AVERAGE : MergeMethodIntensity.MergeMethod.parse(value.value());
+ }
+ case "fade" -> {
+ globalFade = value == null ? 0.5f : Float.parseFloat(value.value());
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ appliedContext = null;
+ apply = false;
+
+ for (CIT<TypeEnchantment> cit : loaded)
+ for (RenderLayer renderLayer : cit.type.renderLayers.values())
+ ((BufferBuilderStorageAccessor) MinecraftClient.getInstance().getBufferBuilders()).getEntityBuilders().remove(renderLayer);
+
+ loaded.clear();
+ loadedLayered.clear();
+ }
+
+ public void apply() {
+ if (appliedContext != null)
+ apply = true;
+ }
+
+ public boolean shouldApply() {
+ return apply && active();
+ }
+
+ public boolean shouldNotApplyDefaultGlint() {
+ return !globalUseGlint || (apply && !defaultGlint);
+ }
+
+ public Container setContext(CITContext context) {
+ apply = false;
+ defaultGlint = false;
+ appliedContext = null;
+ if (context == null)
+ return this;
+
+ List<WeakReference<CIT<TypeEnchantment>>> cits = ((CITCacheEnchantment) (Object) context.stack).citresewn$getCacheTypeEnchantment().get(context);
+
+ appliedContext = new ArrayList<>();
+ if (cits != null)
+ for (WeakReference<CIT<TypeEnchantment>> citRef : cits)
+ if (citRef != null) {
+ CIT<TypeEnchantment> cit = citRef.get();
+ if (cit != null) {
+ appliedContext.add(cit);
+ if (cit.type.useGlint)
+ defaultGlint = true;
+ }
+ }
+
+ if (appliedContext.isEmpty())
+ appliedContext = null;
+ else
+ globalMergeMethod.applyMethod(appliedContext, context);
+
+ return this;
+ }
+
+ public List<CIT<TypeEnchantment>> getRealTimeCIT(CITContext context) {
+ List<CIT<TypeEnchantment>> cits = new ArrayList<>();
+ for (List<CIT<TypeEnchantment>> layer : loadedLayered)
+ for (CIT<TypeEnchantment> cit : layer)
+ if (cit.test(context)) {
+ cits.add(cit);
+ break;
+ }
+
+ return cits;
+ }
+ }
+
+ public enum GlintRenderLayer {
+ ARMOR_GLINT("armor_glint", 8f, layer -> layer
+ .shader(RenderPhaseAccessor.ARMOR_GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST())
+ .layering(RenderPhaseAccessor.VIEW_OFFSET_Z_LAYERING())),
+ ARMOR_ENTITY_GLINT("armor_entity_glint", 0.16f, layer -> layer
+ .shader(RenderPhaseAccessor.ARMOR_ENTITY_GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST())
+ .layering(RenderPhaseAccessor.VIEW_OFFSET_Z_LAYERING())),
+ GLINT_TRANSLUCENT("glint_translucent", 8f, layer -> layer
+ .shader(RenderPhaseAccessor.TRANSLUCENT_GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST())
+ .target(RenderPhaseAccessor.ITEM_TARGET())),
+ GLINT("glint", 8f, layer -> layer
+ .shader(RenderPhaseAccessor.GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST())),
+ DIRECT_GLINT("glint_direct", 8f, layer -> layer
+ .shader(RenderPhaseAccessor.DIRECT_GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST())),
+ ENTITY_GLINT("entity_glint", 0.16f, layer -> layer
+ .shader(RenderPhaseAccessor.ENTITY_GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST())
+ .target(RenderPhaseAccessor.ITEM_TARGET())),
+ DIRECT_ENTITY_GLINT("entity_glint_direct", 0.16f, layer -> layer
+ .shader(RenderPhaseAccessor.DIRECT_ENTITY_GLINT_SHADER())
+ .writeMaskState(RenderPhaseAccessor.COLOR_MASK())
+ .cull(RenderPhaseAccessor.DISABLE_CULLING())
+ .depthTest(RenderPhaseAccessor.EQUAL_DEPTH_TEST()));
+
+ public final String name;
+ private final Consumer<RenderLayer.MultiPhaseParameters.Builder> setup;
+ private final float scale;
+
+ GlintRenderLayer(String name, float scale, Consumer<RenderLayer.MultiPhaseParameters.Builder> setup) {
+ this.name = name;
+ this.scale = scale;
+ this.setup = setup;
+ }
+
+ public RenderLayer build(TypeEnchantment enchantment, Identifier propertiesIdentifier) {
+ class Texturing implements Runnable {
+ private final float speed, rotation, r, g, b, a;
+ private final MergeMethodIntensity methodIntensity;
+
+ Texturing(float speed, float rotation, float r, float g, float b, float a, MergeMethodIntensity methodIntensity) {
+ this.speed = speed;
+ this.rotation = rotation;
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ this.methodIntensity = methodIntensity;
+ }
+
+ @Override
+ public void run() {
+ float l = Util.getMeasuringTimeMs() * CITResewnDefaultsConfig.INSTANCE.type_enchantment_scroll_multiplier * speed;
+ float x = (l % 110000f) / 110000f;
+ float y = (l % 30000f) / 30000f;
+ Matrix4f matrix4f = Matrix4f.translate(-x, y, 0.0f);
+ matrix4f.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion(rotation));
+ matrix4f.multiply(Matrix4f.scale(scale, scale, scale));
+ setTextureMatrix(matrix4f);
+
+ setShaderColor(r, g, b, a * methodIntensity.intensity);
+ }
+ }
+
+ RenderLayer.MultiPhaseParameters.Builder layer = RenderLayer.MultiPhaseParameters.builder()
+ .texture(new RenderPhase.Texture(enchantment.texture, enchantment.blur, false))
+ .texturing(new RenderPhase.Texturing("citresewn_glint_texturing", new Texturing(enchantment.speed, enchantment.rotation, enchantment.r, enchantment.g, enchantment.b, enchantment.a, enchantment.methodIntensity), () -> {
+ RenderSystem.resetTextureMatrix();
+
+ setShaderColor(1f, 1f, 1f, 1f);
+ }))
+ .transparency(enchantment.blend);
+
+ this.setup.accept(layer);
+
+ return RenderLayer.of("citresewn:enchantment_" + this.name + ":" + propertiesIdentifier.toString(),
+ VertexFormats.POSITION_TEXTURE,
+ VertexFormat.DrawMode.QUADS,
+ 256,
+ layer.build(false));
+ }
+
+ public VertexConsumer tryApply(VertexConsumer base, RenderLayer baseLayer, VertexConsumerProvider provider) {
+ if (!CONTAINER.apply || CONTAINER.appliedContext == null || CONTAINER.appliedContext.size() == 0)
+ return null;
+
+ VertexConsumer[] layers = new VertexConsumer[Math.min(CONTAINER.appliedContext.size(), CONTAINER.globalCap)];
+
+ for (int i = 0; i < layers.length; i++)
+ layers[i] = provider.getBuffer(CONTAINER.appliedContext.get(i).type.renderLayers.get(GlintRenderLayer.this));
+
+ provider.getBuffer(baseLayer); // refresh base layer for armor consumer
+
+ return base == null ? VertexConsumers.union(layers) : VertexConsumers.union(VertexConsumers.union(layers), base);
+ }
+ }
+
+ public static class MergeMethodIntensity {
+ public float intensity = 1f;
+
+ public enum MergeMethod {
+ NONE,
+ AVERAGE {
+ @Override
+ public void applyIntensity(Map<Identifier, Integer> stackEnchantments, CIT<TypeEnchantment> cit) {
+ Identifier enchantment = null;
+ for (Identifier enchantmentMatch : cit.type.enchantmentChecks)
+ if (stackEnchantments.containsKey(enchantmentMatch)) {
+ enchantment = enchantmentMatch;
+ break;
+ }
+
+ if (enchantment == null) {
+ cit.type.methodIntensity.intensity = 0f;
+ } else {
+ float sum = 0f;
+ for (Integer value : stackEnchantments.values())
+ sum += value;
+
+ cit.type.methodIntensity.intensity = (float) stackEnchantments.get(enchantment) / sum;
+ }
+ }
+ },
+ LAYERED {
+ @Override
+ public void applyIntensity(Map<Identifier, Integer> stackEnchantments, CIT<TypeEnchantment> cit) {
+ Identifier enchantment = null;
+ for (Identifier enchantmentMatch : cit.type.enchantmentChecks)
+ if (stackEnchantments.containsKey(enchantmentMatch)) {
+ enchantment = enchantmentMatch;
+ break;
+ }
+ if (enchantment == null) {
+ cit.type.methodIntensity.intensity = 0f;
+ return;
+ }
+
+ float max = 0f;
+ for (Integer value : stackEnchantments.values())
+ if (value > max)
+ max = value;
+
+ cit.type.methodIntensity.intensity = (float) stackEnchantments.get(enchantment) / max;
+ }
+ },
+ CYCLE {
+ @Override
+ public void applyMethod(List<CIT<TypeEnchantment>> citEnchantments, CITContext context) {
+ List<Map.Entry<CIT<TypeEnchantment>, Float>> durations = new ArrayList<>();
+ for (CIT<TypeEnchantment> cit : citEnchantments)
+ durations.add(new HashMap.SimpleEntry<>(cit, cit.type.duration));
+
+ for (Map.Entry<CIT<TypeEnchantment>, Float> intensity : Loops.statelessFadingLoop(durations, CONTAINER.globalFade, ticks, 20).entrySet())
+ intensity.getKey().type.methodIntensity.intensity = intensity.getValue();
+ }
+ };
+
+ public static int ticks = 0;
+
+ public void applyIntensity(Map<Identifier, Integer> stackEnchantments, CIT<TypeEnchantment> cit) {
+ cit.type.methodIntensity.intensity = 1f;
+ }
+
+ public void applyMethod(List<CIT<TypeEnchantment>> citEnchantments, CITContext context) {
+ Map<Identifier, Integer> stackEnchantments = context.enchantments();
+
+ for (CIT<TypeEnchantment> cit : citEnchantments)
+ if (cit.type.enchantmentChecks != null)
+ applyIntensity(stackEnchantments, cit);
+ }
+
+ public static MergeMethod parse(String value) {
+ return switch (value.toLowerCase(Locale.ROOT)) {
+ case "none" -> NONE;
+ case "average" -> AVERAGE;
+ case "layered" -> LAYERED;
+ case "cycle" -> CYCLE;
+ default -> throw new IllegalArgumentException("Unknown merge method");
+ };
+ }
+ }
+ }
+
+ public static class Blend extends RenderPhase.Transparency {
+ private final int src, dst, srcAlpha, dstAlpha;
+
+ private Blend(String name, int src, int dst, int srcAlpha, int dstAlpha) {
+ super(name + "_glint_transparency", null, null);
+ this.src = src;
+ this.dst = dst;
+ this.srcAlpha = srcAlpha;
+ this.dstAlpha = dstAlpha;
+ }
+
+ private Blend(String name, int src, int dst) {
+ this(name, src, dst, GL_ZERO, GL_ONE);
+ }
+
+ @Override
+ public void startDrawing() {
+ enableBlend();
+ blendFuncSeparate(src, dst, srcAlpha, dstAlpha);
+ }
+
+ @Override
+ public void endDrawing() {
+ defaultBlendFunc();
+ disableBlend();
+ }
+
+ public static Blend getBlend(String blendString) throws Exception {
+ try { //check named blending function
+ return Named.valueOf(blendString.toUpperCase(Locale.ENGLISH)).blend;
+ } catch (IllegalArgumentException ignored) { // create custom blending function
+ String[] split = blendString.split("\\p{Zs}+");
+ int src, dst, srcAlpha, dstAlpha;
+ if (split.length == 2) {
+ src = parseGLConstant(split[0]);
+ dst = parseGLConstant(split[1]);
+ srcAlpha = GL_ZERO;
+ dstAlpha = GL_ONE;
+ } else if (split.length == 4) {
+ src = parseGLConstant(split[0]);
+ dst = parseGLConstant(split[1]);
+ srcAlpha = parseGLConstant(split[2]);
+ dstAlpha = parseGLConstant(split[3]);
+ } else
+ throw new Exception();
+
+ return new Blend("custom_" + src + "_" + dst + "_" + srcAlpha + "_" + dstAlpha, src, dst, srcAlpha, dstAlpha);
+ }
+ }
+
+ private enum Named {
+ REPLACE(new Blend("replace", 0, 0) {
+ @Override
+ public void startDrawing() {
+ disableBlend();
+ }
+ }),
+ GLINT(new Blend("glint", GL_SRC_COLOR, GL_ONE)),
+ ALPHA(new Blend("alpha", GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)),
+ ADD(new Blend("add", GL_SRC_ALPHA, GL_ONE)),
+ SUBTRACT(new Blend("subtract", GL_ONE_MINUS_DST_COLOR, GL_ZERO)),
+ MULTIPLY(new Blend("multiply", GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA)),
+ DODGE(new Blend("dodge", GL_ONE, GL_ONE)),
+ BURN(new Blend("burn", GL_ZERO, GL_ONE_MINUS_SRC_COLOR)),
+ SCREEN(new Blend("screen", GL_ONE, GL_ONE_MINUS_SRC_COLOR)),
+ OVERLAY(new Blend("overlay", GL_DST_COLOR, GL_SRC_COLOR));
+
+ public final Blend blend;
+
+ Named(Blend blend) {
+ this.blend = blend;
+ }
+ }
+
+ private static int parseGLConstant(String s) throws Exception {
+ try {
+ return GL11.class.getDeclaredField(s).getInt(null);
+ } catch (NoSuchFieldException ignored) { }
+
+ return s.startsWith("0x") ? Integer.parseInt(s.substring(2), 16) : Integer.parseInt(s);
+ }
+ }
+
+ public interface CITCacheEnchantment {
+ CITCache.MultiList<TypeEnchantment> citresewn$getCacheTypeEnchantment();
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeItem.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeItem.java
new file mode 100644
index 0000000..fe0bafb
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/cit/types/TypeItem.java
@@ -0,0 +1,520 @@
+package shcm.shsupercm.fabric.citresewn.defaults.cit.types;
+
+import com.google.common.collect.ImmutableMap;
+import com.mojang.datafixers.util.Either;
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.json.JsonUnbakedModel;
+import net.minecraft.client.render.model.json.ModelOverride;
+import net.minecraft.client.render.model.json.ModelOverrideList;
+import net.minecraft.client.render.model.json.ModelTransformation;
+import net.minecraft.client.texture.SpriteAtlasTexture;
+import net.minecraft.client.util.SpriteIdentifier;
+import net.minecraft.client.world.ClientWorld;
+import net.minecraft.item.Item;
+import net.minecraft.item.Items;
+import net.minecraft.resource.Resource;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.registry.Registry;
+import org.apache.commons.io.IOUtils;
+import shcm.shsupercm.fabric.citresewn.CITResewn;
+import shcm.shsupercm.fabric.citresewn.api.CITTypeContainer;
+import shcm.shsupercm.fabric.citresewn.cit.*;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.conditions.ConditionItems;
+import shcm.shsupercm.fabric.citresewn.defaults.common.ResewnItemModelIdentifier;
+import shcm.shsupercm.fabric.citresewn.defaults.common.ResewnTextureIdentifier;
+import shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item.JsonUnbakedModelAccessor;
+import shcm.shsupercm.fabric.citresewn.ex.CITParsingException;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyGroup;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyKey;
+import shcm.shsupercm.fabric.citresewn.pack.format.PropertyValue;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * ///// PORTED FROM BETA \\\\\
+ * This shit was ported from the
+ * beta and will be rewritten at
+ * some point!
+ * \\\\\ /////
+ */
+public class TypeItem extends CITType {
+ @Entrypoint(CITTypeContainer.ENTRYPOINT)
+ public static final Container CONTAINER = new Container();
+
+ private static final String GENERATED_SUB_CITS_PREFIX = "sub_cititem_generated_";
+ public static final Set<Identifier> GENERATED_SUB_CITS_SEEN = new HashSet<>();
+
+ private final List<Item> items = new ArrayList<>();
+
+ public Map<Identifier, Identifier> assetIdentifiers = new LinkedHashMap<>();
+ public Map<List<ModelOverride.Condition>, JsonUnbakedModel> unbakedAssets = new LinkedHashMap<>();
+ private Map<String, Either<SpriteIdentifier, String>> textureOverrideMap = new HashMap<>();
+ private boolean isTexture = false;
+
+ public BakedModel bakedModel = null;
+ public CITOverrideList bakedSubModels = new CITOverrideList();
+
+ @Override
+ public Set<PropertyKey> typeProperties() {
+ return Set.of(PropertyKey.of("model"), PropertyKey.of("texture"), PropertyKey.of("tile"));
+ }
+
+ @Override
+ public void load(List<CITCondition> conditions, PropertyGroup properties, ResourceManager resourceManager) throws CITParsingException {
+ for (CITCondition condition : conditions)
+ if (condition instanceof ConditionItems conditionItems)
+ items.addAll(Arrays.asList(conditionItems.items));
+
+ if (this.items.size() == 0)
+ try {
+ Identifier propertiesName = new Identifier(properties.stripName());
+ if (!Registry.ITEM.containsId(propertiesName))
+ throw new Exception();
+ Item item = Registry.ITEM.get(propertiesName);
+ conditions.add(new ConditionItems(item));
+ this.items.add(item);
+ } catch (Exception ignored) {
+ throw new CITParsingException("Not targeting any item type", properties, -1);
+ }
+
+ Identifier assetIdentifier;
+ PropertyValue modelProp = properties.getLastWithoutMetadata("citresewn", "model");
+ boolean containsTexture = modelProp == null && !properties.get("citresewn", "texture", "tile").isEmpty();
+
+ if (!containsTexture) {
+ assetIdentifier = resolveAsset(properties.identifier, modelProp, "models", ".json", resourceManager);
+ if (assetIdentifier != null)
+ assetIdentifiers.put(null, assetIdentifier);
+ else if (modelProp != null) {
+ assetIdentifier = resolveAsset(properties.identifier, modelProp, "models", ".json", resourceManager);
+ if (assetIdentifier != null)
+ assetIdentifiers.put(null, assetIdentifier);
+ }
+ }
+
+ for (PropertyValue property : properties.get("citresewn", "model")) {
+ Identifier subIdentifier = resolveAsset(properties.identifier, property, "models", ".json", resourceManager);
+ if (subIdentifier == null)
+ throw new CITParsingException("Cannot resolve path", properties, property.position());
+
+ String subItem = property.keyMetadata();
+ Identifier subItemIdentifier = fixDeprecatedSubItem(subItem, properties, property.position());
+ assetIdentifiers.put(subItemIdentifier == null ? new Identifier("minecraft", "item/" + subItem) : subItemIdentifier, subIdentifier);
+ }
+
+ if (assetIdentifiers.size() == 0) { // attempt to load texture
+ isTexture = true;
+ PropertyValue textureProp = properties.getLastWithoutMetadata("citresewn", "texture", "tile");
+ assetIdentifier = resolveAsset(properties.identifier, textureProp, "textures", ".png", resourceManager);
+ if (assetIdentifier != null)
+ assetIdentifiers.put(null, assetIdentifier);
+
+ for (PropertyValue property : properties.get("citresewn", "texture", "tile")) {
+ Identifier subIdentifier = resolveAsset(properties.identifier, property, "textures", ".png", resourceManager);
+ if (subIdentifier == null)
+ throw new CITParsingException("Cannot resolve path", properties, property.position());
+
+ String subItem = property.keyMetadata();
+ Identifier subItemIdentifier = fixDeprecatedSubItem(subItem, properties, property.position());
+ assetIdentifiers.put(subItemIdentifier == null ? new Identifier("minecraft", "item/" + subItem) : subItemIdentifier, subIdentifier);
+ }
+ } else { // attempt to load textureOverrideMap from textures
+ PropertyValue textureProp = properties.getLastWithoutMetadata("citresewn", "texture", "tile");
+ if (textureProp != null) {
+ assetIdentifier = resolveAsset(properties.identifier, textureProp, "textures", ".png", resourceManager);
+ if (assetIdentifier != null)
+ textureOverrideMap.put(null, Either.left(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new ResewnTextureIdentifier(assetIdentifier))));
+ else
+ throw new CITParsingException("Cannot resolve path", properties, textureProp.position());
+ }
+
+ for (PropertyValue property : properties.get("citresewn", "texture", "tile")) {
+ textureProp = property;
+ Identifier subIdentifier = resolveAsset(properties.identifier, textureProp, "textures", ".png", resourceManager);
+ if (subIdentifier == null)
+ throw new CITParsingException("Cannot resolve path", properties, property.position());
+
+ textureOverrideMap.put(property.keyMetadata(), Either.left(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new ResewnTextureIdentifier(subIdentifier))));
+ }
+ }
+
+ if (assetIdentifiers.size() == 0)
+ throw new CITParsingException("Could not resolve a replacement model/texture", properties, -1);
+ }
+
+ public void loadUnbakedAssets(ResourceManager resourceManager) throws Exception {
+ try {
+ if (isTexture) {
+ JsonUnbakedModel itemJson = getModelForFirstItemType(resourceManager);
+ if (((JsonUnbakedModelAccessor) itemJson).getTextureMap().size() > 1) { // use(some/all of) the asset identifiers to build texture override in layered models
+ textureOverrideMap = ((JsonUnbakedModelAccessor) itemJson).getTextureMap();
+ Identifier defaultAsset = assetIdentifiers.get(null);
+ textureOverrideMap.replaceAll((layerName, originalTextureEither) -> {
+ Identifier textureIdentifier = assetIdentifiers.remove(originalTextureEither.map(SpriteIdentifier::getTextureId, Identifier::new));
+ if (textureIdentifier != null)
+ return Either.left(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new ResewnTextureIdentifier(textureIdentifier)));
+ if (defaultAsset != null)
+ return Either.left(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new ResewnTextureIdentifier(defaultAsset)));
+ return null;
+ });
+
+ if (assetIdentifiers.size() == 0 || (assetIdentifiers.size() == 1 && assetIdentifiers.containsKey(null))) {
+ unbakedAssets.put(null, itemJson);
+ return;
+ }
+ }
+
+ Identifier baseIdentifier = assetIdentifiers.remove(null);
+
+ if (baseIdentifier != null)
+ unbakedAssets.put(null, loadUnbakedAsset(resourceManager, baseIdentifier));
+
+ if (!assetIdentifiers.isEmpty()) { // contains sub models
+ LinkedHashMap<Identifier, List<ModelOverride.Condition>> overrideConditions = new LinkedHashMap<>();
+ for (Item item : this.items) {
+ Identifier itemIdentifier = Registry.ITEM.getId(item);
+ overrideConditions.put(new Identifier(itemIdentifier.getNamespace(), "item/" + itemIdentifier.getPath()), Collections.emptyList());
+
+ Identifier itemModelIdentifier = new Identifier(itemIdentifier.getNamespace(), "models/item/" + itemIdentifier.getPath() + ".json");
+ try (Resource itemModelResource = resourceManager.getResource(itemModelIdentifier); Reader resourceReader = new InputStreamReader(itemModelResource.getInputStream())) {
+ JsonUnbakedModel itemModelJson = JsonUnbakedModel.deserialize(resourceReader);
+
+ if (itemModelJson.getOverrides() != null && !itemModelJson.getOverrides().isEmpty())
+ for (ModelOverride override : itemModelJson.getOverrides())
+ overrideConditions.put(override.getModelId(), override.streamConditions().toList());
+ }
+ }
+
+ ArrayList<Identifier> overrideModels = new ArrayList<>(overrideConditions.keySet());
+ Collections.reverse(overrideModels);
+
+ for (Identifier overrideModel : overrideModels) {
+ Identifier replacement = assetIdentifiers.remove(overrideModel);
+ if (replacement == null)
+ continue;
+
+ List<ModelOverride.Condition> conditions = overrideConditions.get(overrideModel);
+ unbakedAssets.put(conditions, loadUnbakedAsset(resourceManager, replacement));
+ }
+ }
+ } else { // isModel
+ Identifier baseIdentifier = assetIdentifiers.remove(null);
+
+ if (baseIdentifier != null) {
+ if (!GENERATED_SUB_CITS_SEEN.add(baseIdentifier)) // cit generated duplicate
+ baseIdentifier = new Identifier(baseIdentifier.getNamespace(), GENERATED_SUB_CITS_PREFIX + GENERATED_SUB_CITS_SEEN.size() + "_" + baseIdentifier.getPath());
+ GENERATED_SUB_CITS_SEEN.add(baseIdentifier);
+
+ JsonUnbakedModel model = loadUnbakedAsset(resourceManager, baseIdentifier);
+ unbakedAssets.put(null, model);
+
+ if (model.getOverrides().size() > 0 && textureOverrideMap.size() > 0) {
+ LinkedHashMap<Identifier, List<ModelOverride.Condition>> overrideConditions = new LinkedHashMap<>();
+
+ for (ModelOverride override : model.getOverrides())
+ overrideConditions.put(override.getModelId(), override.streamConditions().toList());
+
+ ArrayList<Identifier> overrideModels = new ArrayList<>(overrideConditions.keySet());
+ Collections.reverse(overrideModels);
+
+ for (Identifier overrideModel : overrideModels) {
+ Identifier replacement = resolveAsset(baseIdentifier, overrideModel.toString(), "models", ".json", resourceManager);
+ if (replacement != null) {
+ String subTexturePath = replacement.toString().substring(0, replacement.toString().lastIndexOf('.'));
+ final String subTextureName = subTexturePath.substring(subTexturePath.lastIndexOf('/') + 1);
+
+ replacement = baseIdentifier;
+ if (!GENERATED_SUB_CITS_SEEN.add(replacement)) // cit generated duplicate
+ replacement = new Identifier(replacement.getNamespace(), GENERATED_SUB_CITS_PREFIX + GENERATED_SUB_CITS_SEEN.size() + "_" + replacement.getPath());
+ GENERATED_SUB_CITS_SEEN.add(replacement);
+
+ JsonUnbakedModel jsonModel = loadUnbakedAsset(resourceManager, replacement);
+ jsonModel.getOverrides().clear();
+
+ ((JsonUnbakedModelAccessor) jsonModel).getTextureMap().replaceAll((layerName, texture) -> {
+ if (layerName != null)
+ try {
+ for (String subTexture : textureOverrideMap.keySet())
+ if (subTextureName.equals(subTexture))
+ return textureOverrideMap.get(subTexture);
+ } catch (Exception ignored) { }
+ return texture;
+ });
+
+ unbakedAssets.put(overrideConditions.get(overrideModel), jsonModel);
+ }
+ }
+ }
+ }
+
+ if (!assetIdentifiers.isEmpty()) { // contains sub models
+ LinkedHashMap<Identifier, List<ModelOverride.Condition>> overrideConditions = new LinkedHashMap<>();
+ for (Item item : this.items) {
+ Identifier itemIdentifier = Registry.ITEM.getId(item);
+ overrideConditions.put(new Identifier(itemIdentifier.getNamespace(), "item/" + itemIdentifier.getPath()), Collections.emptyList());
+
+ Identifier itemModelIdentifier = new Identifier(itemIdentifier.getNamespace(), "models/item/" + itemIdentifier.getPath() + ".json");
+ try (Resource itemModelResource = resourceManager.getResource(itemModelIdentifier); Reader resourceReader = new InputStreamReader(itemModelResource.getInputStream())) {
+ JsonUnbakedModel itemModelJson = JsonUnbakedModel.deserialize(resourceReader);
+
+ if (itemModelJson.getOverrides() != null && !itemModelJson.getOverrides().isEmpty())
+ for (ModelOverride override : itemModelJson.getOverrides())
+ overrideConditions.put(override.getModelId(), override.streamConditions().toList());
+ }
+ }
+
+ ArrayList<Identifier> overrideModels = new ArrayList<>(overrideConditions.keySet());
+ Collections.reverse(overrideModels);
+
+ for (Identifier overrideModel : overrideModels) {
+ Identifier replacement = assetIdentifiers.remove(overrideModel);
+ if (replacement == null)
+ continue;
+
+ if (!GENERATED_SUB_CITS_SEEN.add(replacement)) // cit generated duplicate
+ replacement = new Identifier(replacement.getNamespace(), GENERATED_SUB_CITS_PREFIX + GENERATED_SUB_CITS_SEEN.size() + "_" + replacement.getPath());
+ GENERATED_SUB_CITS_SEEN.add(replacement);
+
+ List<ModelOverride.Condition> conditions = overrideConditions.get(overrideModel);
+ unbakedAssets.put(conditions, loadUnbakedAsset(resourceManager, replacement));
+ }
+ }
+ }
+ } finally {
+ assetIdentifiers = null;
+ textureOverrideMap = null;
+ }
+ }
+
+ private JsonUnbakedModel loadUnbakedAsset(ResourceManager resourceManager, Identifier assetIdentifier) throws Exception {
+ final Identifier identifier;
+ {
+ Identifier possibleIdentifier = assetIdentifier;
+ while (possibleIdentifier.getPath().startsWith(GENERATED_SUB_CITS_PREFIX))
+ possibleIdentifier = new Identifier(possibleIdentifier.getNamespace(), possibleIdentifier.getPath().substring(possibleIdentifier.getPath().substring(GENERATED_SUB_CITS_PREFIX.length()).indexOf('_') + GENERATED_SUB_CITS_PREFIX.length() + 1));
+ identifier = possibleIdentifier;
+ }
+ JsonUnbakedModel json;
+ if (identifier.getPath().endsWith(".json")) {
+ InputStream is = null;
+ Resource resource = null;
+ try {
+ json = JsonUnbakedModel.deserialize(IOUtils.toString(is = (resource = resourceManager.getResource(identifier)).getInputStream(), StandardCharsets.UTF_8));
+ json.id = assetIdentifier.toString();
+ json.id = json.id.substring(0, json.id.length() - 5);
+
+ ((JsonUnbakedModelAccessor) json).getTextureMap().replaceAll((layer, original) -> {
+ Optional<SpriteIdentifier> left = original.left();
+ if (left.isPresent()) {
+ Identifier resolvedIdentifier = resolveAsset(identifier, left.get().getTextureId().getPath(), "textures", ".png", resourceManager);
+ if (resolvedIdentifier != null)
+ return Either.left(new SpriteIdentifier(left.get().getAtlasId(), new ResewnTextureIdentifier(resolvedIdentifier)));
+ }
+ return original;
+ });
+
+ if (textureOverrideMap.size() > 0) {
+ Map<String, Either<SpriteIdentifier, String>> jsonTextureMap = ((JsonUnbakedModelAccessor) json).getTextureMap();
+ if (jsonTextureMap.size() == 0)
+ jsonTextureMap.put("layer0", null);
+
+ final Either<SpriteIdentifier, String> defaultTextureOverride = textureOverrideMap.get(null);
+ if (defaultTextureOverride != null)
+ jsonTextureMap.replaceAll((layerName, spriteIdentifierStringEither) -> defaultTextureOverride);
+
+ //jsonTextureMap.putAll(textureOverrideMap);
+ jsonTextureMap.replaceAll((layerName, texture) -> {
+ if (layerName != null)
+ try {
+ String[] split = texture.map(id -> id.getTextureId().getPath(), s -> s).split("/");
+ String textureName = split[split.length - 1];
+ if (textureName.endsWith(".png"))
+ textureName = textureName.substring(0, textureName.length() - 4);
+ return Objects.requireNonNull(textureOverrideMap.get(textureName));
+ } catch (Exception ignored) { }
+ return texture;
+ });
+ jsonTextureMap.values().removeIf(Objects::isNull);
+ }
+
+ Identifier parentId = ((JsonUnbakedModelAccessor) json).getParentId();
+ if (parentId != null) {
+ String[] parentIdPathSplit = parentId.getPath().split("/");
+ if (parentId.getPath().startsWith("./") || (parentIdPathSplit.length > 2 && parentIdPathSplit[1].equals("cit"))) {
+ parentId = resolveAsset(identifier, parentId.getPath(), "models", ".json", resourceManager);
+ if (parentId != null)
+ ((JsonUnbakedModelAccessor) json).setParentId(new ResewnItemModelIdentifier(parentId));
+ }
+ }
+
+ json.getOverrides().replaceAll(override -> {
+ String[] modelIdPathSplit = override.getModelId().getPath().split("/");
+ if (override.getModelId().getPath().startsWith("./") || (modelIdPathSplit.length > 2 && modelIdPathSplit[1].equals("cit"))) {
+ Identifier resolvedOverridePath = resolveAsset(identifier, override.getModelId().getPath(), "models", ".json", resourceManager);
+ if (resolvedOverridePath != null)
+ return new ModelOverride(new ResewnItemModelIdentifier(resolvedOverridePath), override.streamConditions().collect(Collectors.toList()));
+ }
+
+ return override;
+ });
+
+ return json;
+ } finally {
+ IOUtils.closeQuietly(is, resource);
+ }
+ } else if (identifier.getPath().endsWith(".png")) {
+ json = getModelForFirstItemType(resourceManager);
+ if (json == null)
+ json = new JsonUnbakedModel(new Identifier("minecraft", "item/generated"), new ArrayList<>(), ImmutableMap.of("layer0", Either.left(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new ResewnTextureIdentifier(identifier)))), true, JsonUnbakedModel.GuiLight.ITEM, ModelTransformation.NONE, new ArrayList<>());
+ json.getOverrides().clear();
+ json.id = identifier.toString();
+ json.id = json.id.substring(0, json.id.length() - 4);
+
+ ((JsonUnbakedModelAccessor) json).getTextureMap().replaceAll((layerName, originalTextureEither) -> {
+ if (textureOverrideMap.size() > 0) {
+ Either<SpriteIdentifier, String> textureOverride = textureOverrideMap.get(layerName);
+ if (textureOverride == null)
+ textureOverride = textureOverrideMap.get(null);
+ return textureOverride == null ? originalTextureEither : textureOverride;
+ } else
+ return Either.left(new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, new ResewnTextureIdentifier(identifier)));
+ });
+ return json;
+ }
+
+ throw new Exception("Unknown asset type");
+ }
+
+ public Identifier fixDeprecatedSubItem(String subItem, PropertyGroup properties, int position) {
+ if (subItem == null)
+ return null;
+ String replacement = switch (subItem) {
+ case "bow_pulling_standby" -> "bow";
+ case "crossbow_standby" -> "crossbow";
+ case "potion_bottle_drinkable" -> "potion";
+ case "potion_bottle_splash" -> "splash_potion";
+ case "potion_bottle_lingering" -> "lingering_potion";
+
+
+ default -> null;
+ };
+
+ if (replacement != null) {
+ CITResewn.logWarnLoading(properties.messageWithDescriptorOf("Warning: Using deprecated sub item id \"" + subItem + "\" instead of \"" + replacement + "\"", position));
+
+ return new Identifier("minecraft", "item/" + replacement);
+ }
+
+ return null;
+ }
+
+ private JsonUnbakedModel getModelForFirstItemType(ResourceManager resourceManager) {
+ Identifier firstItemIdentifier = Registry.ITEM.getId(this.items.iterator().next()), firstItemModelIdentifier = new Identifier(firstItemIdentifier.getNamespace(), "models/item/" + firstItemIdentifier.getPath() + ".json");
+ Resource itemModelResource = null;
+ try {
+ JsonUnbakedModel json = JsonUnbakedModel.deserialize(IOUtils.toString((itemModelResource = resourceManager.getResource(firstItemModelIdentifier)).getInputStream(), StandardCharsets.UTF_8));
+
+ if (!GENERATED_SUB_CITS_SEEN.add(firstItemModelIdentifier)) // cit generated duplicate
+ firstItemModelIdentifier = new Identifier(firstItemModelIdentifier.getNamespace(), GENERATED_SUB_CITS_PREFIX + GENERATED_SUB_CITS_SEEN.size() + "_" + firstItemModelIdentifier.getPath());
+ GENERATED_SUB_CITS_SEEN.add(firstItemModelIdentifier);
+
+ json.id = firstItemModelIdentifier.toString();
+ json.id = json.id.substring(0, json.id.length() - 5);
+ return json;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ IOUtils.closeQuietly(itemModelResource);
+ }
+ }
+
+ public BakedModel getItemModel(CITContext context, int seed) {
+ ClientWorld world = context.world instanceof ClientWorld clientWorld ? clientWorld : null;
+ // get sub items or bakedModel if no sub item matches @Nullable
+ BakedModel bakedModel = bakedSubModels.apply(this.bakedModel, context.stack, world, context.entity, seed);
+
+ // apply model overrides
+ if (bakedModel != null && bakedModel.getOverrides() != null)
+ bakedModel = bakedModel.getOverrides().apply(bakedModel, context.stack, world, context.entity, seed);
+
+ return bakedModel;
+ }
+
+ public static class CITOverrideList extends ModelOverrideList {
+ public void override(List<ModelOverride.Condition> key, BakedModel bakedModel) {
+ Set<Identifier> conditionTypes = new LinkedHashSet<>(Arrays.asList(this.conditionTypes));
+ for (ModelOverride.Condition condition : key)
+ conditionTypes.add(condition.getType());
+ this.conditionTypes = conditionTypes.toArray(new Identifier[0]);
+
+ this.overrides = Arrays.copyOf(this.overrides, this.overrides.length + 1);
+
+ Object2IntMap<Identifier> object2IntMap = new Object2IntOpenHashMap<>();
+ for(int i = 0; i < this.conditionTypes.length; ++i)
+ object2IntMap.put(this.conditionTypes[i], i);
+
+ this.overrides[this.overrides.length - 1] = new BakedOverride(
+ key.stream()
+ .map((condition) -> new InlinedCondition(object2IntMap.getInt(condition.getType()), condition.getThreshold()))
+ .toArray(InlinedCondition[]::new)
+ , bakedModel);
+ }
+ }
+
+ public static class Container extends CITTypeContainer<TypeItem> {
+ public Container() {
+ super(TypeItem.class, TypeItem::new, "item");
+ }
+
+ public Set<CIT<TypeItem>> loaded = new HashSet<>();
+ public Map<Item, Set<CIT<TypeItem>>> loadedTyped = new IdentityHashMap<>();
+
+ @Override
+ public void load(List<CIT<TypeItem>> parsedCITs) {
+ loaded.addAll(parsedCITs);
+ for (CIT<TypeItem> cit : parsedCITs)
+ for (CITCondition condition : cit.conditions)
+ if (condition instanceof ConditionItems items)
+ for (Item item : items.items)
+ if (item != null)
+ loadedTyped.computeIfAbsent(item, i -> new LinkedHashSet<>()).add(cit);
+ }
+
+ @Override
+ public void dispose() {
+ loaded.clear();
+ loadedTyped.clear();
+ }
+
+ public CIT<TypeItem> getCIT(CITContext context, int seed) {
+ return ((CITCacheItem) (Object) context.stack).citresewn$getCacheTypeItem().get(context).get();
+ }
+
+ public CIT<TypeItem> getRealTimeCIT(CITContext context) {
+ Set<CIT<TypeItem>> loadedForItemType = loadedTyped.get(context.stack.getItem());
+ if (loadedForItemType != null)
+ for (CIT<TypeItem> cit : loadedForItemType)
+ if (cit.test(context))
+ return cit;
+
+ return null;
+ }
+ }
+
+ public interface CITCacheItem {
+ CITCache.Single<TypeItem> citresewn$getCacheTypeItem();
+ }
+
+ public interface BakedModelManagerMixinAccess {
+ void citresewn$forceMojankModel(BakedModel model);
+ }
+} \ No newline at end of file
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnItemModelIdentifier.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnItemModelIdentifier.java
new file mode 100644
index 0000000..498f61f
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnItemModelIdentifier.java
@@ -0,0 +1,16 @@
+package shcm.shsupercm.fabric.citresewn.defaults.common;
+
+import net.minecraft.util.Identifier;
+
+/**
+ * Marks models as cit models.
+ */
+public class ResewnItemModelIdentifier extends Identifier {
+ public ResewnItemModelIdentifier(String id) {
+ super(id);
+ }
+
+ public ResewnItemModelIdentifier(Identifier identifier) {
+ super(identifier.getNamespace(), identifier.getPath());
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnTextureIdentifier.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnTextureIdentifier.java
new file mode 100644
index 0000000..a6dd2ef
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/common/ResewnTextureIdentifier.java
@@ -0,0 +1,12 @@
+package shcm.shsupercm.fabric.citresewn.defaults.common;
+
+import net.minecraft.util.Identifier;
+
+/**
+ * Marks path identifiers as forced literal texture paths.
+ */
+public class ResewnTextureIdentifier extends Identifier {
+ public ResewnTextureIdentifier(Identifier identifier) {
+ super(identifier.getNamespace(), identifier.getPath());
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfig.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfig.java
new file mode 100644
index 0000000..41126d2
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfig.java
@@ -0,0 +1,50 @@
+package shcm.shsupercm.fabric.citresewn.defaults.config;
+
+import com.google.gson.Gson;
+import com.google.gson.stream.JsonWriter;
+import org.apache.commons.io.IOUtils;
+import shcm.shsupercm.fabric.citresewn.CITResewn;
+
+import java.io.*;
+
+public class CITResewnDefaultsConfig {
+ public float type_enchantment_scroll_multiplier = 1f;
+
+ private static final File FILE = new File("config/citresewn-defaults.json");
+
+ public static final CITResewnDefaultsConfig INSTANCE = read();
+
+ public static CITResewnDefaultsConfig read() {
+ if (!FILE.exists())
+ return new CITResewnDefaultsConfig().write();
+
+ Reader reader = null;
+ try {
+ return new Gson().fromJson(reader = new FileReader(FILE), CITResewnDefaultsConfig.class);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ IOUtils.closeQuietly(reader);
+ }
+ }
+
+ public CITResewnDefaultsConfig write() {
+ Gson gson = new Gson();
+ JsonWriter writer = null;
+ try {
+ FILE.getParentFile().mkdirs();
+ writer = gson.newJsonWriter(new FileWriter(FILE));
+ writer.setIndent(" ");
+
+ gson.toJson(gson.toJsonTree(this, CITResewnDefaultsConfig.class), writer);
+ } catch (Exception e) {
+ CITResewn.LOG.error("Couldn't save defaults config");
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } finally {
+ IOUtils.closeQuietly(writer);
+ }
+ return this;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfigScreenFactory.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfigScreenFactory.java
new file mode 100644
index 0000000..95b0579
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsConfigScreenFactory.java
@@ -0,0 +1,33 @@
+package shcm.shsupercm.fabric.citresewn.defaults.config;
+
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import me.shedaniel.clothconfig2.api.ConfigBuilder;
+import me.shedaniel.clothconfig2.api.ConfigCategory;
+import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.text.LiteralText;
+import net.minecraft.text.TranslatableText;
+import shcm.shsupercm.fabric.citresewn.config.CITResewnConfigScreenFactory;
+
+public class CITResewnDefaultsConfigScreenFactory {
+ @Entrypoint(CITResewnConfigScreenFactory.DEFAULTS_CONFIG_ENTRYPOINT)
+ public static Screen create(Screen parent) {
+ CITResewnDefaultsConfig currentConfig = CITResewnDefaultsConfig.INSTANCE, defaultConfig = new CITResewnDefaultsConfig();
+
+ ConfigBuilder builder = ConfigBuilder.create()
+ .setParentScreen(parent)
+ .setTitle(new TranslatableText("config.citresewn-defaults.title"))
+ .setSavingRunnable(currentConfig::write);
+
+ ConfigCategory category = builder.getOrCreateCategory(new LiteralText(""));
+ ConfigEntryBuilder entryBuilder = builder.entryBuilder();
+
+ category.addEntry(entryBuilder.startFloatField(new TranslatableText("config.citresewn-defaults.type_enchantment_scroll_multiplier.title"), currentConfig.type_enchantment_scroll_multiplier)
+ .setTooltip(new TranslatableText("config.citresewn-defaults.type_enchantment_scroll_multiplier.tooltip"))
+ .setSaveConsumer(newConfig -> currentConfig.type_enchantment_scroll_multiplier = newConfig)
+ .setDefaultValue(defaultConfig.type_enchantment_scroll_multiplier)
+ .build());
+
+ return builder.build();
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsModMenu.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsModMenu.java
new file mode 100644
index 0000000..48edf33
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/config/CITResewnDefaultsModMenu.java
@@ -0,0 +1,27 @@
+package shcm.shsupercm.fabric.citresewn.defaults.config;
+
+import com.terraformersmc.modmenu.api.ConfigScreenFactory;
+import com.terraformersmc.modmenu.api.ModMenuApi;
+import io.shcm.shsupercm.fabric.fletchingtable.api.Entrypoint;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.screen.NoticeScreen;
+import net.minecraft.text.Text;
+
+@Entrypoint("modmenu")
+public class CITResewnDefaultsModMenu implements ModMenuApi {
+ @Override
+ public ConfigScreenFactory<?> getModConfigScreenFactory() {
+ if (FabricLoader.getInstance().isModLoaded("cloth-config2"))
+ return new ClothConfigOpenImpl().getModConfigScreenFactory();
+
+ return parent -> new NoticeScreen(() -> MinecraftClient.getInstance().setScreen(parent), Text.of("CIT Resewn: Defaults"), Text.of("CIT Resewn requires Cloth Config to be able to show the config."));
+ }
+
+ private static class ClothConfigOpenImpl implements ModMenuApi {
+ @Override
+ public ConfigScreenFactory<?> getModConfigScreenFactory() {
+ return CITResewnDefaultsConfigScreenFactory::create;
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/ModelLoaderMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/ModelLoaderMixin.java
new file mode 100644
index 0000000..8ed0e20
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/ModelLoaderMixin.java
@@ -0,0 +1,87 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.common;
+
+import com.mojang.datafixers.util.Either;
+import net.minecraft.client.render.model.ModelLoader;
+import net.minecraft.client.render.model.json.JsonUnbakedModel;
+import net.minecraft.client.render.model.json.ModelOverride;
+import net.minecraft.client.util.SpriteIdentifier;
+import net.minecraft.resource.Resource;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.util.Identifier;
+import org.apache.commons.io.IOUtils;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import shcm.shsupercm.fabric.citresewn.cit.CITType;
+import shcm.shsupercm.fabric.citresewn.defaults.common.ResewnItemModelIdentifier;
+import shcm.shsupercm.fabric.citresewn.defaults.common.ResewnTextureIdentifier;
+import shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item.JsonUnbakedModelAccessor;
+
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * Will be rewritten at some point.
+ */
+@Mixin(ModelLoader.class)
+public class ModelLoaderMixin {
+ @Shadow @Final private ResourceManager resourceManager;
+
+ @Inject(method = "loadModelFromJson", cancellable = true, at = @At("HEAD"))
+ public void citresewn$forceLiteralResewnModelIdentifier(Identifier id, CallbackInfoReturnable<JsonUnbakedModel> cir) {
+ if (id instanceof ResewnItemModelIdentifier) {
+ InputStream is = null;
+ Resource resource = null;
+ try {
+ JsonUnbakedModel json = JsonUnbakedModel.deserialize(IOUtils.toString(is = (resource = resourceManager.getResource(id)).getInputStream(), StandardCharsets.UTF_8));
+ json.id = id.toString();
+ json.id = json.id.substring(0, json.id.length() - 5);
+
+ ((JsonUnbakedModelAccessor) json).getTextureMap().replaceAll((layer, original) -> {
+ Optional<SpriteIdentifier> left = original.left();
+ if (left.isPresent()) {
+ String originalPath = left.get().getTextureId().getPath();
+ String[] split = originalPath.split("/");
+ if (originalPath.startsWith("./") || (split.length > 2 && split[1].equals("cit"))) {
+ Identifier resolvedIdentifier = CITType.resolveAsset(id, originalPath, "textures", ".png", resourceManager);
+ if (resolvedIdentifier != null)
+ return Either.left(new SpriteIdentifier(left.get().getAtlasId(), new ResewnTextureIdentifier(resolvedIdentifier)));
+ }
+ }
+ return original;
+ });
+
+ Identifier parentId = ((JsonUnbakedModelAccessor) json).getParentId();
+ if (parentId != null) {
+ String[] parentIdPathSplit = parentId.getPath().split("/");
+ if (parentId.getPath().startsWith("./") || (parentIdPathSplit.length > 2 && parentIdPathSplit[1].equals("cit"))) {
+ parentId = CITType.resolveAsset(id, parentId.getPath(), "models", ".json", resourceManager);
+ if (parentId != null)
+ ((JsonUnbakedModelAccessor) json).setParentId(new ResewnItemModelIdentifier(parentId));
+ }
+ }
+
+ json.getOverrides().replaceAll(override -> {
+ String[] modelIdPathSplit = override.getModelId().getPath().split("/");
+ if (override.getModelId().getPath().startsWith("./") || (modelIdPathSplit.length > 2 && modelIdPathSplit[1].equals("cit"))) {
+ Identifier resolvedOverridePath = CITType.resolveAsset(id, override.getModelId().getPath(), "models", ".json", resourceManager);
+ if (resolvedOverridePath != null)
+ return new ModelOverride(new ResewnItemModelIdentifier(resolvedOverridePath), override.streamConditions().collect(Collectors.toList()));
+ }
+
+ return override;
+ });
+
+ cir.setReturnValue(json);
+ } catch (Exception ignored) {
+ } finally {
+ IOUtils.closeQuietly(is, resource);
+ }
+ }
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/SpriteAtlasTextureMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/SpriteAtlasTextureMixin.java
new file mode 100644
index 0000000..61eff5c
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/common/SpriteAtlasTextureMixin.java
@@ -0,0 +1,18 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.common;
+
+import net.minecraft.client.texture.SpriteAtlasTexture;
+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 shcm.shsupercm.fabric.citresewn.defaults.common.ResewnTextureIdentifier;
+
+@Mixin(SpriteAtlasTexture.class)
+public class SpriteAtlasTextureMixin {
+ @Inject(method = "getTexturePath", cancellable = true, at = @At("HEAD"))
+ public void forceLiteralResewnTextureIdentifier(Identifier id, CallbackInfoReturnable<Identifier> cir) {
+ if (id instanceof ResewnTextureIdentifier)
+ cir.setReturnValue(id);
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ArmorFeatureRendererMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ArmorFeatureRendererMixin.java
new file mode 100644
index 0000000..d61af4c
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ArmorFeatureRendererMixin.java
@@ -0,0 +1,51 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.armor;
+
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.ArmorItem;
+import net.minecraft.item.ItemStack;
+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.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import shcm.shsupercm.fabric.citresewn.cit.CIT;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeArmor;
+
+import java.util.Map;
+
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeArmor.CONTAINER;
+
+@Mixin(ArmorFeatureRenderer.class)
+public class ArmorFeatureRendererMixin<T extends LivingEntity, M extends BipedEntityModel<T>, A extends BipedEntityModel<T>> {
+ private Map<String, Identifier> citresewn$cachedTextures = null;
+
+ @Inject(method = "renderArmor", at = @At("HEAD"))
+ public void citresewn$renderArmor(MatrixStack matrices, VertexConsumerProvider vertexConsumers, T entity, EquipmentSlot armorSlot, int light, A model, CallbackInfo ci) {
+ citresewn$cachedTextures = null;
+ if (!CONTAINER.active())
+ return;
+
+ ItemStack equippedStack = entity.getEquippedStack(armorSlot);
+
+ CIT<TypeArmor> cit = CONTAINER.getCIT(new CITContext(equippedStack, entity.getWorld(), entity));
+ if (cit != null)
+ citresewn$cachedTextures = cit.type.textures;
+ }
+
+ @Inject(method = "getArmorTexture", cancellable = true, at = @At("HEAD"))
+ private void citresewn$getArmorTexture(ArmorItem item, boolean legs, String overlay, CallbackInfoReturnable<Identifier> cir) {
+ if (citresewn$cachedTextures == null)
+ return;
+
+ Identifier identifier = citresewn$cachedTextures.get(item.getMaterial().getName() + "_layer_" + (legs ? "2" : "1") + (overlay == null ? "" : "_" + overlay));
+ if (identifier != null)
+ cir.setReturnValue(identifier);
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ItemStackMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ItemStackMixin.java
new file mode 100644
index 0000000..85b0d22
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/armor/ItemStackMixin.java
@@ -0,0 +1,16 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.armor;
+
+import net.minecraft.item.ItemStack;
+import org.spongepowered.asm.mixin.Mixin;
+import shcm.shsupercm.fabric.citresewn.cit.CITCache;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeArmor;
+
+@Mixin(ItemStack.class)
+public class ItemStackMixin implements TypeArmor.CITCacheArmor {
+ private final CITCache.Single<TypeArmor> citresewn$cacheTypeArmor = new CITCache.Single<>(TypeArmor.CONTAINER::getRealTimeCIT);
+
+ @Override
+ public CITCache.Single<TypeArmor> citresewn$getCacheTypeArmor() {
+ return this.citresewn$cacheTypeArmor;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ElytraFeatureRendererMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ElytraFeatureRendererMixin.java
new file mode 100644
index 0000000..0772adf
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ElytraFeatureRendererMixin.java
@@ -0,0 +1,42 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.elytra;
+
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.feature.ElytraFeatureRenderer;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Mutable;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import shcm.shsupercm.fabric.citresewn.cit.CIT;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeElytra;
+
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeElytra.CONTAINER;
+
+@Mixin(ElytraFeatureRenderer.class)
+public class ElytraFeatureRendererMixin {
+ @Shadow @Mutable @Final private static Identifier SKIN;
+
+ private final static Identifier citresewn$ORIGINAL_SKIN = SKIN;
+
+ @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFFFFF)V", at = @At("HEAD"))
+ public void citresewn$render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, LivingEntity livingEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) {
+ if (!CONTAINER.active())
+ return;
+
+ ItemStack equippedStack = livingEntity.getEquippedStack(EquipmentSlot.CHEST);
+ if (!equippedStack.isOf(Items.ELYTRA))
+ return;
+
+ CIT<TypeElytra> cit = CONTAINER.getCIT(new CITContext(equippedStack, livingEntity.getWorld(), livingEntity));
+ SKIN = cit == null ? citresewn$ORIGINAL_SKIN : cit.type.texture;
+ }
+} \ No newline at end of file
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ItemStackMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ItemStackMixin.java
new file mode 100644
index 0000000..a751fb9
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/elytra/ItemStackMixin.java
@@ -0,0 +1,16 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.elytra;
+
+import net.minecraft.item.ItemStack;
+import org.spongepowered.asm.mixin.Mixin;
+import shcm.shsupercm.fabric.citresewn.cit.CITCache;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeElytra;
+
+@Mixin(ItemStack.class)
+public class ItemStackMixin implements TypeElytra.CITCacheElytra {
+ private final CITCache.Single<TypeElytra> citresewn$cacheTypeElytra = new CITCache.Single<>(TypeElytra.CONTAINER::getRealTimeCIT);
+
+ @Override
+ public CITCache.Single<TypeElytra> citresewn$getCacheTypeElytra() {
+ return this.citresewn$cacheTypeElytra;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ArmorFeatureRendererMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ArmorFeatureRendererMixin.java
new file mode 100644
index 0000000..4a852ca
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ArmorFeatureRendererMixin.java
@@ -0,0 +1,30 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.feature.ArmorFeatureRenderer;
+import net.minecraft.client.render.entity.model.BipedEntityModel;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+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;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeEnchantment.CONTAINER;
+
+@Mixin(ArmorFeatureRenderer.class)
+public class ArmorFeatureRendererMixin<T extends LivingEntity, M extends BipedEntityModel<T>, A extends BipedEntityModel<T>> {
+ @Inject(method = "renderArmor", at = @At("HEAD"))
+ private void citresewn$enchantment$setAppliedContextAndStartApplyingArmor(MatrixStack matrices, VertexConsumerProvider vertexConsumers, T livingEntity, EquipmentSlot armorSlot, int light, A model, CallbackInfo ci) {
+ if (CONTAINER.active())
+ CONTAINER.setContext(new CITContext(livingEntity.getEquippedStack(armorSlot), livingEntity.world, livingEntity)).apply();
+ }
+
+ @Inject(method = "renderArmor", at = @At("RETURN"))
+ private void citresewn$enchantment$stopApplyingArmor(MatrixStack matrices, VertexConsumerProvider vertexConsumers, T livingEntity, EquipmentSlot armorSlot, int light, A model, CallbackInfo ci) {
+ if (CONTAINER.active())
+ CONTAINER.setContext(null);
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/BufferBuilderStorageAccessor.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/BufferBuilderStorageAccessor.java
new file mode 100644
index 0000000..e23e091
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/BufferBuilderStorageAccessor.java
@@ -0,0 +1,15 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+import net.minecraft.client.render.BufferBuilder;
+import net.minecraft.client.render.BufferBuilderStorage;
+import net.minecraft.client.render.RenderLayer;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.SortedMap;
+
+@Mixin(BufferBuilderStorage.class)
+public interface BufferBuilderStorageAccessor {
+ @Accessor
+ SortedMap<RenderLayer, BufferBuilder> getEntityBuilders();
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ElytraFeatureRendererMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ElytraFeatureRendererMixin.java
new file mode 100644
index 0000000..c64fb77
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ElytraFeatureRendererMixin.java
@@ -0,0 +1,29 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.entity.feature.ElytraFeatureRenderer;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.EquipmentSlot;
+import net.minecraft.entity.LivingEntity;
+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;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeEnchantment.CONTAINER;
+
+@Mixin(ElytraFeatureRenderer.class)
+public class ElytraFeatureRendererMixin {
+ @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFFFFF)V", at = @At("HEAD"))
+ private void citresewn$enchantment$setAppliedContextAndStartApplyingElytra(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, LivingEntity livingEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) {
+ if (CONTAINER.active())
+ CONTAINER.setContext(new CITContext(livingEntity.getEquippedStack(EquipmentSlot.CHEST), livingEntity.world, livingEntity)).apply();
+ }
+
+ @Inject(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/entity/LivingEntity;FFFFFF)V", at = @At("RETURN"))
+ private void citresewn$enchantment$stopApplyingElytra(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, LivingEntity livingEntity, float f, float g, float h, float j, float k, float l, CallbackInfo ci) {
+ if (CONTAINER.active())
+ CONTAINER.setContext(null);
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemRendererMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemRendererMixin.java
new file mode 100644
index 0000000..b4bd37d
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemRendererMixin.java
@@ -0,0 +1,86 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.*;
+import net.minecraft.client.render.item.ItemRenderer;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.json.ModelTransformation;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.ItemStack;
+import net.minecraft.world.World;
+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;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeEnchantment;
+
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeEnchantment.CONTAINER;
+
+@Mixin(value = ItemRenderer.class, priority = 200)
+public class ItemRendererMixin {
+ @Inject(method = "getModel", at = @At("HEAD"))
+ private void citresewn$enchantment$setAppliedContext(ItemStack stack, World world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
+ if (CONTAINER.active())
+ CONTAINER.setContext(new CITContext(stack, world, entity));
+ }
+
+ @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformation$Mode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", at = @At("HEAD"))
+ private void citresewn$enchantment$startApplyingItem(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
+ if (CONTAINER.active())
+ CONTAINER.apply();
+ }
+
+ @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformation$Mode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", at = @At("RETURN"))
+ private void citresewn$enchantment$stopApplyingItem(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
+ if (CONTAINER.active())
+ CONTAINER.setContext(null);
+ }
+
+ @Inject(method = "getArmorGlintConsumer", cancellable = true, at = @At("RETURN"))
+ private static void citresewn$enchantment$getArmorGlintConsumer(VertexConsumerProvider provider, RenderLayer layer, boolean solid, boolean glint, CallbackInfoReturnable<VertexConsumer> cir) {
+ if (!CONTAINER.shouldApply())
+ return;
+ VertexConsumer vertexConsumer = solid ? TypeEnchantment.GlintRenderLayer.ARMOR_GLINT.tryApply(cir.getReturnValue(), layer, provider) : TypeEnchantment.GlintRenderLayer.ARMOR_ENTITY_GLINT.tryApply(cir.getReturnValue(), layer, provider);
+ if (vertexConsumer != null)
+ cir.setReturnValue(vertexConsumer);
+ }
+
+ @Inject(method = "getCompassGlintConsumer", cancellable = true, at = @At("RETURN"))
+ private static void citresewn$enchantment$getCompassGlintConsumer(VertexConsumerProvider provider, RenderLayer layer, MatrixStack.Entry entry, CallbackInfoReturnable<VertexConsumer> cir) {
+ if (!CONTAINER.shouldApply())
+ return;
+ VertexConsumer vertexConsumer = TypeEnchantment.GlintRenderLayer.GLINT.tryApply(null, layer, provider);
+ if (vertexConsumer != null)
+ cir.setReturnValue(VertexConsumers.union(new OverlayVertexConsumer(vertexConsumer, entry.getPositionMatrix(), entry.getNormalMatrix()), cir.getReturnValue()));
+ }
+
+ @Inject(method = "getDirectCompassGlintConsumer", cancellable = true, at = @At("RETURN"))
+ private static void citresewn$enchantment$getDirectCompassGlintConsumer(VertexConsumerProvider provider, RenderLayer layer, MatrixStack.Entry entry, CallbackInfoReturnable<VertexConsumer> cir) {
+ if (!CONTAINER.shouldApply())
+ return;
+ VertexConsumer vertexConsumer = TypeEnchantment.GlintRenderLayer.DIRECT_GLINT.tryApply(null, layer, provider);
+ if (vertexConsumer != null)
+ cir.setReturnValue(VertexConsumers.union(new OverlayVertexConsumer(vertexConsumer, entry.getPositionMatrix(), entry.getNormalMatrix()), cir.getReturnValue()));
+ }
+
+ @Inject(method = "getItemGlintConsumer", cancellable = true, at = @At("RETURN"))
+ private static void citresewn$enchantment$getItemGlintConsumer(VertexConsumerProvider provider, RenderLayer layer, boolean solid, boolean glint, CallbackInfoReturnable<VertexConsumer> cir) {
+ if (!CONTAINER.shouldApply())
+ return;
+ VertexConsumer vertexConsumer = MinecraftClient.isFabulousGraphicsOrBetter() && layer == TexturedRenderLayers.getItemEntityTranslucentCull() ? TypeEnchantment.GlintRenderLayer.GLINT_TRANSLUCENT.tryApply(cir.getReturnValue(), layer, provider) : (solid ? TypeEnchantment.GlintRenderLayer.GLINT.tryApply(cir.getReturnValue(), layer, provider) : TypeEnchantment.GlintRenderLayer.ENTITY_GLINT.tryApply(cir.getReturnValue(), layer, provider));
+ if (vertexConsumer != null)
+ cir.setReturnValue(vertexConsumer);
+ }
+
+ @Inject(method = "getDirectItemGlintConsumer", cancellable = true, at = @At("RETURN"))
+ private static void citresewn$enchantment$getDirectItemGlintConsumer(VertexConsumerProvider provider, RenderLayer layer, boolean solid, boolean glint, CallbackInfoReturnable<VertexConsumer> cir) {
+ if (!CONTAINER.shouldApply())
+ return;
+ VertexConsumer vertexConsumer = solid ? TypeEnchantment.GlintRenderLayer.DIRECT_GLINT.tryApply(cir.getReturnValue(), layer, provider) : TypeEnchantment.GlintRenderLayer.DIRECT_ENTITY_GLINT.tryApply(cir.getReturnValue(), layer, provider);
+ if (vertexConsumer != null)
+ cir.setReturnValue(vertexConsumer);
+ }
+} \ No newline at end of file
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemStackMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemStackMixin.java
new file mode 100644
index 0000000..d49e116
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/ItemStackMixin.java
@@ -0,0 +1,25 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+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.CallbackInfoReturnable;
+import shcm.shsupercm.fabric.citresewn.cit.CITCache;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeEnchantment;
+
+@Mixin(ItemStack.class)
+public class ItemStackMixin implements TypeEnchantment.CITCacheEnchantment {
+ private final CITCache.MultiList<TypeEnchantment> citresewn$cacheTypeEnchantment = new CITCache.MultiList<>(TypeEnchantment.CONTAINER::getRealTimeCIT);
+
+ @Override
+ public CITCache.MultiList<TypeEnchantment> citresewn$getCacheTypeEnchantment() {
+ return this.citresewn$cacheTypeEnchantment;
+ }
+
+ @Inject(method = "hasGlint", cancellable = true, at = @At("HEAD"))
+ private void citresewn$enchantment$disableDefaultGlint(CallbackInfoReturnable<Boolean> cir) {
+ if (TypeEnchantment.CONTAINER.shouldNotApplyDefaultGlint())
+ cir.setReturnValue(false);
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/MinecraftClientMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/MinecraftClientMixin.java
new file mode 100644
index 0000000..e8b346b
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/MinecraftClientMixin.java
@@ -0,0 +1,16 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+import net.minecraft.client.MinecraftClient;
+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;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeEnchantment;
+
+@Mixin(MinecraftClient.class)
+public class MinecraftClientMixin {
+ @Inject(method = "tick", at = @At("HEAD"))
+ public void onTick(CallbackInfo ci) {
+ TypeEnchantment.MergeMethodIntensity.MergeMethod.ticks++;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/RenderPhaseAccessor.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/RenderPhaseAccessor.java
new file mode 100644
index 0000000..b2a59b4
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/enchantment/RenderPhaseAccessor.java
@@ -0,0 +1,21 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.enchantment;
+
+import net.minecraft.client.render.RenderPhase;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(RenderPhase.class)
+public interface RenderPhaseAccessor {
+ @Accessor("ARMOR_GLINT_SHADER") static RenderPhase.Shader ARMOR_GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("ARMOR_ENTITY_GLINT_SHADER") static RenderPhase.Shader ARMOR_ENTITY_GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("TRANSLUCENT_GLINT_SHADER") static RenderPhase.Shader TRANSLUCENT_GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("GLINT_SHADER") static RenderPhase.Shader GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("DIRECT_GLINT_SHADER") static RenderPhase.Shader DIRECT_GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("ENTITY_GLINT_SHADER") static RenderPhase.Shader ENTITY_GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("DIRECT_ENTITY_GLINT_SHADER") static RenderPhase.Shader DIRECT_ENTITY_GLINT_SHADER() { throw new RuntimeException(); }
+ @Accessor("DISABLE_CULLING") static RenderPhase.Cull DISABLE_CULLING() { throw new RuntimeException(); }
+ @Accessor("EQUAL_DEPTH_TEST") static RenderPhase.DepthTest EQUAL_DEPTH_TEST() { throw new RuntimeException(); }
+ @Accessor("COLOR_MASK") static RenderPhase.WriteMaskState COLOR_MASK() { throw new RuntimeException(); }
+ @Accessor("VIEW_OFFSET_Z_LAYERING") static RenderPhase.Layering VIEW_OFFSET_Z_LAYERING() { throw new RuntimeException(); }
+ @Accessor("ITEM_TARGET") static RenderPhase.Target ITEM_TARGET() { throw new RuntimeException(); }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/BakedModelManagerMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/BakedModelManagerMixin.java
new file mode 100644
index 0000000..f7f6b48
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/BakedModelManagerMixin.java
@@ -0,0 +1,29 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item;
+
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.BakedModelManager;
+import net.minecraft.client.util.ModelIdentifier;
+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 shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeItem;
+
+@Mixin(BakedModelManager.class)
+public class BakedModelManagerMixin implements TypeItem.BakedModelManagerMixinAccess {
+ private BakedModel citresewn$forcedMojankModel = null;
+
+ @Inject(method = "getModel", cancellable = true, at =
+ @At("HEAD"))
+ private void citresewn$getCITMojankModel(ModelIdentifier id, CallbackInfoReturnable<BakedModel> cir) {
+ if (citresewn$forcedMojankModel != null) {
+ cir.setReturnValue(citresewn$forcedMojankModel);
+ citresewn$forcedMojankModel = null;
+ }
+ }
+
+ @Override
+ public void citresewn$forceMojankModel(BakedModel model) {
+ this.citresewn$forcedMojankModel = model;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemRendererMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemRendererMixin.java
new file mode 100644
index 0000000..5f59329
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemRendererMixin.java
@@ -0,0 +1,68 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item;
+
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.render.item.ItemModels;
+import net.minecraft.client.render.item.ItemRenderer;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.json.ModelTransformation;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.entity.LivingEntity;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import shcm.shsupercm.fabric.citresewn.cit.CIT;
+import shcm.shsupercm.fabric.citresewn.cit.CITContext;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeItem;
+
+import java.lang.ref.WeakReference;
+
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeItem.CONTAINER;
+
+/**
+ * Do not go through this class, it looks awful because it was ported from a "proof of concept".<br>
+ * The whole type will be rewritten at some point.
+ */
+@Mixin(ItemRenderer.class)
+public class ItemRendererMixin {
+ @Shadow @Final private ItemModels models;
+
+ private WeakReference<BakedModel> citresewn$mojankCITModel = null;
+
+ @Inject(method = "getModel", cancellable = true, at = @At("HEAD"))
+ private void citresewn$getItemModel(ItemStack stack, World world, LivingEntity entity, int seed, CallbackInfoReturnable<BakedModel> cir) {
+ if (!CONTAINER.active())
+ return;
+
+ CITContext context = new CITContext(stack, world, entity);
+ CIT<TypeItem> cit = CONTAINER.getCIT(context, seed);
+ citresewn$mojankCITModel = null;
+ if (cit != null) {
+ BakedModel citModel = cit.type.getItemModel(context, seed);
+
+ if (citModel != null) {
+ if (stack.isOf(Items.TRIDENT) || stack.isOf(Items.SPYGLASS)) {
+ citresewn$mojankCITModel = new WeakReference<>(citModel);
+ } else
+ cir.setReturnValue(citModel);
+ }
+ }
+ }
+
+ @Inject(method = "renderItem(Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/render/model/json/ModelTransformation$Mode;ZLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;IILnet/minecraft/client/render/model/BakedModel;)V", at = @At("HEAD"))
+ private void citresewn$fixMojankCITsContext(ItemStack stack, ModelTransformation.Mode renderMode, boolean leftHanded, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay, BakedModel model, CallbackInfo ci) {
+ if (!CONTAINER.active() || citresewn$mojankCITModel == null)
+ return;
+
+ if (renderMode == ModelTransformation.Mode.GUI || renderMode == ModelTransformation.Mode.GROUND || renderMode == ModelTransformation.Mode.FIXED)
+ ((TypeItem.BakedModelManagerMixinAccess) this.models.getModelManager()).citresewn$forceMojankModel(citresewn$mojankCITModel.get());
+
+ citresewn$mojankCITModel = null;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemStackMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemStackMixin.java
new file mode 100644
index 0000000..450d8a3
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ItemStackMixin.java
@@ -0,0 +1,16 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item;
+
+import net.minecraft.item.ItemStack;
+import org.spongepowered.asm.mixin.Mixin;
+import shcm.shsupercm.fabric.citresewn.cit.CITCache;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeItem;
+
+@Mixin(ItemStack.class)
+public class ItemStackMixin implements TypeItem.CITCacheItem {
+ private final CITCache.Single<TypeItem> citresewn$cacheTypeItem = new CITCache.Single<>(TypeItem.CONTAINER::getRealTimeCIT);
+
+ @Override
+ public CITCache.Single<TypeItem> citresewn$getCacheTypeItem() {
+ return this.citresewn$cacheTypeItem;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/JsonUnbakedModelAccessor.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/JsonUnbakedModelAccessor.java
new file mode 100644
index 0000000..350d01a
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/JsonUnbakedModelAccessor.java
@@ -0,0 +1,22 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item;
+
+import com.mojang.datafixers.util.Either;
+import net.minecraft.client.render.model.json.JsonUnbakedModel;
+import net.minecraft.client.util.SpriteIdentifier;
+import net.minecraft.util.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.Map;
+
+@Mixin(JsonUnbakedModel.class)
+public interface JsonUnbakedModelAccessor {
+ @Accessor
+ Map<String, Either<SpriteIdentifier, String>> getTextureMap();
+
+ @Accessor
+ Identifier getParentId();
+
+ @Accessor
+ void setParentId(Identifier parentId);
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ModelLoaderMixin.java b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ModelLoaderMixin.java
new file mode 100644
index 0000000..93bab6a
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/fabric/citresewn/defaults/mixin/types/item/ModelLoaderMixin.java
@@ -0,0 +1,99 @@
+package shcm.shsupercm.fabric.citresewn.defaults.mixin.types.item;
+
+import net.minecraft.client.color.block.BlockColors;
+import net.minecraft.client.render.model.BakedModel;
+import net.minecraft.client.render.model.ModelLoader;
+import net.minecraft.client.render.model.SpriteAtlasManager;
+import net.minecraft.client.render.model.UnbakedModel;
+import net.minecraft.client.render.model.json.JsonUnbakedModel;
+import net.minecraft.client.render.model.json.ModelOverride;
+import net.minecraft.client.texture.TextureManager;
+import net.minecraft.resource.ResourceManager;
+import net.minecraft.util.Identifier;
+import net.minecraft.util.profiler.Profiler;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.ModifyArg;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import shcm.shsupercm.fabric.citresewn.CITResewn;
+import shcm.shsupercm.fabric.citresewn.cit.CIT;
+import shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeItem;
+import shcm.shsupercm.fabric.citresewn.defaults.common.ResewnItemModelIdentifier;
+
+import java.util.*;
+
+import static shcm.shsupercm.fabric.citresewn.CITResewn.info;
+import static shcm.shsupercm.fabric.citresewn.defaults.cit.types.TypeItem.CONTAINER;
+
+@Mixin(ModelLoader.class)
+public class ModelLoaderMixin {
+ @Shadow @Final private Set<Identifier> modelsToLoad;
+ @Shadow @Final private Map<Identifier, UnbakedModel> modelsToBake;
+ @Shadow @Final private Map<Identifier, UnbakedModel> unbakedModels;
+ @Shadow @Final private Map<Identifier, BakedModel> bakedModels;
+
+ @Inject(method = "<init>", at =
+ @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V"))
+ public void citresewn$addTypeItemModels(ResourceManager resourceManager, BlockColors blockColors, Profiler profiler, int i, CallbackInfo ci) {
+ profiler.swap("citresewn:type_item_models");
+ if (!CONTAINER.active())
+ return;
+
+ info("Loading item CIT models...");
+ for (CIT<TypeItem> cit : CONTAINER.loaded)
+ try {
+ cit.type.loadUnbakedAssets(resourceManager);
+
+ for (JsonUnbakedModel unbakedModel : cit.type.unbakedAssets.values()) {
+ ResewnItemModelIdentifier id = new ResewnItemModelIdentifier(unbakedModel.id);
+ this.unbakedModels.put(id, unbakedModel);
+ this.modelsToLoad.addAll(unbakedModel.getModelDependencies());
+ this.modelsToBake.put(id, unbakedModel);
+ }
+ } catch (Exception e) {
+ CITResewn.logErrorLoading("Errored loading model in " + cit.propertiesIdentifier + " from " + cit.packName);
+ e.printStackTrace();
+ }
+
+ TypeItem.GENERATED_SUB_CITS_SEEN.clear();
+ }
+
+ @Inject(method = "upload", at = @At("RETURN"))
+ public void citresewn$linkTypeItemModels(TextureManager textureManager, Profiler profiler, CallbackInfoReturnable<SpriteAtlasManager> cir) {
+ if (!CONTAINER.active())
+ return;
+
+ profiler.push("citresewn:type_item_linking");
+ info("Linking baked models to item CITs...");
+
+ for (CIT<TypeItem> cit : CONTAINER.loaded) {
+ for (Map.Entry<List<ModelOverride.Condition>, JsonUnbakedModel> citModelEntry : cit.type.unbakedAssets.entrySet()) {
+ if (citModelEntry.getKey() == null) {
+ cit.type.bakedModel = this.bakedModels.get(new ResewnItemModelIdentifier(citModelEntry.getValue().id));
+ } else {
+ BakedModel bakedModel = bakedModels.get(new ResewnItemModelIdentifier(citModelEntry.getValue().id));
+ if (bakedModel == null)
+ CITResewn.logWarnLoading("Skipping sub cit: Failed loading model for \"" + citModelEntry.getValue().id + "\" in " + cit.propertiesIdentifier + " from " + cit.packName);
+ else
+ cit.type.bakedSubModels.override(citModelEntry.getKey(), bakedModel);
+ }
+ }
+ cit.type.unbakedAssets = null;
+ }
+
+ profiler.pop();
+ }
+
+ @ModifyArg(method = "loadModelFromJson", at =
+ @At(value = "INVOKE", target = "Lnet/minecraft/resource/ResourceManager;getResource(Lnet/minecraft/util/Identifier;)Lnet/minecraft/resource/Resource;"))
+ public Identifier citresewn$fixDuplicatePrefixSuffix(Identifier original) {
+ if (CONTAINER.active() && original.getPath().startsWith("models/models/") && original.getPath().endsWith(".json.json") && original.getPath().contains("cit"))
+ return new Identifier(original.getNamespace(), original.getPath().substring(7, original.getPath().length() - 5));
+
+ return original;
+ }
+}
diff --git a/defaults/src/main/java/shcm/shsupercm/util/logic/Loops.java b/defaults/src/main/java/shcm/shsupercm/util/logic/Loops.java
new file mode 100644
index 0000000..6c18244
--- /dev/null
+++ b/defaults/src/main/java/shcm/shsupercm/util/logic/Loops.java
@@ -0,0 +1,60 @@
+package shcm.shsupercm.util.logic;
+
+import java.util.*;
+
+/**
+ * This class(or class portion) is a part of SHCM's utilities. Feel free to use without credit.
+ */
+public class Loops {
+ /**
+ * Creates a loop of T with linked intensities allowing for fading between the elements.
+ * @param items list of items and pause durations(in time units) ordered as they are in the loop
+ * @param fade time in units to fade between each item
+ * @param ticks positive raising counter
+ * @param tpu the amount of ticks per time unit
+ * @param <T> element type
+ * @return map of elements and their respective intensities(between 0.0f and 1.0f)
+ */
+ public static <T> Map<T, Float> statelessFadingLoop(List<Map.Entry<T, Float>> items, float fade, int ticks, int tpu) {
+ Map<T, Float> itemValues = new HashMap<>();
+
+ if (items == null || items.size() == 0)
+ return itemValues;
+
+ if (items.size() == 1) {
+ itemValues.put(items.get(0).getKey(), 1f);
+ return itemValues;
+ }
+
+ float totalUnitsInLoop = 0f;
+ for (Map.Entry<T, Float> item : items) {
+ itemValues.put(item.getKey(), 0f);
+ totalUnitsInLoop += item.getValue() + fade;
+ }
+
+ float unitInLoop = (ticks % (tpu * totalUnitsInLoop)) / tpu;
+
+ for (int i = 0; i < items.size(); i++) {
+ Map.Entry<T, Float> item = items.get(i);
+ if (unitInLoop < item.getValue()) {
+ itemValues.put(item.getKey(), 1f);
+ break;
+ } else
+ unitInLoop -= item.getValue();
+
+ if (unitInLoop < fade) {
+ Map.Entry<T, Float> nextItem = items.get(i + 1 >= items.size() ? 0 : i + 1);
+
+ unitInLoop /= fade;
+
+ itemValues.put(item.getKey(), 1f - unitInLoop);
+ itemValues.put(nextItem.getKey(), unitInLoop);
+
+ break;
+ } else
+ unitInLoop -= fade;
+ }
+
+ return itemValues;
+ }
+} \ No newline at end of file
diff --git a/defaults/src/main/resources/assets/citresewn-defaults/lang/en_us.json b/defaults/src/main/resources/assets/citresewn-defaults/lang/en_us.json
new file mode 100644
index 0000000..5f68e45
--- /dev/null
+++ b/defaults/src/main/resources/assets/citresewn-defaults/lang/en_us.json
@@ -0,0 +1,7 @@
+{
+ "config.citresewn-defaults.title": "CIT Resewn: Defaults",
+ "config.citresewn-defaults.tooltip": "Go to the defaults' config menu",
+
+ "config.citresewn-defaults.type_enchantment_scroll_multiplier.title": "Type Enchantment: Scroll multiplier",
+ "config.citresewn-defaults.type_enchantment_scroll_multiplier.tooltip": "A general multiplier for how fast cit enchantment glints scroll"
+} \ No newline at end of file
diff --git a/defaults/src/main/resources/assets/citresewn-defaults/logo.png b/defaults/src/main/resources/assets/citresewn-defaults/logo.png
new file mode 100644
index 0000000..35859ac
--- /dev/null
+++ b/defaults/src/main/resources/assets/citresewn-defaults/logo.png
Binary files differ
diff --git a/defaults/src/main/resources/citresewn-defaults.accesswidener b/defaults/src/main/resources/citresewn-defaults.accesswidener
new file mode 100644
index 0000000..739fc5e
--- /dev/null
+++ b/defaults/src/main/resources/citresewn-defaults.accesswidener
@@ -0,0 +1,30 @@
+accessWidener v1 named
+
+# ConditionNBT
+accessible field net/minecraft/nbt/NbtCompound entries Ljava/util/Map;
+
+# TypeItem
+accessible class net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride
+accessible class net/minecraft/client/render/model/json/ModelOverrideList$InlinedCondition
+accessible method net/minecraft/client/render/model/json/ModelOverrideList <init> ()V
+accessible method net/minecraft/client/render/model/json/ModelOverrideList$BakedOverride <init> ([Lnet/minecraft/client/render/model/json/ModelOverrideList$InlinedCondition;Lnet/minecraft/client/render/model/BakedModel;)V
+accessible method net/minecraft/client/render/model/json/ModelOverrideList$InlinedCondition <init> (IF)V
+accessible field net/minecraft/client/render/model/json/ModelOverrideList overrides [Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;
+mutable field net/minecraft/client/render/model/json/ModelOverrideList overrides [Lnet/minecraft/client/render/model/json/ModelOverrideList$BakedOverride;
+accessible field net/minecraft/client/render/model/json/ModelOverrideList conditionTypes [Lnet/minecraft/util/Identifier;
+mutable field net/minecraft/client/render/model/json/ModelOverrideList conditionTypes [Lnet/minecraft/util/Identifier;
+
+# TypeEnchantment
+accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
+accessible method net/minecraft/client/render/RenderLayer of (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;ILnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase;
+accessible class net/minecraft/client/render/RenderPhase$Shader
+accessible class net/minecraft/client/render/RenderPhase$Texturing
+accessible class net/minecraft/client/render/RenderPhase$Transparency
+accessible class net/minecraft/client/render/RenderPhase$Texture
+accessible class net/minecraft/client/render/RenderPhase$Lightmap
+accessible class net/minecraft/client/render/RenderPhase$Overlay
+accessible class net/minecraft/client/render/RenderPhase$Cull
+accessible class net/minecraft/client/render/RenderPhase$DepthTest
+accessible class net/minecraft/client/render/RenderPhase$WriteMaskState
+accessible class net/minecraft/client/render/RenderPhase$Layering
+accessible class net/minecraft/client/render/RenderPhase$Target \ No newline at end of file
diff --git a/defaults/src/main/resources/citresewn-defaults.mixins.json b/defaults/src/main/resources/citresewn-defaults.mixins.json
new file mode 100644
index 0000000..536380b
--- /dev/null
+++ b/defaults/src/main/resources/citresewn-defaults.mixins.json
@@ -0,0 +1,9 @@
+{
+ "required": true,
+ "minVersion": "0.8",
+ "package": "shcm.shsupercm.fabric.citresewn.defaults.mixin",
+ "compatibilityLevel": "JAVA_17",
+ "injectors": {
+ "defaultRequire": 1
+ }
+}
diff --git a/defaults/src/main/resources/fabric.mod.json b/defaults/src/main/resources/fabric.mod.json
new file mode 100644
index 0000000..f35e7bb
--- /dev/null
+++ b/defaults/src/main/resources/fabric.mod.json
@@ -0,0 +1,36 @@
+{
+ "schemaVersion": 1,
+ "id": "citresewn-defaults",
+ "version": "${version}",
+ "name": "CIT Resewn: Defaults",
+ "description": "Default types and conditions for CIT Resewn",
+ "authors": [
+ "SHsuperCM"
+ ],
+ "license": "MIT",
+ "icon": "assets/citresewn-defaults/logo.png",
+ "contact": {
+ "homepage": "https://citresewn.shcm.io/",
+ "sources": "https://github.com/SHsuperCM/CITResewn",
+ "issues": "https://github.com/SHsuperCM/CITResewn/issues"
+ },
+
+ "environment": "client",
+ "accessWidener" : "citresewn-defaults.accesswidener",
+ "mixins": [
+ "citresewn-defaults.mixins.json"
+ ],
+ "custom": {
+ "modmenu": {
+ "parent": {
+ "id": "citresewn"
+ }
+ }
+ },
+ "depends": {
+ "citresewn": "${version}"
+ },
+ "conflicts": {
+ "eatinganimationid": "*"
+ }
+}