From 81c6e9405d5ba4ec65be7c9eb677331d974c6d5d Mon Sep 17 00:00:00 2001 From: flmeyer Date: Thu, 30 Jul 2026 09:45:20 +0200 Subject: [PATCH 01/19] feat: POC mixin of ItemStackComponentizationFix --- .../MixinItemStackComponentizationFix.java | 21 +++++++++++++++++++ .../src/main/resources/hexplat.accesswidener | 1 + Common/src/main/resources/hexplat.mixins.json | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java new file mode 100644 index 0000000000..eed6f9760c --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -0,0 +1,21 @@ +package at.petrak.hexcasting.mixin.datafixer; + +import com.mojang.serialization.Dynamic; +import java.util.Map; +import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemStackComponentizationFix.class) +public class MixinItemStackComponentizationFix { + @Inject(method = "fixItemStack", at = @At("TAIL")) + private static void fixHexItemStack(ItemStackComponentizationFix.ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { + if (itemStackData.is("hexcasting:focus")) { + Map> data = itemStackData.removeTag("data").asMap((dynamicx) -> dynamicx.asString(""), (dynamicx) -> dynamicx); + Dynamic component = dynamic.createMap(Map.of(dynamic.createString("type"), data.get("hexcasting:type"), dynamic.createString("value"), data.get("hexcasting:data"))); + itemStackData.setComponent("hexcasting:iota", component); + } + } +} diff --git a/Common/src/main/resources/hexplat.accesswidener b/Common/src/main/resources/hexplat.accesswidener index 181ba7db3a..24e391e488 100644 --- a/Common/src/main/resources/hexplat.accesswidener +++ b/Common/src/main/resources/hexplat.accesswidener @@ -8,3 +8,4 @@ accessible method net/minecraft/world/item/crafting/Ingredient (Ljava/uti accessible method net/minecraft/world/item/context/UseOnContext (Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/phys/BlockHitResult;)V accessible method net/minecraft/world/damagesource/DamageSources source (Lnet/minecraft/resources/ResourceKey;)Lnet/minecraft/world/damagesource/DamageSource; accessible method net/minecraft/world/damagesource/DamageSources source (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/world/damagesource/DamageSource; +accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData \ No newline at end of file diff --git a/Common/src/main/resources/hexplat.mixins.json b/Common/src/main/resources/hexplat.mixins.json index 9c6121aa10..8b5e787695 100644 --- a/Common/src/main/resources/hexplat.mixins.json +++ b/Common/src/main/resources/hexplat.mixins.json @@ -16,7 +16,8 @@ "accessor.AccessorLivingEntity", "accessor.AccessorLootTable", "accessor.AccessorUseOnContext", - "accessor.AccessorVillager" + "accessor.AccessorVillager", + "datafixer.MixinItemStackComponentizationFix" ], "client": [ "accessor.client.AccessorBlockEntityRenderDispatcher", From 2d7a98799e87e7f9ab5ce1cb862d4e62bc07e76c Mon Sep 17 00:00:00 2001 From: flmeyer Date: Thu, 30 Jul 2026 14:17:08 +0200 Subject: [PATCH 02/19] feat: add datafixing for thought knot --- .../MixinItemStackComponentizationFix.java | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index eed6f9760c..d41d53bf51 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -1,21 +1,49 @@ package at.petrak.hexcasting.mixin.datafixer; import com.mojang.serialization.Dynamic; +import java.util.HashMap; import java.util.Map; +import java.util.Set; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; +import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ItemStackComponentizationFix.class) public class MixinItemStackComponentizationFix { + private static final String HEX_IOTA_COMPONENT = "hexcasting:iota"; + private static final String HEX_IOTA_TYPE = "hexcasting:type"; + private static final String HEX_STORAGE_SEALED = "hexcasting:sealed"; + private static final String HEX_DATA = "hexcasting:data"; + @Inject(method = "fixItemStack", at = @At("TAIL")) - private static void fixHexItemStack(ItemStackComponentizationFix.ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { - if (itemStackData.is("hexcasting:focus")) { - Map> data = itemStackData.removeTag("data").asMap((dynamicx) -> dynamicx.asString(""), (dynamicx) -> dynamicx); - Dynamic component = dynamic.createMap(Map.of(dynamic.createString("type"), data.get("hexcasting:type"), dynamic.createString("value"), data.get("hexcasting:data"))); - itemStackData.setComponent("hexcasting:iota", component); + private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { + if (itemStackData.is(Set.of("hexcasting:focus", "hexcasting:thought_knot"))) { + Map> data = + itemStackData + .removeTag("data") + .asMap((dynamicx) -> dynamicx.asString(""), (dynamicx) -> dynamicx); + if (data.containsKey(HEX_DATA) && data.containsKey(HEX_IOTA_TYPE)) { + hexCasting$fixIotaHolder( + itemStackData, + dynamic, + data.remove(HEX_IOTA_TYPE).asString(""), + data.remove(HEX_DATA), + data.remove(HEX_STORAGE_SEALED).asBoolean(false)); + } } } + + + @Unique + private static void hexCasting$fixIotaHolder(ItemStackData itemStackData, Dynamic dynamic, String iotaType, Dynamic hexData, boolean sealed) { + Map, Dynamic> component = new HashMap<>(); + component.put(dynamic.createString("type"), dynamic.createString(iotaType)); + component.put(dynamic.createString("value"), hexData); + if (sealed) component.put(dynamic.createString("sealed"), dynamic.createBoolean(true)); + itemStackData.setComponent(HEX_IOTA_COMPONENT, dynamic.createMap(component)); + } } From 0076d04c071bb27489debcb10573ee824c8e5dc0 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Thu, 30 Jul 2026 14:28:51 +0200 Subject: [PATCH 03/19] fix: properly create sealed component --- .../mixin/datafixer/MixinItemStackComponentizationFix.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index d41d53bf51..8c506bb548 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -15,6 +15,7 @@ @Mixin(ItemStackComponentizationFix.class) public class MixinItemStackComponentizationFix { private static final String HEX_IOTA_COMPONENT = "hexcasting:iota"; + private static final String HEX_SEALED_COMPONENT = "hexcasting:sealed"; private static final String HEX_IOTA_TYPE = "hexcasting:type"; private static final String HEX_STORAGE_SEALED = "hexcasting:sealed"; private static final String HEX_DATA = "hexcasting:data"; @@ -43,7 +44,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna Map, Dynamic> component = new HashMap<>(); component.put(dynamic.createString("type"), dynamic.createString(iotaType)); component.put(dynamic.createString("value"), hexData); - if (sealed) component.put(dynamic.createString("sealed"), dynamic.createBoolean(true)); itemStackData.setComponent(HEX_IOTA_COMPONENT, dynamic.createMap(component)); + if (sealed) itemStackData.setComponent(HEX_SEALED_COMPONENT, dynamic.createMap(Map.of())); } } From d0e4e1d0a02a9d781363150c143cab720813f23b Mon Sep 17 00:00:00 2001 From: flmeyer Date: Thu, 30 Jul 2026 15:46:50 +0200 Subject: [PATCH 04/19] feat: Scroll DataFix --- .../MixinItemStackComponentizationFix.java | 75 +++++++++++++++---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 8c506bb548..d1391224cf 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -1,9 +1,13 @@ package at.petrak.hexcasting.mixin.datafixer; +import at.petrak.hexcasting.api.casting.math.HexPattern; import com.mojang.serialization.Dynamic; + import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; + import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; import org.spongepowered.asm.mixin.Mixin; @@ -14,37 +18,80 @@ @Mixin(ItemStackComponentizationFix.class) public class MixinItemStackComponentizationFix { - private static final String HEX_IOTA_COMPONENT = "hexcasting:iota"; - private static final String HEX_SEALED_COMPONENT = "hexcasting:sealed"; + @Unique private static final String HEX_IOTA_TYPE = "hexcasting:type"; + @Unique private static final String HEX_STORAGE_SEALED = "hexcasting:sealed"; + @Unique private static final String HEX_DATA = "hexcasting:data"; @Inject(method = "fixItemStack", at = @At("TAIL")) private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { if (itemStackData.is(Set.of("hexcasting:focus", "hexcasting:thought_knot"))) { Map> data = - itemStackData - .removeTag("data") - .asMap((dynamicx) -> dynamicx.asString(""), (dynamicx) -> dynamicx); + itemStackData + .removeTag("data") + .asMap((dynamicx) -> dynamicx.asString(""), (dynamicx) -> dynamicx); if (data.containsKey(HEX_DATA) && data.containsKey(HEX_IOTA_TYPE)) { - hexCasting$fixIotaHolder( - itemStackData, - dynamic, - data.remove(HEX_IOTA_TYPE).asString(""), - data.remove(HEX_DATA), - data.remove(HEX_STORAGE_SEALED).asBoolean(false)); + hexCasting$fixIotaHolder( + itemStackData, + dynamic, + data.get(HEX_IOTA_TYPE).asString(""), + data.get(HEX_DATA), + data.containsKey(HEX_STORAGE_SEALED) && data.get(HEX_STORAGE_SEALED).asBoolean(false)); } } - } + if (itemStackData.is(Set.of("hexcasting:scroll_small", "hexcasting:scroll_medium", "hexcasting:scroll"))) { + hexCasting$fixScroll(itemStackData, dynamic); + } + if (itemStackData.is("hexcasting:ancient_cypher")) { + // TODO: hex name component + } + if (itemStackData.is("hexcasting:abacus")) { + // TODO: abacus value component + } + if (itemStackData.is("hexcasting:spellbook")) { + hexCasting$fixSpellbook(itemStackData, dynamic); + } + // TODO: visual override component + // TODO: item variant component + // TODO: wait for #1220, then hex holder component + // TODO: media component + // TODO: media_max component + } @Unique private static void hexCasting$fixIotaHolder(ItemStackData itemStackData, Dynamic dynamic, String iotaType, Dynamic hexData, boolean sealed) { Map, Dynamic> component = new HashMap<>(); component.put(dynamic.createString("type"), dynamic.createString(iotaType)); component.put(dynamic.createString("value"), hexData); - itemStackData.setComponent(HEX_IOTA_COMPONENT, dynamic.createMap(component)); - if (sealed) itemStackData.setComponent(HEX_SEALED_COMPONENT, dynamic.createMap(Map.of())); + itemStackData.setComponent("hexcasting:iota", dynamic.createMap(component)); + if (sealed) itemStackData.setComponent("hexcasting:sealed", dynamic.createMap(Map.of())); + } + + @Unique + private static final String[] hexCasting$hexDir = {"NORTH_EAST", "EAST", "SOUTH_EAST", "SOUTH_WEST", "WEST", "NORTH_WEST"}; + @Unique + private static final String[] hexCasting$hexAngle = {"w", "e", "d", "s", "a", "q"}; + + @Unique + private static void hexCasting$fixScroll(ItemStackData itemStackData, Dynamic dynamic) { + Dynamic pattern = itemStackData.removeTag("pattern").orElseEmptyMap(); + byte startDir = pattern.get("start_dir").asByte((byte) 0); + List angles = pattern.get("angles").asList(dynamic0 -> dynamic0.asByte((byte) 0)); + Map, Dynamic> patternComponent = new HashMap<>(); + patternComponent.put(dynamic.createString(HexPattern.TAG_START_DIR), dynamic.createString(hexCasting$hexDir[startDir])); + patternComponent.put(dynamic.createString(HexPattern.TAG_ANGLES), dynamic.createString(String.join("", angles.stream().map(a -> hexCasting$hexAngle[a]).toList()))); + itemStackData.setComponent("hexcasting:pattern", dynamic.createMap(patternComponent)); + + itemStackData.moveTagToComponent("op_id", "hexcasting:op_id"); + itemStackData.moveTagToComponent("recalc_warning", "hexcasting:recalc_warning"); + itemStackData.moveTagToComponent("needs_purchase", "hexcasting:needs_purchase"); + } + + @Unique + private static void hexCasting$fixSpellbook(ItemStackData itemStackData, Dynamic dynamic) { + // TODO: all spellbook components } } From 6b575329f125045158d5c4216e750acddbc083bc Mon Sep 17 00:00:00 2001 From: Florian Meyer Date: Thu, 30 Jul 2026 19:26:29 +0200 Subject: [PATCH 05/19] feat: fix ancient cypher name --- .../mixin/datafixer/MixinItemStackComponentizationFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index d1391224cf..fcb42b98dd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -45,7 +45,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna hexCasting$fixScroll(itemStackData, dynamic); } if (itemStackData.is("hexcasting:ancient_cypher")) { - // TODO: hex name component + itemStackData.moveTagToComponent("hex_name", "hexcasting:hex_name"); } if (itemStackData.is("hexcasting:abacus")) { // TODO: abacus value component From cf5e7f5d8904bb26b7ce660cca9f5ed972cdf150 Mon Sep 17 00:00:00 2001 From: Florian Meyer Date: Thu, 30 Jul 2026 19:28:38 +0200 Subject: [PATCH 06/19] fix: corrected handling of iota holders --- .../datafixer/MixinItemStackComponentizationFix.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index fcb42b98dd..1f666efa0c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -3,11 +3,9 @@ import at.petrak.hexcasting.api.casting.math.HexPattern; import com.mojang.serialization.Dynamic; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import com.mojang.serialization.OptionalDynamic; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; import org.spongepowered.asm.mixin.Mixin; @@ -65,6 +63,12 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna private static void hexCasting$fixIotaHolder(ItemStackData itemStackData, Dynamic dynamic, String iotaType, Dynamic hexData, boolean sealed) { Map, Dynamic> component = new HashMap<>(); component.put(dynamic.createString("type"), dynamic.createString(iotaType)); + switch (iotaType) { + case "hexcasting:double": + component.put(dynamic.createString("value"), hexData); + break; + // TODO: correctly fix each iota type. Can we somehow even do this for non-basemod iotas? + } component.put(dynamic.createString("value"), hexData); itemStackData.setComponent("hexcasting:iota", dynamic.createMap(component)); if (sealed) itemStackData.setComponent("hexcasting:sealed", dynamic.createMap(Map.of())); From c5eb6e7543dcf13e338cdf9ccdfb64002fde49ce Mon Sep 17 00:00:00 2001 From: Florian Meyer Date: Thu, 30 Jul 2026 20:24:45 +0200 Subject: [PATCH 07/19] feat: entity iota fixing --- .../at/petrak/hexcasting/api/casting/iota/EntityIota.java | 4 +++- .../datafixer/MixinItemStackComponentizationFix.java | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java index a116d42ac6..faf6eba96f 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/EntityIota.java @@ -28,7 +28,7 @@ public class EntityIota extends Iota { private final UUID entityId; @Nullable - private final Component entityName; + private Component entityName; private boolean isPlayer; public EntityIota(@NotNull Entity e) { @@ -115,6 +115,8 @@ public boolean validate(EntityIota iota, ServerLevel level) { var entity = iota.getEntity(level); // update isPlayer so older non-player entity iotas are not protected iota.isPlayer = (entity instanceof Player); + if (iota.entityName == null) + iota.entityName = getEntityNameWithInline(entity); return entity != null; } diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 1f666efa0c..894fd1849a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -4,8 +4,8 @@ import com.mojang.serialization.Dynamic; import java.util.*; +import java.util.stream.IntStream; -import com.mojang.serialization.OptionalDynamic; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; import org.spongepowered.asm.mixin.Mixin; @@ -67,6 +67,12 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna case "hexcasting:double": component.put(dynamic.createString("value"), hexData); break; + case "hexcasting:entity": + IntStream uuid = hexData.get("uuid").asIntStream(); + // Unfortunately, it seems like we cannot easily fix InlineAPI components, so we will have to live with "an unknown entity" + component.put(dynamic.createString("entityId"), dynamic.createIntList(uuid)); + component.put(dynamic.createString("isPlayer"), dynamic.createBoolean(true)); + break; // TODO: correctly fix each iota type. Can we somehow even do this for non-basemod iotas? } component.put(dynamic.createString("value"), hexData); From 50169e055bb9e3d32554eb42025ed646f189d2e2 Mon Sep 17 00:00:00 2001 From: Florian Meyer Date: Thu, 30 Jul 2026 21:37:15 +0200 Subject: [PATCH 08/19] feat: datafix all iota types except for continuation --- .../MixinItemStackComponentizationFix.java | 100 ++++++++++++------ 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 894fd1849a..7f412b13b8 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -4,10 +4,13 @@ import com.mojang.serialization.Dynamic; import java.util.*; +import java.util.function.Function; import java.util.stream.IntStream; +import java.util.stream.Stream; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; +import org.apache.commons.lang3.NotImplementedException; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -26,21 +29,10 @@ public class MixinItemStackComponentizationFix { @Inject(method = "fixItemStack", at = @At("TAIL")) private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { if (itemStackData.is(Set.of("hexcasting:focus", "hexcasting:thought_knot"))) { - Map> data = - itemStackData - .removeTag("data") - .asMap((dynamicx) -> dynamicx.asString(""), (dynamicx) -> dynamicx); - if (data.containsKey(HEX_DATA) && data.containsKey(HEX_IOTA_TYPE)) { - hexCasting$fixIotaHolder( - itemStackData, - dynamic, - data.get(HEX_IOTA_TYPE).asString(""), - data.get(HEX_DATA), - data.containsKey(HEX_STORAGE_SEALED) && data.get(HEX_STORAGE_SEALED).asBoolean(false)); - } + hexCasting$fixIotaHolder(itemStackData, dynamic); } if (itemStackData.is(Set.of("hexcasting:scroll_small", "hexcasting:scroll_medium", "hexcasting:scroll"))) { - hexCasting$fixScroll(itemStackData, dynamic); + hexCasting$fixScroll(itemStackData); } if (itemStackData.is("hexcasting:ancient_cypher")) { itemStackData.moveTagToComponent("hex_name", "hexcasting:hex_name"); @@ -60,41 +52,85 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna } @Unique - private static void hexCasting$fixIotaHolder(ItemStackData itemStackData, Dynamic dynamic, String iotaType, Dynamic hexData, boolean sealed) { + private static void hexCasting$fixIotaHolder(ItemStackData itemStackData, Dynamic dynamic) { + itemStackData.fixSubTag("data", true, MixinItemStackComponentizationFix::hexCasting$mapIotaData); + itemStackData.moveTagToComponent("data", "hexcasting:iota"); + + if (itemStackData.removeTag(HEX_STORAGE_SEALED).asBoolean(false)) + itemStackData.setComponent("hexcasting:sealed", dynamic.createMap(Map.of())); + } + + @Unique + private static Dynamic hexCasting$mapIotaData(Dynamic iota) { + String iotaType = iota.get(HEX_IOTA_TYPE).asString(""); + Dynamic iotaData = iota.get(HEX_DATA).orElseEmptyMap(); Map, Dynamic> component = new HashMap<>(); - component.put(dynamic.createString("type"), dynamic.createString(iotaType)); + component.put(iota.createString("type"), iota.createString(iotaType)); switch (iotaType) { - case "hexcasting:double": - component.put(dynamic.createString("value"), hexData); - break; case "hexcasting:entity": - IntStream uuid = hexData.get("uuid").asIntStream(); + IntStream uuid = iotaData.get("uuid").asIntStream(); // Unfortunately, it seems like we cannot easily fix InlineAPI components, so we will have to live with "an unknown entity" - component.put(dynamic.createString("entityId"), dynamic.createIntList(uuid)); - component.put(dynamic.createString("isPlayer"), dynamic.createBoolean(true)); + component.put(iota.createString("entityId"), iota.createIntList(uuid)); + component.put(iota.createString("isPlayer"), iota.createBoolean(true)); + break; + case "hexcasting:boolean": + case "hexcasting:double": + component.put(iota.createString("value"), iotaData); + break; + case "hexcasting:list": + List> listData = iotaData.asList(MixinItemStackComponentizationFix::hexCasting$mapIotaData); + component.put(iota.createString("list"), iota.createList(listData.stream())); + break; + case "hexcasting:pattern": + component.put(iota.createString("value"), hexCasting$mapPattern(iotaData)); + break; + case "hexcasting:vec3": + component.put(iota.createString("value"), hexCasting$mapVec3(iotaData)); + break; + case "hexcasting:continuation": + List> frames = iotaData.asList(MixinItemStackComponentizationFix::hexCasting$mapContinuationFrame); + component.put(iota.createString("value"), iota.createList(frames.stream())); + break; + case "hexcasting:null": + case "hexcasting:garbage": + default: break; - // TODO: correctly fix each iota type. Can we somehow even do this for non-basemod iotas? } - component.put(dynamic.createString("value"), hexData); - itemStackData.setComponent("hexcasting:iota", dynamic.createMap(component)); - if (sealed) itemStackData.setComponent("hexcasting:sealed", dynamic.createMap(Map.of())); + return iota.createMap(component); } @Unique private static final String[] hexCasting$hexDir = {"NORTH_EAST", "EAST", "SOUTH_EAST", "SOUTH_WEST", "WEST", "NORTH_WEST"}; @Unique private static final String[] hexCasting$hexAngle = {"w", "e", "d", "s", "a", "q"}; - @Unique - private static void hexCasting$fixScroll(ItemStackData itemStackData, Dynamic dynamic) { - Dynamic pattern = itemStackData.removeTag("pattern").orElseEmptyMap(); + private static Dynamic hexCasting$mapPattern(Dynamic pattern) { + Map, Dynamic> patternComponent = new HashMap<>(); byte startDir = pattern.get("start_dir").asByte((byte) 0); List angles = pattern.get("angles").asList(dynamic0 -> dynamic0.asByte((byte) 0)); - Map, Dynamic> patternComponent = new HashMap<>(); - patternComponent.put(dynamic.createString(HexPattern.TAG_START_DIR), dynamic.createString(hexCasting$hexDir[startDir])); - patternComponent.put(dynamic.createString(HexPattern.TAG_ANGLES), dynamic.createString(String.join("", angles.stream().map(a -> hexCasting$hexAngle[a]).toList()))); - itemStackData.setComponent("hexcasting:pattern", dynamic.createMap(patternComponent)); + patternComponent.put(pattern.createString(HexPattern.TAG_START_DIR), pattern.createString(hexCasting$hexDir[startDir])); + patternComponent.put(pattern.createString(HexPattern.TAG_ANGLES), pattern.createString(String.join("", angles.stream().map(a -> hexCasting$hexAngle[a]).toList()))); + return pattern.createMap(patternComponent); + } + + @Unique + private static Dynamic hexCasting$mapVec3(Dynamic iotaData) { + double x = iotaData.get("x").asDouble(0); + double y = iotaData.get("y").asDouble(0); + double z = iotaData.get("z").asDouble(0); + return iotaData.createList(Stream.of(iotaData.createDouble(x), iotaData.createDouble(y), iotaData.createDouble(z))); + } + + @Unique + private static Dynamic hexCasting$mapContinuationFrame(Dynamic dynamic) { + throw new NotImplementedException(); + } + + @Unique + private static void hexCasting$fixScroll(ItemStackData itemStackData) { + itemStackData.fixSubTag("pattern", true, MixinItemStackComponentizationFix::hexCasting$mapPattern); + itemStackData.moveTagToComponent("pattern", "hexcasting:pattern"); itemStackData.moveTagToComponent("op_id", "hexcasting:op_id"); itemStackData.moveTagToComponent("recalc_warning", "hexcasting:recalc_warning"); itemStackData.moveTagToComponent("needs_purchase", "hexcasting:needs_purchase"); From 3e7bbbf777673e86679d23a9902031691504994e Mon Sep 17 00:00:00 2001 From: Florian Meyer Date: Thu, 30 Jul 2026 22:36:42 +0200 Subject: [PATCH 09/19] feat: datafix continuation iota type --- .../MixinItemStackComponentizationFix.java | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 7f412b13b8..8f65f90e81 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -4,7 +4,6 @@ import com.mojang.serialization.Dynamic; import java.util.*; -import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -20,7 +19,7 @@ @Mixin(ItemStackComponentizationFix.class) public class MixinItemStackComponentizationFix { @Unique - private static final String HEX_IOTA_TYPE = "hexcasting:type"; + private static final String HEX_TYPE = "hexcasting:type"; @Unique private static final String HEX_STORAGE_SEALED = "hexcasting:sealed"; @Unique @@ -62,7 +61,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna @Unique private static Dynamic hexCasting$mapIotaData(Dynamic iota) { - String iotaType = iota.get(HEX_IOTA_TYPE).asString(""); + String iotaType = iota.get(HEX_TYPE).asString(""); Dynamic iotaData = iota.get(HEX_DATA).orElseEmptyMap(); Map, Dynamic> component = new HashMap<>(); component.put(iota.createString("type"), iota.createString(iotaType)); @@ -78,8 +77,8 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna component.put(iota.createString("value"), iotaData); break; case "hexcasting:list": - List> listData = iotaData.asList(MixinItemStackComponentizationFix::hexCasting$mapIotaData); - component.put(iota.createString("list"), iota.createList(listData.stream())); + component.put(iota.createString("list"), + iota.createList(iotaData.asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); break; case "hexcasting:pattern": component.put(iota.createString("value"), hexCasting$mapPattern(iotaData)); @@ -88,8 +87,8 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna component.put(iota.createString("value"), hexCasting$mapVec3(iotaData)); break; case "hexcasting:continuation": - List> frames = iotaData.asList(MixinItemStackComponentizationFix::hexCasting$mapContinuationFrame); - component.put(iota.createString("value"), iota.createList(frames.stream())); + component.put(iota.createString("value"), + iota.createList(iotaData.asStream().map(MixinItemStackComponentizationFix::hexCasting$mapContinuationFrame))); break; case "hexcasting:null": case "hexcasting:garbage": @@ -107,9 +106,11 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna private static Dynamic hexCasting$mapPattern(Dynamic pattern) { Map, Dynamic> patternComponent = new HashMap<>(); byte startDir = pattern.get("start_dir").asByte((byte) 0); - List angles = pattern.get("angles").asList(dynamic0 -> dynamic0.asByte((byte) 0)); + List angles = pattern.get("angles").asStream() + .map(a -> hexCasting$hexAngle[a.asByte((byte) 0)]) + .toList(); patternComponent.put(pattern.createString(HexPattern.TAG_START_DIR), pattern.createString(hexCasting$hexDir[startDir])); - patternComponent.put(pattern.createString(HexPattern.TAG_ANGLES), pattern.createString(String.join("", angles.stream().map(a -> hexCasting$hexAngle[a]).toList()))); + patternComponent.put(pattern.createString(HexPattern.TAG_ANGLES), pattern.createString(String.join("", angles))); return pattern.createMap(patternComponent); } @@ -122,8 +123,36 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna } @Unique - private static Dynamic hexCasting$mapContinuationFrame(Dynamic dynamic) { - throw new NotImplementedException(); + private static Dynamic hexCasting$mapContinuationFrame(Dynamic frame) { + String type = frame.get(HEX_TYPE).asString(""); + Dynamic frameData = frame.get(HEX_DATA).orElseEmptyMap(); + Map, Dynamic> component = new HashMap<>(); + component.put(frame.createString("type"), frame.createString(type)); + switch (type) { + case "hexcasting:evaluate": + component.put(frame.createString("patterns"), + frame.createList(frameData.get("patterns").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + component.put(frame.createString("isMetacasting"), + frame.createBoolean(frameData.get("isMetacasting").asBoolean(false))); + break; + case "hexcasting:foreach": + component.put(frame.createString("data"), + frame.createList(frameData.get("data").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + component.put(frame.createString("code"), + frame.createList(frameData.get("code").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + component.put(frame.createString("context"), + frame.createList(frameData.get("base").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + // TODO: figure out whether stashed should be base (replicating otherwise unavailable 1.20 thoth behavior) or an empty list (equivalent to 1.21 thoth with whatever size the stack had before casting) + component.put(frame.createString("stashed"), + frame.createList(frameData.get("base").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + component.put(frame.createString("accumulator"), + frame.createList(frameData.get("accumulator").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + break; + case "hexcasting:end": + default: + break; + } + return frame.createMap(component); } @Unique From d025bd2e85481710dd868b685dd044fb22596e16 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 07:23:37 +0200 Subject: [PATCH 10/19] fix: sealed foci --- .../datafixer/MixinItemStackComponentizationFix.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 8f65f90e81..6c4b490bf0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -21,8 +21,6 @@ public class MixinItemStackComponentizationFix { @Unique private static final String HEX_TYPE = "hexcasting:type"; @Unique - private static final String HEX_STORAGE_SEALED = "hexcasting:sealed"; - @Unique private static final String HEX_DATA = "hexcasting:data"; @Inject(method = "fixItemStack", at = @At("TAIL")) @@ -55,7 +53,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna itemStackData.fixSubTag("data", true, MixinItemStackComponentizationFix::hexCasting$mapIotaData); itemStackData.moveTagToComponent("data", "hexcasting:iota"); - if (itemStackData.removeTag(HEX_STORAGE_SEALED).asBoolean(false)) + if (itemStackData.removeTag("sealed").asBoolean(false)) itemStackData.setComponent("hexcasting:sealed", dynamic.createMap(Map.of())); } @@ -72,8 +70,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna component.put(iota.createString("entityId"), iota.createIntList(uuid)); component.put(iota.createString("isPlayer"), iota.createBoolean(true)); break; - case "hexcasting:boolean": - case "hexcasting:double": + case "hexcasting:boolean", "hexcasting:double": component.put(iota.createString("value"), iotaData); break; case "hexcasting:list": @@ -90,8 +87,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna component.put(iota.createString("value"), iota.createList(iotaData.asStream().map(MixinItemStackComponentizationFix::hexCasting$mapContinuationFrame))); break; - case "hexcasting:null": - case "hexcasting:garbage": + case "hexcasting:null", "hexcasting:garbage": default: break; } From 46ecc9ec2884cc57aac8bfb4375b01f45166f7d4 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 07:28:34 +0200 Subject: [PATCH 11/19] feat: datafix abacus value --- .../mixin/datafixer/MixinItemStackComponentizationFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 6c4b490bf0..f6ed3c2c2c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -35,7 +35,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna itemStackData.moveTagToComponent("hex_name", "hexcasting:hex_name"); } if (itemStackData.is("hexcasting:abacus")) { - // TODO: abacus value component + itemStackData.moveTagToComponent("value", "hexcasting:abacus_value"); } if (itemStackData.is("hexcasting:spellbook")) { hexCasting$fixSpellbook(itemStackData, dynamic); From 37399b9e1b80f2e4c7088ca23981a9b359f91170 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 07:44:40 +0200 Subject: [PATCH 12/19] feat: datafix slate item --- .../datafixer/MixinItemStackComponentizationFix.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index f6ed3c2c2c..b6829de32a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -9,7 +9,6 @@ import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; -import org.apache.commons.lang3.NotImplementedException; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -23,6 +22,15 @@ public class MixinItemStackComponentizationFix { @Unique private static final String HEX_DATA = "hexcasting:data"; + @Inject(method = "fixItemStack", at = @At("HEAD")) + private static void preFixHexItemStack(ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { + if (itemStackData.is("hexcasting:slate")) { + itemStackData.fixSubTag("BlockEntityTag", false, dynamic0 -> + hexCasting$mapPattern(dynamic0.get("pattern").orElseEmptyMap())); + itemStackData.moveTagToComponent("BlockEntityTag", "pattern"); + } + } + @Inject(method = "fixItemStack", at = @At("TAIL")) private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { if (itemStackData.is(Set.of("hexcasting:focus", "hexcasting:thought_knot"))) { From 246c7612f3b2a22b756663acce9c50c77ea42e6d Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 09:01:41 +0200 Subject: [PATCH 13/19] feat: datafix spellbook item --- .../MixinItemStackComponentizationFix.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index b6829de32a..0b91a18616 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -4,6 +4,7 @@ import com.mojang.serialization.Dynamic; import java.util.*; +import java.util.function.Function; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -159,6 +160,11 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna return frame.createMap(component); } + @Unique + private static Dynamic hexCasting$stringToPlainComponent(Dynamic string) { + return string.createMap(Map.of(string.createString("text"), string)); + } + @Unique private static void hexCasting$fixScroll(ItemStackData itemStackData) { itemStackData.fixSubTag("pattern", true, MixinItemStackComponentizationFix::hexCasting$mapPattern); @@ -171,6 +177,16 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna @Unique private static void hexCasting$fixSpellbook(ItemStackData itemStackData, Dynamic dynamic) { - // TODO: all spellbook components + itemStackData.moveTagToComponent("page_idx", "hexcasting:page_idx"); + + itemStackData.fixSubTag("page_names", true, d0 -> + d0.createMap(d0.asMap(Function.identity(), MixinItemStackComponentizationFix::hexCasting$stringToPlainComponent))); + itemStackData.moveTagToComponent("page_names", "hexcasting:page_names"); + + itemStackData.fixSubTag("pages", true, d0 -> + d0.createMap(d0.asMap(Function.identity(), MixinItemStackComponentizationFix::hexCasting$mapPattern))); + itemStackData.moveTagToComponent("pages", "hexcasting:pages"); + + itemStackData.moveTagToComponent("sealed_pages", "hexcasting:sealed_pages"); } } From 46fd3191038d5dcf949a536b3f0c8857ada2ce1a Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 09:43:33 +0200 Subject: [PATCH 14/19] feat: datafix visual override --- .../datafixer/MixinItemStackComponentizationFix.java | 11 +++++++++-- Common/src/main/resources/hexplat.accesswidener | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 0b91a18616..90c375432e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.mixin.datafixer; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.api.item.IotaHolderItem; import com.mojang.serialization.Dynamic; import java.util.*; @@ -8,8 +9,11 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix; import net.minecraft.util.datafix.fixes.ItemStackComponentizationFix.ItemStackData; +import net.minecraft.world.item.Item; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -34,6 +38,8 @@ private static void preFixHexItemStack(ItemStackData itemStackData, Dynamic d @Inject(method = "fixItemStack", at = @At("TAIL")) private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dynamic, CallbackInfo ci) { + Item item = BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemStackData.item)); + if (itemStackData.is(Set.of("hexcasting:focus", "hexcasting:thought_knot"))) { hexCasting$fixIotaHolder(itemStackData, dynamic); } @@ -49,8 +55,9 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna if (itemStackData.is("hexcasting:spellbook")) { hexCasting$fixSpellbook(itemStackData, dynamic); } - - // TODO: visual override component + if (item instanceof IotaHolderItem) { + itemStackData.moveTagToComponent("VisualOverride", "hexcasting:visual_override"); + } // TODO: item variant component // TODO: wait for #1220, then hex holder component // TODO: media component diff --git a/Common/src/main/resources/hexplat.accesswidener b/Common/src/main/resources/hexplat.accesswidener index 24e391e488..191d7aaf35 100644 --- a/Common/src/main/resources/hexplat.accesswidener +++ b/Common/src/main/resources/hexplat.accesswidener @@ -8,4 +8,5 @@ accessible method net/minecraft/world/item/crafting/Ingredient (Ljava/uti accessible method net/minecraft/world/item/context/UseOnContext (Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/InteractionHand;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/phys/BlockHitResult;)V accessible method net/minecraft/world/damagesource/DamageSources source (Lnet/minecraft/resources/ResourceKey;)Lnet/minecraft/world/damagesource/DamageSource; accessible method net/minecraft/world/damagesource/DamageSources source (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/world/entity/Entity;)Lnet/minecraft/world/damagesource/DamageSource; -accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData \ No newline at end of file +accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData +accessible field net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData item Ljava/lang/String; \ No newline at end of file From c21f4e458c35d5818ea606533311b27d0d74f3b0 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 09:47:35 +0200 Subject: [PATCH 15/19] feat: datafix variant items --- .../mixin/datafixer/MixinItemStackComponentizationFix.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 90c375432e..5a0c4b071b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -2,6 +2,7 @@ import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.item.IotaHolderItem; +import at.petrak.hexcasting.api.item.VariantItem; import com.mojang.serialization.Dynamic; import java.util.*; @@ -58,7 +59,9 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna if (item instanceof IotaHolderItem) { itemStackData.moveTagToComponent("VisualOverride", "hexcasting:visual_override"); } - // TODO: item variant component + if (item instanceof VariantItem) { + itemStackData.moveTagToComponent("variant", "hexcasting:variant"); + } // TODO: wait for #1220, then hex holder component // TODO: media component // TODO: media_max component From 5fbc36aafc725fde1fff18326d54ff9691476e12 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 09:54:23 +0200 Subject: [PATCH 16/19] feat: datafix media holder items --- .../datafixer/MixinItemStackComponentizationFix.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 5a0c4b071b..999b6d5e7b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -3,6 +3,8 @@ import at.petrak.hexcasting.api.casting.math.HexPattern; import at.petrak.hexcasting.api.item.IotaHolderItem; import at.petrak.hexcasting.api.item.VariantItem; +import at.petrak.hexcasting.common.items.magic.ItemMediaHolder; +import at.petrak.hexcasting.common.items.magic.ItemPackagedHex; import com.mojang.serialization.Dynamic; import java.util.*; @@ -62,9 +64,13 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna if (item instanceof VariantItem) { itemStackData.moveTagToComponent("variant", "hexcasting:variant"); } - // TODO: wait for #1220, then hex holder component - // TODO: media component - // TODO: media_max component + if (item instanceof ItemPackagedHex) { + // TODO: wait for #1220, then hex holder component + } + if (item instanceof ItemMediaHolder) { + itemStackData.moveTagToComponent("hexcasting:media", "hexcasting:media"); + itemStackData.moveTagToComponent("hexcasting:start_media", "hexcasting:start_media"); + } } @Unique From 5ed15132038c530b347972f93611dcf6c9d239a6 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 12:21:53 +0200 Subject: [PATCH 17/19] fix: slate and spellbook pages --- .../mixin/datafixer/MixinItemStackComponentizationFix.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 999b6d5e7b..ecc0c13d45 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -35,7 +35,7 @@ private static void preFixHexItemStack(ItemStackData itemStackData, Dynamic d if (itemStackData.is("hexcasting:slate")) { itemStackData.fixSubTag("BlockEntityTag", false, dynamic0 -> hexCasting$mapPattern(dynamic0.get("pattern").orElseEmptyMap())); - itemStackData.moveTagToComponent("BlockEntityTag", "pattern"); + itemStackData.moveTagToComponent("BlockEntityTag", "hexcasting:pattern"); } } @@ -200,7 +200,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna itemStackData.moveTagToComponent("page_names", "hexcasting:page_names"); itemStackData.fixSubTag("pages", true, d0 -> - d0.createMap(d0.asMap(Function.identity(), MixinItemStackComponentizationFix::hexCasting$mapPattern))); + d0.createMap(d0.asMap(Function.identity(), MixinItemStackComponentizationFix::hexCasting$mapIotaData))); itemStackData.moveTagToComponent("pages", "hexcasting:pages"); itemStackData.moveTagToComponent("sealed_pages", "hexcasting:sealed_pages"); From 277b0ce0aef59b39dd7baf16447b664d38242217 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Fri, 31 Jul 2026 12:43:09 +0200 Subject: [PATCH 18/19] fix: new thoth behavior --- .../mixin/datafixer/MixinItemStackComponentizationFix.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index ecc0c13d45..2f9b91298a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -163,9 +163,8 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna frame.createList(frameData.get("code").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); component.put(frame.createString("context"), frame.createList(frameData.get("base").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); - // TODO: figure out whether stashed should be base (replicating otherwise unavailable 1.20 thoth behavior) or an empty list (equivalent to 1.21 thoth with whatever size the stack had before casting) component.put(frame.createString("stashed"), - frame.createList(frameData.get("base").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); + frame.createList(Stream.of())); component.put(frame.createString("accumulator"), frame.createList(frameData.get("accumulator").asStream().map(MixinItemStackComponentizationFix::hexCasting$mapIotaData))); break; From da7617f9ea40373c05258dab19097d0b395ea595 Mon Sep 17 00:00:00 2001 From: flmeyer Date: Sat, 1 Aug 2026 09:17:42 +0200 Subject: [PATCH 19/19] feat: datafix ItemPackagedHex (depends on #1220) --- .../MixinItemStackComponentizationFix.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java index 2f9b91298a..afcfbb7585 100644 --- a/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java +++ b/Common/src/main/java/at/petrak/hexcasting/mixin/datafixer/MixinItemStackComponentizationFix.java @@ -56,7 +56,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna itemStackData.moveTagToComponent("value", "hexcasting:abacus_value"); } if (itemStackData.is("hexcasting:spellbook")) { - hexCasting$fixSpellbook(itemStackData, dynamic); + hexCasting$fixSpellbook(itemStackData); } if (item instanceof IotaHolderItem) { itemStackData.moveTagToComponent("VisualOverride", "hexcasting:visual_override"); @@ -65,7 +65,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna itemStackData.moveTagToComponent("variant", "hexcasting:variant"); } if (item instanceof ItemPackagedHex) { - // TODO: wait for #1220, then hex holder component + hexCasting$fixPackagedHex(itemStackData, dynamic); } if (item instanceof ItemMediaHolder) { itemStackData.moveTagToComponent("hexcasting:media", "hexcasting:media"); @@ -191,7 +191,7 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna } @Unique - private static void hexCasting$fixSpellbook(ItemStackData itemStackData, Dynamic dynamic) { + private static void hexCasting$fixSpellbook(ItemStackData itemStackData) { itemStackData.moveTagToComponent("page_idx", "hexcasting:page_idx"); itemStackData.fixSubTag("page_names", true, d0 -> @@ -204,4 +204,15 @@ private static void fixHexItemStack(ItemStackData itemStackData, Dynamic dyna itemStackData.moveTagToComponent("sealed_pages", "hexcasting:sealed_pages"); } + + @Unique + private static void hexCasting$fixPackagedHex(ItemStackData itemStackData, Dynamic dynamic) { + Stream> patterns = itemStackData.removeTag("patterns").asStream() + .map(MixinItemStackComponentizationFix::hexCasting$mapIotaData); + Dynamic pigment = itemStackData.removeTag("pigment").orElseEmptyMap(); + Dynamic hexHolder = dynamic.createMap(Map.of( + dynamic.createString("hex"), dynamic.createList(patterns), + dynamic.createString("pigment"), pigment)); + itemStackData.setComponent("hexcasting:hex_holder", hexHolder); + } }