WIP: hexic 2.1.0+6afea87f [kwlznnky] #5

Draft
poolcritter wants to merge 1 commit from poolcritter/Hexwoven:push-qprrktmrmnup into main
Collaborator
diff --git a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json
index e964caa72d..9c26e2152e 100644
--- a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json
+++ b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json
@@ -22,11 +22,11 @@
         },
         {
             "type": "hexcasting:pattern",
-            "op_id": "hexic:dye_offhand",
-            "anchor": "hexic:dye_offhand",
+            "op_id": "hexic:dye_offpaw",
+            "anchor": "hexic:dye_offpaw",
             "input": "pigment",
             "output": "",
-            "text": "book.hexic.page.dye_offhand"
+            "text": "book.hexic.page.dye_offpaw"
         },
         {
             "type": "hexcasting:pattern",
diff --git a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json
index 1b7f69c24a..e64009048c 100644
--- a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json
+++ b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json
@@ -22,11 +22,11 @@
         },
         {
             "type": "hexcasting:pattern",
-            "op_id": "hexic:dye_offhand",
-            "anchor": "hexic:dye_offhand",
+            "op_id": "hexic:dye_offpaw",
+            "anchor": "hexic:dye_offpaw",
             "input": "pigment",
             "output": "",
-            "text": "book.hexic.page.dye_offhand"
+            "text": "book.hexic.page.dye_offpaw"
         },
         {
             "type": "hexcasting:pattern",
diff --git a/project/hexic/changelog b/project/hexic/changelog
index dafa529e8e..6e66aa454c 100644
--- a/project/hexic/changelog
+++ b/project/hexic/changelog
@@ -31,5 +31,16 @@
 2.0.0 rename media bundles to casting pouches
 2.0.0 sent Stickia to the milk dimension
 2.0.0 textures now use JPEG XL
+2.1.0 added -Dhexic.max_stack_size to cap itemstack size at deserialization-time (default: max integer)
 2.1.0 added equipment macros
-2.1.0 fix hitbox for void blocks
+2.1.0 demiplane spells' docs have been changed again
+2.1.0 dual's reflection only considers players in ambit
+2.1.0 hitbox for void blocks is no longer weirdly offset
+2.1.0 item/fluid concept displays no longer suck
+2.1.0 mediaweave can now actually be erased, sorry
+2.1.0 mediaweave can now be tied
+2.1.0 negative item stacks are now disabled by default, they can be reenabled by setting -Dhexic.min_stack_size to your favorite value
+2.1.0 read-only properties can no longer be converted to access iotas
+2.1.0 Refinement Distillation now properly drops input iotas on first loop as it should
+2.1.0 translations have been updated [@chuijk]
+2.1.0 wool and carpet edification are now actually somewhat balanced wrt each other
diff --git a/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala b/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala
index 5b2c0d801d..0908969192 100644
--- a/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala
+++ b/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala
@@ -390,10 +390,12 @@
           "attachworld" -> "Bind Demiplane",
           "blind" -> "Hidden Sun's Nadir",
           "collar" -> "Tie Mediaweave",
+          "conceptavailable" -> "Debit Purification",
+          "conceptremaining" -> "Credit Purification",
           "decollar" -> "Untie Mediaweave",
           "deleteworld" -> "Shatter Demiplane",
           "drop" -> "Rejection Distillation",
-          "dye_offhand" -> "Apply Pigment",
+          "dye_offpaw" -> "Apply Pigment",
           "erase" -> "Erase Block",
           "extract" -> "Excisor's Gambit",
           "findview" -> "Reflection Purification",
@@ -453,7 +455,7 @@
           case p: PigmentItem => gen.add("item.hexic.stringworm." + p.getTranslationKey, "Shimmering " + hexLang(p.getTranslationKey).replace("Pigment", "Stringworm"))
           case e => println(e)
         for page -> text <- Vector(
-          "dye_offhand" -> "Imbues the item held in my offhand (e.g. a $(l:items/hexcasting)$(item)casting item/$) with the given pigment.",
+          "dye_offpaw" -> "Imbues the item held in my offhand (e.g. a $(l:items/hexcasting)$(item)casting item/$) with the given pigment.",
           "erase" -> "Erases the _Hex or iota contained within a dropped item or block. Costs one dust per item.",
           "get_other_caster" -> "Adds the closest sentient being, excluding me, to the stack.",
           "modulo" -> "Similar to Modulus, but differs for negative numbers: -8 %%₁ 3 = -2, but -8 %%₂ 3 = 1.",
diff --git a/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json b/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json
index 73cde66b4b..4df36a4627 100644
--- a/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json
+++ b/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json
@@ -4,14 +4,14 @@
   "category": "hexcasting:patterns",
   "icon": "minecraft:white_carpet",
   "pages": [
-    "the world under my control nature is mine na$(bold)ture is MI/$NE the world $(underline)the world NO LONGER/$ will $(bold)the OVerworld rule me/$ My $(media)mind is going/$ My $(media)mind/$ is going $(o)THE PAIN OF THOUGHT/$ my mind my $(o)mind/$ my a nine by nine room to myself SOLELY MYE$(bold)LF NO ONE ELSE/$ a $(bold)burst/$ of _media to Shatter the $(media)world/$ nearly $(media)six` allays $(bold)sewn/$ into $(underline)the walls/$ for eternity oh how it must hurt $(bold)IT HURTS IT/$ $(k)TORTUES/$",
+    "the world under my control nature is mine na$(bold)ture is MI/$NE the world $(underline)the world NO LONGER/$ will $(bold)the OVerworld rule me/$ My $(media)mind is going/$ My $(media)mind/$ is going $(o)THE PAIN OF THOUGHT/$ my mind my $(o)mind/$ my a nine by nine room to myself SOLELY MYE$(bold)LF NO ONE ELSE/$ a $(bold)burst/$ of _media to Shatter the $(media)world/$ nearly $(media)six allays $(bold)sewn/$ into $(underline)the walls/$ for eternity oh how it must hurt $(bold)IT HURTS IT/$ $(k)TORTUES/$",
     {
       "type": "hexcasting:pattern",
       "op_id": "hexic:makeworld",
       "anchor": "hexic:makeworld",
       "input": "",
       "output": "imprint",
-      "text": "Creates a fresh cuboid with a 9x9x9 interior, as well as a dimension to hold it in. Costs 18.2 thousand dust."
+      "text": "Creates a fresh cuboid with a 9x9x9 interior, as well as a dimension to hold it in. Costs six quenched allays (720 dust)."
     },
     "fragments of space the $(media)world/$ falling apart crumpling a $(o)fine powder/$ to the _media tie my plane TIE IT DOWN WELL bindings of $(media)thought/$ to keep it safe safe from others safe from $(media)me/$ only $(bold)a sliver of an allay's mind for the price/$ eternally trapped n$(underline)ot alive not dead mer/$ely floating Form the $(media)allay into bindings f/$rom some point outside must $(underline)hurry/$ now $(o)I feel it slipping away/$ $(bold)the cost of tying it to itself $(o)disasterous/$ the plane slipping away $(media)my/$ mind slipping away",
     {
@@ -20,7 +20,7 @@
       "anchor": "hexic:attachworld",
       "input": "imprint, vec",
       "output": "",
-      "text": "Binds the given demiplane to a position. This position is used when exiting the demiplane, as well as in case of any $(o)unfortunate accidents/$. Mishaps if I bind a demiplane to the plane I'm in."
+      "text": "Binds the given demiplane to a position in my current dimension (which must not be the demiplane itself). This position is used when exiting the demiplane, as well as in case of any $(o)unfortunate accidents/$. Costs one shard."
     },
     "My mind is drifting drifting $(o)spinning/$, $(o)running/$ from me with every slice I take of Nature. Every passing moment my grip oh my hands weakening my mind passing through like sand$(2br)I must steady myself. The price of sanity is outright shattering the planes I've made — a burst of media worth 25 shards, and the pocket will crumple like a villager, spewing its contents into where it was bound.$(2br)Testing this process on living creatures is unwise.",
     {
@@ -29,7 +29,7 @@
       "anchor": "hexic:deleteworld",
       "input": "imprint, vec",
       "output": "",
-      "text": "Ruptures the boundaries of the given demiplane, destroying its contents. All dropped items and experience are spewed at the plane's attachment point."
+      "text": "Ruptures the boundaries of the given demiplane, destroying its contents. All dropped items and experience are spewed at the plane's attachment point. Costs five shards."
     }
   ]
 }
diff --git a/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch b/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch
index 9facfb0031..44ac1dc795 100644
--- a/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch
+++ b/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch
@@ -3,9 +3,9 @@
 
 $pages = arrays.push($pages, {
   type: "hexcasting:pattern",
-  op_id: "hexic:dye_offhand",
-  anchor: "hexic:dye_offhand",
+  op_id: "hexic:dye_offpaw",
+  anchor: "hexic:dye_offpaw",
   input: "pigment",
   output: "",
-  text: "book.hexic.page.dye_offhand"
+  text: "book.hexic.page.dye_offpaw"
 });
\ No newline at end of file
diff --git a/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json b/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json
index 8e105e5a89..759f98e161 100644
--- a/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json
+++ b/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json
@@ -1,5 +1,5 @@
 {
-  "book.hexic.page.dye_offhand": "将所给染色剂内化到我副手中的物品(如$(l:items/hexcasting)$(item)施法物品/$)里。",
+  "book.hexic.page.dye_offpaw": "将所给染色剂内化到我副手中的物品(如$(l:items/hexcasting)$(item)施法物品/$)里。",
   "book.hexic.page.erase": "清除物品实体或方块中的$(hex)咒术/$或 iota。每个物品消耗 1 个紫水晶粉。",
   "book.hexic.page.get_other_caster": "将离我最近的有智慧存在压入栈,我自己不计入统计范围。",
   "book.hexic.page.modulo": "与余数之馏化类似,但两者在负数上的表现不同:-8 %%₁ 3 = -2,而 -8 %%₂ 3 = 1。",
@@ -8,7 +8,7 @@
   "hexcasting.action.hexic:blind": "隐阳西沉",
   "hexcasting.action.hexic:deleteworld": "击碎半位面",
   "hexcasting.action.hexic:drop": "拒斥之馏化",
-  "hexcasting.action.hexic:dye_offhand": "应用染色剂",
+  "hexcasting.action.hexic:dye_offpaw": "应用染色剂",
   "hexcasting.action.hexic:erase": "清除方块",
   "hexcasting.action.hexic:extract": "切除器之策略",
   "hexcasting.action.hexic:findview": "精思之纯化",
diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala b/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala
index b37ee240e5..bf6ff8347e 100644
--- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala
+++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala
@@ -14,7 +14,7 @@
 import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, CastingEnvironmentComponent, MishapEnvironment, OperationResult, ResolvedPattern, ResolvedPatternType}
 import at.petrak.hexcasting.api.casting.iota.*
 import at.petrak.hexcasting.api.casting.math.{HexDir, HexPattern}
-import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapBadOffhandItem, MishapInvalidIota, MishapInvalidOperatorArgs, MishapNotEnoughArgs, MishapOthersName, MishapTooManyCloseParens}
+import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapInvalidIota, MishapInvalidOperatorArgs, MishapNotEnoughArgs, MishapOthersName, MishapTooManyCloseParens, MishapBadOffhandItem as MishapBadOffpawItem}
 import at.petrak.hexcasting.api.pigment.FrozenPigment
 import at.petrak.hexcasting.api.utils.{HexUtils, MediaHelper}
 import at.petrak.hexcasting.common.lib.{HexAttributes, HexItems, HexRegistries, HexSounds}
@@ -73,7 +73,7 @@
 import net.minecraft.text.{HoverEvent, LiteralTextContent, MutableText, Style, Text, TextColor, TextContent, Texts}
 import net.minecraft.util.dynamic.Codecs
 import net.minecraft.util.math.{BlockPointer, BlockPos, ChunkPos, Direction, Vec3d}
-import net.minecraft.util.{ActionResult, Arm, ClickType, DyeColor, Formatting, Hand, Identifier, Rarity, TypedActionResult, Util, Uuids, WorldSavePath}
+import net.minecraft.util.{ActionResult, Arm, ClickType, DyeColor, Formatting, Identifier, Rarity, TypedActionResult, Util, Uuids, WorldSavePath, Hand as Paw}
 import net.minecraft.world.biome.Biome
 import net.minecraft.world.{BlockView, TeleportTarget, World}
 import org.eu.net.pool.hexic
@@ -492,18 +492,18 @@
 
 case class Pen private [hexic] (color: DyeColor) extends Item(Item.Settings().maxCount(1)) with Registered(Registries.ITEM, s"pen/$color"):
   override def toString = s"$getClass(color=$color)${super[Item].toString}"
-  override def use(world: World, player: PlayerEntity, hand: Hand): TypedActionResult[ItemStack] =
+  override def use(world: World, player: PlayerEntity, paw: Paw): TypedActionResult[ItemStack] =
     // if player.getAttributeValue(HexAttributes.FEEBLE_MIND) > 0.0 then
-    //   TypedActionResult.fail(player.getStackInHand(hand))
+    //   TypedActionResult.fail(player.getStackInHand(paw))
     // else
       if !world.isClient && player.isInstanceOf[ServerPlayerEntity] then
         val serverPlayer: ServerPlayerEntity = player.asInstanceOf[ServerPlayerEntity]
-        val vm = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, hand)
+        val vm = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, paw)
         val patterns = IXplatAbstractions.INSTANCE.getPatternsSavedInUi(serverPlayer).asScala
         val descs = vm.generateDescs
-        IXplatAbstractions.INSTANCE.sendPacketToPlayer(serverPlayer, new MsgOpenSpellGuiS2C(hand, patterns, descs.getFirst, descs.getSecond, 0))
+        IXplatAbstractions.INSTANCE.sendPacketToPlayer(serverPlayer, new MsgOpenSpellGuiS2C(paw, patterns, descs.getFirst, descs.getSecond, 0))
       player.incrementStat(Stats.USED.getOrCreateStat(this))
-      TypedActionResult.success(player.getStackInHand(hand))
+      TypedActionResult.success(player.getStackInHand(paw))
 object Pen:
   val instances: DyeColor :> Pen = DyeColor.values.map(c => c -> new Pen(c)).toMap
 
@@ -518,11 +518,18 @@
         case c: NbtCompound => c
         case _ => null
   override def writeable(stack: ItemStack): Boolean = true
-  override def canWrite(stack: ItemStack, iota: Iota): Boolean = iota match
-    case l: ListIota => true
-    case _ => iota.executable
+  override def canWrite(stack: ItemStack, iota: Iota): Boolean =
+    iota match
+      case null => true
+      case l: ListIota => true
+      case _ => iota.executable
   override def writeDatum(stack: ItemStack, iota: Iota): Unit =
-    stack.getOrCreateNbt.put("Hex", IotaType.serialize(iota))
+    iota match
+      case null =>
+        for nbt <- Option(stack.getNbt) do
+          nbt.remove("Hex")
+          if nbt.isEmpty then stack.setNbt(null)
+      case iota => stack.getOrCreateNbt.put("Hex", IotaType.serialize(iota))
   override def appendTooltip(stack: ItemStack, world: World, tooltip: util.List[Text], context: TooltipContext): Unit =
     IotaHolderItem.appendHoverText(this, stack, tooltip, context)
   DispenserBlock.registerBehavior(this, new ItemDispenserBehavior:
@@ -916,7 +923,7 @@
   private val DUST_AMOUNT = new DecimalFormat("###,###.##")
 val wizard = Item(Item.Settings().rarity(Rarity.EPIC).maxCount(1))
 
-val aLotOfMedia = (200000 /* max phial size */ * 6 /* phials per small pouch */ * 4 /* small pouches per large pouch */ * (36 /* inventory slots */ + 4 /* armor slots */ + 2 /* offhands */) + 20 /* healthcasting */) * MediaConstants.DUST_UNIT
+val aLotOfMedia = (200000 /* max phial size */ * 6 /* phials per small pouch */ * 4 /* small pouches per large pouch */ * (36 /* inventory slots */ + 4 /* armor slots */ + 2 /* offpaws */) + 20 /* healthcasting */) * MediaConstants.DUST_UNIT
 
 class Event[T, R](default: T => R) extends (T => R):
   private var current = default
@@ -1108,9 +1115,9 @@
       override def getCollisionShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape =
         getOutlineShape(state, world, pos, context)
 
-      override def onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult = boundary:
+      override def onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, paw: Paw, hit: BlockHitResult): ActionResult = boundary:
         lazy val entity = findEntity(world, pos).getOrElse(boundary.break(ActionResult.FAIL))
-        player.getStackInHand(hand) match
+        player.getStackInHand(paw) match
           case stack@ItemStackAccess(HexItems.CHARGED_AMETHYST, _, _) if !(for i <- 0 until 14; j <- 0 until 14 yield entity.bit(i, j)).all =>
             for i <- 0 until 14; j <- 0 until 14 do
               entity.bit(i, j) = true
@@ -1151,12 +1158,12 @@
       registerHopperEndpoint <- classNamed("org.eu.net.pool.registerHopperEndpoint")
     do
       registerHopperEndpoint.runtimeClass.newInstance().asInstanceOf[() => Unit]()
-    Patterns.register("dye_offhand", w"eqdeeqdweeqddqdwwdew"):
+    Patterns.register("dye_offpaw", w"eqdeeqdweeqddqdwwdew"):
       Patterns.mkAction: (img, cont) =>
         val stack = img.getStack.asScala
         stack.lastOption.getOrElse(throw MishapNotEnoughArgs(1, 0)) match
           case p: PigmentIota =>
-            val info = summon[CastingEnvironment].getHeldItemToOperateOn(!_.isEmpty).pipe(Option(_)).getOrElse(throw MishapBadOffhandItem(null, Text.translatable("text.hexic.pigment_holder_item")))
+            val info = summon[CastingEnvironment].getHeldItemToOperateOn(!_.isEmpty).pipe(Option(_)).getOrElse(throw MishapBadOffpawItem(null, Text.translatable("text.hexic.pigment_holder_item")))
             (img.withStack(_.init), cont, HexEvalSounds.SPELL, Seq:
               OperatorSideEffect.AttemptSpell(
                 new RenderedSpell:
@@ -1172,20 +1179,20 @@
           case i => throw MishapInvalidIota.ofType(i, 0, "pigment")
   Patterns.register("prop_fi", sw"aawqe"):
     Patterns.mkConstAction(1):
-      case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Writer(x.getName, "head"))
-      case Seq(x) => throw MishapInvalidIota(x, 0, "property")
+      case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Writer(x.getName, "head"))
+      case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop")
   Patterns.register("prop_fo", sw"aawqd"):
     Patterns.mkConstAction(1):
-      case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Stream(x.getName, "head"))
-      case Seq(x) => throw MishapInvalidIota(x, 0, "property")
+      case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Stream(x.getName, "head"))
+      case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop")
   Patterns.register("prop_li", sw"aawdwq"):
     Patterns.mkConstAction(1):
-      case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Writer(x.getName, "tail"))
-      case Seq(x) => throw MishapInvalidIota(x, 0, "property")
+      case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Writer(x.getName, "tail"))
+      case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop")
   Patterns.register("prop_lo", sw"aawdwa"):
     Patterns.mkConstAction(1):
-      case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Stream(x.getName, "tail"))
-      case Seq(x) => throw MishapInvalidIota(x, 0, "property")
+      case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Stream(x.getName, "tail"))
+      case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop")
   Patterns.register("where", nw"qaeaqwdd"):
     Patterns.mkConstAction(1): i =>
       val Seq(x) = i
@@ -1466,7 +1473,7 @@
                 override def cast(env: CastingEnvironment): Unit =
                   world.parentInfo = Some(env.getWorld.getRegistryKey, pos)
                 override def cast(env: CastingEnvironment, image: CastingImage): CastingImage = { cast(env); image },
-                MediaConstants.SHARD_UNIT * 3,
+                MediaConstants.SHARD_UNIT,
                 Seq(),
                 1
             )
@@ -1592,7 +1599,7 @@
       summon[CastingEnvironment].getCastingEntity match
         case caster: ServerPlayerEntity =>
           val staffcast = HexCardinalComponents.STAFFCAST_IMAGE.get(caster)
-          val oldImage = staffcast.getVM(Hand.MAIN_HAND).getImage
+          val oldImage = staffcast.getVM(Paw.MAIN_HAND).getImage
           staffcast.setImage(img)
           val vm = staffcast.getVM(summon[CastingEnvironment].getCastingHand)
           try
@@ -1659,7 +1666,7 @@
         others = others.filter:
           case _: EntityPlayerMPFake => false
           case _ => true
-      val sorted = others.toSeq.sortBy(_.getPos.squaredDistanceTo(summon[CastingEnvironment].mishapSprayPos))
+      val sorted = others.toSeq.sortBy(_.getPos.squaredDistanceTo(summon[CastingEnvironment].mishapSprayPos)).filter(summon[CastingEnvironment].isEntityInRange(_, true))
       sorted.headOption.fold(NullIota())(EntityIota(_))
   Patterns.register("blind", se"qqqqqadwawawd")(OpPotionEffect(StatusEffects.BLINDNESS, 1000, false, false))
   Patterns.register("erase", e"wqwdwqwawwwwwawwwww"):
diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java
index 3ebbe0c9cd..4189c5d923 100644
--- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java
+++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java
@@ -3,7 +3,6 @@
 import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
 import at.petrak.hexcasting.api.casting.iota.GarbageIota;
 import at.petrak.hexcasting.api.casting.iota.IotaType;
-import at.petrak.hexcasting.api.casting.iota.ListIota;
 import at.petrak.hexcasting.xplat.IXplatAbstractions;
 import net.minecraft.client.item.TooltipContext;
 import net.minecraft.entity.player.PlayerEntity;
@@ -14,15 +13,12 @@
 import net.minecraft.nbt.NbtList;
 import net.minecraft.server.network.ServerPlayerEntity;
 import net.minecraft.server.world.ServerWorld;
-import net.minecraft.text.MutableText;
 import net.minecraft.text.Text;
-import net.minecraft.text.TranslatableTextContent;
 import net.minecraft.util.Hand;
 import net.minecraft.util.TypedActionResult;
 import net.minecraft.world.World;
 import org.jetbrains.annotations.Nullable;
 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;
@@ -45,14 +41,14 @@
     }
 
     @Inject(method = "use", at = @At("HEAD"), cancellable = true)
-    void use(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable<TypedActionResult<ItemStack>> cir) {
+    void use(World world, PlayerEntity user, Hand paw, CallbackInfoReturnable<TypedActionResult<ItemStack>> cir) {
         if ((Object) this != ECHO_SHARD) return;
-        ItemStack stack = user.getStackInHand(hand);
+        ItemStack stack = user.getStackInHand(paw);
         NbtCompound nbt = stack.getNbt();
         if (nbt == null) return;
         NbtList patterns = nbt.getList("hexic:memory", NbtElement.COMPOUND_TYPE);
         if (patterns.isEmpty() || world.isClient || !(world instanceof ServerWorld serverWorld && user instanceof ServerPlayerEntity serverPlayer)) return;
-        CastingVM staffcast = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, hand);
+        CastingVM staffcast = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, paw);
         stack.decrement(1);
         NbtCompound newNbt = nbt.copy();
         newNbt.remove("hexic:memory");
diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java
index c8633b5865..53568ebe3e 100644
--- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java
+++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java
@@ -5,11 +5,13 @@
 import net.minecraft.item.ItemStack;
 import net.minecraft.nbt.NbtCompound;
 import net.minecraft.nbt.NbtElement;
+import org.eu.net.pool.hexic.cfg;
 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 scala.util.CommandLineParser;
 
 @Mixin(ItemStack.class)
 public class ItemStackMixin {
@@ -20,6 +22,10 @@
         if (nbt.contains("Count", NbtElement.INT_TYPE)) {
             count = nbt.getInt("Count");
         }
+        int minSize = cfg.apply("hexic.min_stack_size", Integer::parseInt).getOrElse(() -> 0);
+        int maxSize = cfg.apply("hexic.max_stack_size", Integer::parseInt).getOrElse(() -> Integer.MAX_VALUE);
+        if (count < minSize) count = minSize;
+        if (count > maxSize) count = maxSize;
     }
 
     @WrapOperation(method = {"writeNbt", "method_7953"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NbtCompound;putByte(Ljava/lang/String;B)V"))
diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java
index 0e4e0babec..2323fd23c3 100644
--- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java
+++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java
@@ -41,13 +41,13 @@
             return true;
         }
         if (original.call(instance, BlockTags.WOOL)) {
+            mediaweave.set(2);
+            return true;
+        }
+        if (original.call(instance, BlockTags.WOOL_CARPETS)) {
             mediaweave.set(3);
             return true;
         }
-        if (original.call(instance, BlockTags.WOOL_CARPETS)) {
-            mediaweave.set(2);
-            return true;
-        }
         if (instance.isOf(Blocks.TRIPWIRE)) {
             mediaweave.set(-1);
             return true;
diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java
index 47a562d537..f0263f8703 100644
--- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java
+++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java
@@ -62,9 +62,9 @@
             return;
         }
         // TODO: consider whether shards should intercept pen patterns
-        ItemStack offhandStack = sender.getStackInHand(vm.getEnv().getOtherHand());
-        if (offhandStack.isOf(ECHO_SHARD)) {
-            NbtCompound tag = offhandStack.getOrCreateNbt();
+        ItemStack offpawStack = sender.getStackInHand(vm.getEnv().getOtherHand());
+        if (offpawStack.isOf(ECHO_SHARD)) {
+            NbtCompound tag = offpawStack.getOrCreateNbt();
             NbtList queuedPatterns = tag.getList("hexic:memory", NbtElement.COMPOUND_TYPE);
             queuedPatterns.add(IotaType.serialize(new PatternIota(msg.pattern())));
             tag.put("hexic:memory", queuedPatterns);
diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala b/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala
index 5596117816..63f4ecadf0 100644
--- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala
+++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala
@@ -35,6 +35,8 @@
 import net.minecraft.world.{BlockView, TeleportTarget, World}
 import org.eu.net.pool.phlib.{*, given}
 import org.slf4j.{Logger, LoggerFactory}
+import ram.talia.hexal.api.casting.iota.MoteIota
+import ram.talia.hexal.api.mediafieditems.MediafiedItemManager
 import ram.talia.moreiotas.api.casting.iota.{ItemStackIota, ItemTypeIota}
 
 import java.util.UUID
@@ -88,6 +90,7 @@
     override def isTruthy = views ∃(_.isTruthy)
     override def asText = views match
       case Seq() => "∅"
+      case h +: t => (Text.empty().append(h.asText) /: t) (_ `append` "+" `append` _.asText)
     override def serialize =
       val c = NbtCompound()
       val list = NbtList()
@@ -131,7 +134,9 @@
         view <- InventoryView.deserialize(c)
       yield view)*))
   private given typeOfEntity: InventoryView.Type[OfEntity]:
-    override def deserialize(data: NbtCompound)(using ServerWorld): Option[OfEntity] = ???
+    override def deserialize(data: NbtCompound)(using world: ServerWorld): Option[OfEntity] =
+      given MinecraftServer = world.getServer
+      Some(OfEntity(UUID(data.getLong("m"), data.getLong("l"))))
   private given typeOfBlock: InventoryView.Type[OfBlock]:
     override def deserialize(data: NbtCompound)(using ServerWorld): Option[OfBlock] =
       for
@@ -302,6 +307,26 @@
   setConceptScale[FluidVariant](81000)
   setConceptScale[SingletonVariant.media.type](10000)
   setConceptScale[SingletonVariant.heat.type](20)
+  Patterns.register("conceptavailable", sw"wedwqwdewwaqaa"):
+    Patterns.mkConstAction(2):
+      case Seq(BoxedView.Instance(target), VariantIota(typ, _)) =>
+        Using.resource(Transaction.openOuter()):
+          case tx@given Transaction =>
+            val amt = target.tryExtract(typ, Long.MaxValue) / conceptScale(ClassTag(typ.getClass))
+            tx.abort()
+            Seq(DoubleIota(amt))
+      case Seq(_: BoxedView.Instance, perp) => throw MishapInvalidIota(perp, 0, VariantIota.typeName)
+      case Seq(perp, _) => throw MishapInvalidIota(perp, 1, BoxedView.typeName)
+  Patterns.register("conceptremaining", sw"wedwqwdewadedd"):
+    Patterns.mkConstAction(2):
+      case Seq(BoxedView.Instance(target), VariantIota(typ, _)) =>
+        Using.resource(Transaction.openOuter()):
+          case tx@given Transaction =>
+            val amt = target.tryInsert(typ, Long.MaxValue) / conceptScale(ClassTag(typ.getClass))
+            tx.abort()
+            Seq(DoubleIota(amt))
+      case Seq(_: BoxedView.Instance, perp) => throw MishapInvalidIota(perp, 0, VariantIota.typeName)
+      case Seq(perp, _) => throw MishapInvalidIota(perp, 1, BoxedView.typeName)
   Patterns.register("moveconcept", se"wawdwawqdewewedqwawdwaw"):
     Patterns.mkConstAction(4):
       case Seq(isIota[BoxedView.Instance, 3](BoxedView.Instance(from)), isIota[BoxedView.Instance, 2](BoxedView.Instance(into)), typ: VariantIota[?], isIota[DoubleIota, 0](count)) =>
@@ -366,6 +391,12 @@
               case s: ItemEntity => Seq(if s.getStack.getItem == Items.AIR then NullIota() else VariantIota(ItemVariant.of(s.getStack), RegistryKey.of(VariantIota.key, Identifier("item"))))
               case s: ItemFrameEntity => Seq(if s.getHeldItemStack.getItem == Items.AIR then NullIota() else VariantIota(ItemVariant.of(s.getHeldItemStack), RegistryKey.of(VariantIota.key, Identifier("item"))))
               case _ => dieOfBadType()
+          case m: MoteIota if MediafiedItemManager.contains(m.getItemIndex) =>
+            Seq(
+              if m.getItem == Items.AIR then
+                NullIota()
+              else
+                VariantIota(ItemVariant.of(m.getItem, m.getTag), RegistryKey.of(VariantIota.key, Identifier("item"))))
           case _ => dieOfBadType()
 //noinspection UnstableApiUsage
 case class VariantIota[T: ClassTag](data: TransferVariant[T], key: RegistryKey[VariantIota.Reader]) extends Iota(VariantIota, data):
@@ -426,6 +457,11 @@
       type T = SingletonVariant
       def variant = SingletonVariant.media
       def display: Text = Text.literal("Media").styled(_.withColor(0x74b3f2)))
+  registry("heat") = c =>
+    Some(new TaggedVariant:
+      type T = SingletonVariant
+      def variant = SingletonVariant.heat
+      def display: Text = Text.literal("Heat").styled(_.withColor(0xe08355)))
 
 //noinspection UnstableApiUsage
 class SingletonVariant extends TransferVariant[SingletonVariant]:
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f959142aa5..c876aad35c 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -22,6 +22,8 @@
     id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
 }
 
+rootProject.name = "hex-addons"
+
 include("util")
 includeBuild("plugin")
 for (mod in listOf("hexic", "iotaworks", "hexxytounge")) {
diff --git a/util/src/main/scala/org/eu/net/pool/phlib/main.scala b/util/src/main/scala/org/eu/net/pool/phlib/main.scala
index 1ec2991e8d..6ba3456877 100644
--- a/util/src/main/scala/org/eu/net/pool/phlib/main.scala
+++ b/util/src/main/scala/org/eu/net/pool/phlib/main.scala
@@ -1,56 +1,47 @@
 package org.eu.net.pool
 package phlib
 
-import at.petrak.hexcasting.api.utils.HexUtils
-import com.google.gson.JsonElement
-import com.mojang.serialization.{Codec, DynamicOps, JsonOps}
-import net.minecraft.nbt.{NbtByte, NbtByteArray, NbtDouble, NbtEnd, NbtFloat, NbtInt, NbtIntArray, NbtList, NbtLong, NbtLongArray, NbtOps, NbtShort, NbtString, NbtType}
-import net.minecraft.util.dynamic.Codecs
-import at.petrak.hexcasting.api.addldata.ADMediaHolder
-import scala.collection.{IterableOnceOps, IterableOps}
-import at.petrak.hexcasting.api.casting.{ActionRegistryEntry, ParticleSpray, RenderedSpell, SpellList}
-import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic
-import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator
-import at.petrak.hexcasting.api.casting.castables.{Action, ConstMediaAction, OperationAction, SpecialHandler, SpellAction}
-import at.petrak.hexcasting.api.casting.eval.env.PlayerBasedCastEnv
-import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect.DoMishap
+import at.petrak.hexcasting.api.casting.ActionRegistryEntry
+import at.petrak.hexcasting.api.casting.castables.{Action, ConstMediaAction, OperationAction}
 import at.petrak.hexcasting.api.casting.eval.sideeffects.{EvalSound, OperatorSideEffect}
-import at.petrak.hexcasting.api.casting.eval.vm.{CastingImage, CastingVM, ContinuationFrame, FrameEvaluate, SpellContinuation}
-import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, CastingEnvironmentComponent, MishapEnvironment, OperationResult, ResolvedPattern, ResolvedPatternType}
+import at.petrak.hexcasting.api.casting.eval.vm.{CastingImage, CastingVM, SpellContinuation}
+import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, CastingEnvironmentComponent, OperationResult}
 import at.petrak.hexcasting.api.casting.iota.*
 import at.petrak.hexcasting.api.casting.math.{HexDir, HexPattern}
-import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapBadOffhandItem, MishapInvalidIota, MishapInvalidOperatorArgs, MishapNotEnoughArgs, MishapOthersName, MishapTooManyCloseParens}
+import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapInvalidIota, MishapNotEnoughArgs}
+import at.petrak.hexcasting.api.utils.HexUtils
 import at.petrak.hexcasting.common.lib.HexRegistries
 import at.petrak.hexcasting.fabric.cc.HexCardinalComponents
+import com.google.gson.JsonElement
 import com.mojang.brigadier.builder.{LiteralArgumentBuilder, RequiredArgumentBuilder}
+import com.mojang.serialization.{Codec, DynamicOps, JsonOps}
 import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback
+import net.minecraft.command.argument.{EntityArgumentType, NbtElementArgumentType, RegistryEntryArgumentType}
 import net.minecraft.command.{CommandException, EntitySelector}
-import net.minecraft.command.argument.{EntityArgumentType, NbtElementArgumentType, RegistryEntryArgumentType}
-import net.minecraft.nbt.{NbtCompound, NbtElement}
+import net.minecraft.nbt.*
 import net.minecraft.server.command.ServerCommandSource
 import net.minecraft.server.network.ServerPlayerEntity
 import net.minecraft.server.world.ServerWorld
 import net.minecraft.util.Hand
+import net.minecraft.util.dynamic.Codecs
 
 import scala.annotation.tailrec
+import scala.collection.{IterableOnceOps, IterableOps}
 import scala.math.Ordered.orderingToOrdered
 import scala.reflect.ClassTag
 import scala.util.{Failure, Success, Try}
 export scala.collection.convert.ImplicitConversions.*
 export scala.util.chaining._
-import java.util
+import at.petrak.hexcasting.xplat.IXplatAbstractions
+import net.fabricmc.fabric.api.event.{Event, EventFactory}
 import net.fabricmc.loader.api.FabricLoader
+import net.minecraft.registry.{Registry, RegistryKey}
+import net.minecraft.text.{MutableText, Text}
 import net.minecraft.util.Identifier
+import org.slf4j.{Logger, LoggerFactory}
+
+import java.util
 import scala.util.boundary
-import org.slf4j.LoggerFactory
-import org.slf4j.Logger
-import at.petrak.hexcasting.xplat.IXplatAbstractions
-import net.minecraft.registry.Registry
-import net.minecraft.registry.RegistryKey
-import net.minecraft.text.MutableText
-import net.minecraft.text.Text
-import net.fabricmc.fabric.api.event.Event
-import net.fabricmc.fabric.api.event.EventFactory
 
 val fabric = FabricLoader.getInstance
 val isDev = fabric.isDevelopmentEnvironment
@@ -254,7 +245,6 @@
 package mixin:
   import net.minecraft.block.Block
   import net.minecraft.item.Item
-  import org.spongepowered.asm.mixin.injection.{At, Inject}
   import org.spongepowered.asm.mixin.Mixin
   @Mixin(value = Array(classOf[Item], classOf[Block]))
   private[phlib] class AllocationTrackerMixin() extends AnyRef with AllocationTracked:
```diff diff --git a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json index e964caa72d..9c26e2152e 100644 --- a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json +++ b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/appendix.json @@ -22,11 +22,11 @@ }, { "type": "hexcasting:pattern", - "op_id": "hexic:dye_offhand", - "anchor": "hexic:dye_offhand", + "op_id": "hexic:dye_offpaw", + "anchor": "hexic:dye_offpaw", "input": "pigment", "output": "", - "text": "book.hexic.page.dye_offhand" + "text": "book.hexic.page.dye_offpaw" }, { "type": "hexcasting:pattern", diff --git a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json index 1b7f69c24a..e64009048c 100644 --- a/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json +++ b/doc/resources/assets/hexcasting/patchouli_books/thehexbook/zh_cn/entries/addon/hexic/appendix.json @@ -22,11 +22,11 @@ }, { "type": "hexcasting:pattern", - "op_id": "hexic:dye_offhand", - "anchor": "hexic:dye_offhand", + "op_id": "hexic:dye_offpaw", + "anchor": "hexic:dye_offpaw", "input": "pigment", "output": "", - "text": "book.hexic.page.dye_offhand" + "text": "book.hexic.page.dye_offpaw" }, { "type": "hexcasting:pattern", diff --git a/project/hexic/changelog b/project/hexic/changelog index dafa529e8e..6e66aa454c 100644 --- a/project/hexic/changelog +++ b/project/hexic/changelog @@ -31,5 +31,16 @@ 2.0.0 rename media bundles to casting pouches 2.0.0 sent Stickia to the milk dimension 2.0.0 textures now use JPEG XL +2.1.0 added -Dhexic.max_stack_size to cap itemstack size at deserialization-time (default: max integer) 2.1.0 added equipment macros -2.1.0 fix hitbox for void blocks +2.1.0 demiplane spells' docs have been changed again +2.1.0 dual's reflection only considers players in ambit +2.1.0 hitbox for void blocks is no longer weirdly offset +2.1.0 item/fluid concept displays no longer suck +2.1.0 mediaweave can now actually be erased, sorry +2.1.0 mediaweave can now be tied +2.1.0 negative item stacks are now disabled by default, they can be reenabled by setting -Dhexic.min_stack_size to your favorite value +2.1.0 read-only properties can no longer be converted to access iotas +2.1.0 Refinement Distillation now properly drops input iotas on first loop as it should +2.1.0 translations have been updated [@chuijk] +2.1.0 wool and carpet edification are now actually somewhat balanced wrt each other diff --git a/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala b/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala index 5b2c0d801d..0908969192 100644 --- a/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala +++ b/project/hexic/src/client/scala/org/eu/net/pool/hexic/client.scala @@ -390,10 +390,12 @@ "attachworld" -> "Bind Demiplane", "blind" -> "Hidden Sun's Nadir", "collar" -> "Tie Mediaweave", + "conceptavailable" -> "Debit Purification", + "conceptremaining" -> "Credit Purification", "decollar" -> "Untie Mediaweave", "deleteworld" -> "Shatter Demiplane", "drop" -> "Rejection Distillation", - "dye_offhand" -> "Apply Pigment", + "dye_offpaw" -> "Apply Pigment", "erase" -> "Erase Block", "extract" -> "Excisor's Gambit", "findview" -> "Reflection Purification", @@ -453,7 +455,7 @@ case p: PigmentItem => gen.add("item.hexic.stringworm." + p.getTranslationKey, "Shimmering " + hexLang(p.getTranslationKey).replace("Pigment", "Stringworm")) case e => println(e) for page -> text <- Vector( - "dye_offhand" -> "Imbues the item held in my offhand (e.g. a $(l:items/hexcasting)$(item)casting item/$) with the given pigment.", + "dye_offpaw" -> "Imbues the item held in my offhand (e.g. a $(l:items/hexcasting)$(item)casting item/$) with the given pigment.", "erase" -> "Erases the _Hex or iota contained within a dropped item or block. Costs one dust per item.", "get_other_caster" -> "Adds the closest sentient being, excluding me, to the stack.", "modulo" -> "Similar to Modulus, but differs for negative numbers: -8 %%₁ 3 = -2, but -8 %%₂ 3 = 1.", diff --git a/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json b/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json index 73cde66b4b..4df36a4627 100644 --- a/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json +++ b/project/hexic/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/addon/hexic/world.json @@ -4,14 +4,14 @@ "category": "hexcasting:patterns", "icon": "minecraft:white_carpet", "pages": [ - "the world under my control nature is mine na$(bold)ture is MI/$NE the world $(underline)the world NO LONGER/$ will $(bold)the OVerworld rule me/$ My $(media)mind is going/$ My $(media)mind/$ is going $(o)THE PAIN OF THOUGHT/$ my mind my $(o)mind/$ my a nine by nine room to myself SOLELY MYE$(bold)LF NO ONE ELSE/$ a $(bold)burst/$ of _media to Shatter the $(media)world/$ nearly $(media)six` allays $(bold)sewn/$ into $(underline)the walls/$ for eternity oh how it must hurt $(bold)IT HURTS IT/$ $(k)TORTUES/$", + "the world under my control nature is mine na$(bold)ture is MI/$NE the world $(underline)the world NO LONGER/$ will $(bold)the OVerworld rule me/$ My $(media)mind is going/$ My $(media)mind/$ is going $(o)THE PAIN OF THOUGHT/$ my mind my $(o)mind/$ my a nine by nine room to myself SOLELY MYE$(bold)LF NO ONE ELSE/$ a $(bold)burst/$ of _media to Shatter the $(media)world/$ nearly $(media)six allays $(bold)sewn/$ into $(underline)the walls/$ for eternity oh how it must hurt $(bold)IT HURTS IT/$ $(k)TORTUES/$", { "type": "hexcasting:pattern", "op_id": "hexic:makeworld", "anchor": "hexic:makeworld", "input": "", "output": "imprint", - "text": "Creates a fresh cuboid with a 9x9x9 interior, as well as a dimension to hold it in. Costs 18.2 thousand dust." + "text": "Creates a fresh cuboid with a 9x9x9 interior, as well as a dimension to hold it in. Costs six quenched allays (720 dust)." }, "fragments of space the $(media)world/$ falling apart crumpling a $(o)fine powder/$ to the _media tie my plane TIE IT DOWN WELL bindings of $(media)thought/$ to keep it safe safe from others safe from $(media)me/$ only $(bold)a sliver of an allay's mind for the price/$ eternally trapped n$(underline)ot alive not dead mer/$ely floating Form the $(media)allay into bindings f/$rom some point outside must $(underline)hurry/$ now $(o)I feel it slipping away/$ $(bold)the cost of tying it to itself $(o)disasterous/$ the plane slipping away $(media)my/$ mind slipping away", { @@ -20,7 +20,7 @@ "anchor": "hexic:attachworld", "input": "imprint, vec", "output": "", - "text": "Binds the given demiplane to a position. This position is used when exiting the demiplane, as well as in case of any $(o)unfortunate accidents/$. Mishaps if I bind a demiplane to the plane I'm in." + "text": "Binds the given demiplane to a position in my current dimension (which must not be the demiplane itself). This position is used when exiting the demiplane, as well as in case of any $(o)unfortunate accidents/$. Costs one shard." }, "My mind is drifting drifting $(o)spinning/$, $(o)running/$ from me with every slice I take of Nature. Every passing moment my grip oh my hands weakening my mind passing through like sand$(2br)I must steady myself. The price of sanity is outright shattering the planes I've made — a burst of media worth 25 shards, and the pocket will crumple like a villager, spewing its contents into where it was bound.$(2br)Testing this process on living creatures is unwise.", { @@ -29,7 +29,7 @@ "anchor": "hexic:deleteworld", "input": "imprint, vec", "output": "", - "text": "Ruptures the boundaries of the given demiplane, destroying its contents. All dropped items and experience are spewed at the plane's attachment point." + "text": "Ruptures the boundaries of the given demiplane, destroying its contents. All dropped items and experience are spewed at the plane's attachment point. Costs five shards." } ] } diff --git a/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch b/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch index 9facfb0031..44ac1dc795 100644 --- a/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch +++ b/project/hexic/src/main/resources/assets/hexic/jsonpatch/pigments.jsonpatch @@ -3,9 +3,9 @@ $pages = arrays.push($pages, { type: "hexcasting:pattern", - op_id: "hexic:dye_offhand", - anchor: "hexic:dye_offhand", + op_id: "hexic:dye_offpaw", + anchor: "hexic:dye_offpaw", input: "pigment", output: "", - text: "book.hexic.page.dye_offhand" + text: "book.hexic.page.dye_offpaw" }); \ No newline at end of file diff --git a/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json b/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json index 8e105e5a89..759f98e161 100644 --- a/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json +++ b/project/hexic/src/main/resources/assets/hexic/lang/zh_cn.json @@ -1,5 +1,5 @@ { - "book.hexic.page.dye_offhand": "将所给染色剂内化到我副手中的物品(如$(l:items/hexcasting)$(item)施法物品/$)里。", + "book.hexic.page.dye_offpaw": "将所给染色剂内化到我副手中的物品(如$(l:items/hexcasting)$(item)施法物品/$)里。", "book.hexic.page.erase": "清除物品实体或方块中的$(hex)咒术/$或 iota。每个物品消耗 1 个紫水晶粉。", "book.hexic.page.get_other_caster": "将离我最近的有智慧存在压入栈,我自己不计入统计范围。", "book.hexic.page.modulo": "与余数之馏化类似,但两者在负数上的表现不同:-8 %%₁ 3 = -2,而 -8 %%₂ 3 = 1。", @@ -8,7 +8,7 @@ "hexcasting.action.hexic:blind": "隐阳西沉", "hexcasting.action.hexic:deleteworld": "击碎半位面", "hexcasting.action.hexic:drop": "拒斥之馏化", - "hexcasting.action.hexic:dye_offhand": "应用染色剂", + "hexcasting.action.hexic:dye_offpaw": "应用染色剂", "hexcasting.action.hexic:erase": "清除方块", "hexcasting.action.hexic:extract": "切除器之策略", "hexcasting.action.hexic:findview": "精思之纯化", diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala b/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala index b37ee240e5..bf6ff8347e 100644 --- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala +++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/main.scala @@ -14,7 +14,7 @@ import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, CastingEnvironmentComponent, MishapEnvironment, OperationResult, ResolvedPattern, ResolvedPatternType} import at.petrak.hexcasting.api.casting.iota.* import at.petrak.hexcasting.api.casting.math.{HexDir, HexPattern} -import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapBadOffhandItem, MishapInvalidIota, MishapInvalidOperatorArgs, MishapNotEnoughArgs, MishapOthersName, MishapTooManyCloseParens} +import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapInvalidIota, MishapInvalidOperatorArgs, MishapNotEnoughArgs, MishapOthersName, MishapTooManyCloseParens, MishapBadOffhandItem as MishapBadOffpawItem} import at.petrak.hexcasting.api.pigment.FrozenPigment import at.petrak.hexcasting.api.utils.{HexUtils, MediaHelper} import at.petrak.hexcasting.common.lib.{HexAttributes, HexItems, HexRegistries, HexSounds} @@ -73,7 +73,7 @@ import net.minecraft.text.{HoverEvent, LiteralTextContent, MutableText, Style, Text, TextColor, TextContent, Texts} import net.minecraft.util.dynamic.Codecs import net.minecraft.util.math.{BlockPointer, BlockPos, ChunkPos, Direction, Vec3d} -import net.minecraft.util.{ActionResult, Arm, ClickType, DyeColor, Formatting, Hand, Identifier, Rarity, TypedActionResult, Util, Uuids, WorldSavePath} +import net.minecraft.util.{ActionResult, Arm, ClickType, DyeColor, Formatting, Identifier, Rarity, TypedActionResult, Util, Uuids, WorldSavePath, Hand as Paw} import net.minecraft.world.biome.Biome import net.minecraft.world.{BlockView, TeleportTarget, World} import org.eu.net.pool.hexic @@ -492,18 +492,18 @@ case class Pen private [hexic] (color: DyeColor) extends Item(Item.Settings().maxCount(1)) with Registered(Registries.ITEM, s"pen/$color"): override def toString = s"$getClass(color=$color)${super[Item].toString}" - override def use(world: World, player: PlayerEntity, hand: Hand): TypedActionResult[ItemStack] = + override def use(world: World, player: PlayerEntity, paw: Paw): TypedActionResult[ItemStack] = // if player.getAttributeValue(HexAttributes.FEEBLE_MIND) > 0.0 then - // TypedActionResult.fail(player.getStackInHand(hand)) + // TypedActionResult.fail(player.getStackInHand(paw)) // else if !world.isClient && player.isInstanceOf[ServerPlayerEntity] then val serverPlayer: ServerPlayerEntity = player.asInstanceOf[ServerPlayerEntity] - val vm = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, hand) + val vm = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, paw) val patterns = IXplatAbstractions.INSTANCE.getPatternsSavedInUi(serverPlayer).asScala val descs = vm.generateDescs - IXplatAbstractions.INSTANCE.sendPacketToPlayer(serverPlayer, new MsgOpenSpellGuiS2C(hand, patterns, descs.getFirst, descs.getSecond, 0)) + IXplatAbstractions.INSTANCE.sendPacketToPlayer(serverPlayer, new MsgOpenSpellGuiS2C(paw, patterns, descs.getFirst, descs.getSecond, 0)) player.incrementStat(Stats.USED.getOrCreateStat(this)) - TypedActionResult.success(player.getStackInHand(hand)) + TypedActionResult.success(player.getStackInHand(paw)) object Pen: val instances: DyeColor :> Pen = DyeColor.values.map(c => c -> new Pen(c)).toMap @@ -518,11 +518,18 @@ case c: NbtCompound => c case _ => null override def writeable(stack: ItemStack): Boolean = true - override def canWrite(stack: ItemStack, iota: Iota): Boolean = iota match - case l: ListIota => true - case _ => iota.executable + override def canWrite(stack: ItemStack, iota: Iota): Boolean = + iota match + case null => true + case l: ListIota => true + case _ => iota.executable override def writeDatum(stack: ItemStack, iota: Iota): Unit = - stack.getOrCreateNbt.put("Hex", IotaType.serialize(iota)) + iota match + case null => + for nbt <- Option(stack.getNbt) do + nbt.remove("Hex") + if nbt.isEmpty then stack.setNbt(null) + case iota => stack.getOrCreateNbt.put("Hex", IotaType.serialize(iota)) override def appendTooltip(stack: ItemStack, world: World, tooltip: util.List[Text], context: TooltipContext): Unit = IotaHolderItem.appendHoverText(this, stack, tooltip, context) DispenserBlock.registerBehavior(this, new ItemDispenserBehavior: @@ -916,7 +923,7 @@ private val DUST_AMOUNT = new DecimalFormat("###,###.##") val wizard = Item(Item.Settings().rarity(Rarity.EPIC).maxCount(1)) -val aLotOfMedia = (200000 /* max phial size */ * 6 /* phials per small pouch */ * 4 /* small pouches per large pouch */ * (36 /* inventory slots */ + 4 /* armor slots */ + 2 /* offhands */) + 20 /* healthcasting */) * MediaConstants.DUST_UNIT +val aLotOfMedia = (200000 /* max phial size */ * 6 /* phials per small pouch */ * 4 /* small pouches per large pouch */ * (36 /* inventory slots */ + 4 /* armor slots */ + 2 /* offpaws */) + 20 /* healthcasting */) * MediaConstants.DUST_UNIT class Event[T, R](default: T => R) extends (T => R): private var current = default @@ -1108,9 +1115,9 @@ override def getCollisionShape(state: BlockState, world: BlockView, pos: BlockPos, context: ShapeContext): VoxelShape = getOutlineShape(state, world, pos, context) - override def onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult = boundary: + override def onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, paw: Paw, hit: BlockHitResult): ActionResult = boundary: lazy val entity = findEntity(world, pos).getOrElse(boundary.break(ActionResult.FAIL)) - player.getStackInHand(hand) match + player.getStackInHand(paw) match case stack@ItemStackAccess(HexItems.CHARGED_AMETHYST, _, _) if !(for i <- 0 until 14; j <- 0 until 14 yield entity.bit(i, j)).all => for i <- 0 until 14; j <- 0 until 14 do entity.bit(i, j) = true @@ -1151,12 +1158,12 @@ registerHopperEndpoint <- classNamed("org.eu.net.pool.registerHopperEndpoint") do registerHopperEndpoint.runtimeClass.newInstance().asInstanceOf[() => Unit]() - Patterns.register("dye_offhand", w"eqdeeqdweeqddqdwwdew"): + Patterns.register("dye_offpaw", w"eqdeeqdweeqddqdwwdew"): Patterns.mkAction: (img, cont) => val stack = img.getStack.asScala stack.lastOption.getOrElse(throw MishapNotEnoughArgs(1, 0)) match case p: PigmentIota => - val info = summon[CastingEnvironment].getHeldItemToOperateOn(!_.isEmpty).pipe(Option(_)).getOrElse(throw MishapBadOffhandItem(null, Text.translatable("text.hexic.pigment_holder_item"))) + val info = summon[CastingEnvironment].getHeldItemToOperateOn(!_.isEmpty).pipe(Option(_)).getOrElse(throw MishapBadOffpawItem(null, Text.translatable("text.hexic.pigment_holder_item"))) (img.withStack(_.init), cont, HexEvalSounds.SPELL, Seq: OperatorSideEffect.AttemptSpell( new RenderedSpell: @@ -1172,20 +1179,20 @@ case i => throw MishapInvalidIota.ofType(i, 0, "pigment") Patterns.register("prop_fi", sw"aawqe"): Patterns.mkConstAction(1): - case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Writer(x.getName, "head")) - case Seq(x) => throw MishapInvalidIota(x, 0, "property") + case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Writer(x.getName, "head")) + case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop") Patterns.register("prop_fo", sw"aawqd"): Patterns.mkConstAction(1): - case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Stream(x.getName, "head")) - case Seq(x) => throw MishapInvalidIota(x, 0, "property") + case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Stream(x.getName, "head")) + case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop") Patterns.register("prop_li", sw"aawdwq"): Patterns.mkConstAction(1): - case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Writer(x.getName, "tail")) - case Seq(x) => throw MishapInvalidIota(x, 0, "property") + case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Writer(x.getName, "tail")) + case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop") Patterns.register("prop_lo", sw"aawdwa"): Patterns.mkConstAction(1): - case Seq(x: PropertyIota) => Seq(PropertyAccessIota.Stream(x.getName, "tail")) - case Seq(x) => throw MishapInvalidIota(x, 0, "property") + case Seq(x: PropertyIota) if !x.getReadonly => Seq(PropertyAccessIota.Stream(x.getName, "tail")) + case Seq(x) => throw MishapInvalidIota(x, 0, "writeable_prop") Patterns.register("where", nw"qaeaqwdd"): Patterns.mkConstAction(1): i => val Seq(x) = i @@ -1466,7 +1473,7 @@ override def cast(env: CastingEnvironment): Unit = world.parentInfo = Some(env.getWorld.getRegistryKey, pos) override def cast(env: CastingEnvironment, image: CastingImage): CastingImage = { cast(env); image }, - MediaConstants.SHARD_UNIT * 3, + MediaConstants.SHARD_UNIT, Seq(), 1 ) @@ -1592,7 +1599,7 @@ summon[CastingEnvironment].getCastingEntity match case caster: ServerPlayerEntity => val staffcast = HexCardinalComponents.STAFFCAST_IMAGE.get(caster) - val oldImage = staffcast.getVM(Hand.MAIN_HAND).getImage + val oldImage = staffcast.getVM(Paw.MAIN_HAND).getImage staffcast.setImage(img) val vm = staffcast.getVM(summon[CastingEnvironment].getCastingHand) try @@ -1659,7 +1666,7 @@ others = others.filter: case _: EntityPlayerMPFake => false case _ => true - val sorted = others.toSeq.sortBy(_.getPos.squaredDistanceTo(summon[CastingEnvironment].mishapSprayPos)) + val sorted = others.toSeq.sortBy(_.getPos.squaredDistanceTo(summon[CastingEnvironment].mishapSprayPos)).filter(summon[CastingEnvironment].isEntityInRange(_, true)) sorted.headOption.fold(NullIota())(EntityIota(_)) Patterns.register("blind", se"qqqqqadwawawd")(OpPotionEffect(StatusEffects.BLINDNESS, 1000, false, false)) Patterns.register("erase", e"wqwdwqwawwwwwawwwww"): diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java index 3ebbe0c9cd..4189c5d923 100644 --- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java +++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemMixin.java @@ -3,7 +3,6 @@ import at.petrak.hexcasting.api.casting.eval.vm.CastingVM; import at.petrak.hexcasting.api.casting.iota.GarbageIota; import at.petrak.hexcasting.api.casting.iota.IotaType; -import at.petrak.hexcasting.api.casting.iota.ListIota; import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.client.item.TooltipContext; import net.minecraft.entity.player.PlayerEntity; @@ -14,15 +13,12 @@ import net.minecraft.nbt.NbtList; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.text.TranslatableTextContent; import net.minecraft.util.Hand; import net.minecraft.util.TypedActionResult; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; 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; @@ -45,14 +41,14 @@ } @Inject(method = "use", at = @At("HEAD"), cancellable = true) - void use(World world, PlayerEntity user, Hand hand, CallbackInfoReturnable<TypedActionResult<ItemStack>> cir) { + void use(World world, PlayerEntity user, Hand paw, CallbackInfoReturnable<TypedActionResult<ItemStack>> cir) { if ((Object) this != ECHO_SHARD) return; - ItemStack stack = user.getStackInHand(hand); + ItemStack stack = user.getStackInHand(paw); NbtCompound nbt = stack.getNbt(); if (nbt == null) return; NbtList patterns = nbt.getList("hexic:memory", NbtElement.COMPOUND_TYPE); if (patterns.isEmpty() || world.isClient || !(world instanceof ServerWorld serverWorld && user instanceof ServerPlayerEntity serverPlayer)) return; - CastingVM staffcast = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, hand); + CastingVM staffcast = IXplatAbstractions.INSTANCE.getStaffcastVM(serverPlayer, paw); stack.decrement(1); NbtCompound newNbt = nbt.copy(); newNbt.remove("hexic:memory"); diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java index c8633b5865..53568ebe3e 100644 --- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java +++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/ItemStackMixin.java @@ -5,11 +5,13 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; +import org.eu.net.pool.hexic.cfg; 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 scala.util.CommandLineParser; @Mixin(ItemStack.class) public class ItemStackMixin { @@ -20,6 +22,10 @@ if (nbt.contains("Count", NbtElement.INT_TYPE)) { count = nbt.getInt("Count"); } + int minSize = cfg.apply("hexic.min_stack_size", Integer::parseInt).getOrElse(() -> 0); + int maxSize = cfg.apply("hexic.max_stack_size", Integer::parseInt).getOrElse(() -> Integer.MAX_VALUE); + if (count < minSize) count = minSize; + if (count > maxSize) count = maxSize; } @WrapOperation(method = {"writeNbt", "method_7953"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NbtCompound;putByte(Ljava/lang/String;B)V")) diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java index 0e4e0babec..2323fd23c3 100644 --- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java +++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/OpEdifySaplingMixin.java @@ -41,13 +41,13 @@ return true; } if (original.call(instance, BlockTags.WOOL)) { + mediaweave.set(2); + return true; + } + if (original.call(instance, BlockTags.WOOL_CARPETS)) { mediaweave.set(3); return true; } - if (original.call(instance, BlockTags.WOOL_CARPETS)) { - mediaweave.set(2); - return true; - } if (instance.isOf(Blocks.TRIPWIRE)) { mediaweave.set(-1); return true; diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java index 47a562d537..f0263f8703 100644 --- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java +++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/mixin/StaffCastEnvMixin.java @@ -62,9 +62,9 @@ return; } // TODO: consider whether shards should intercept pen patterns - ItemStack offhandStack = sender.getStackInHand(vm.getEnv().getOtherHand()); - if (offhandStack.isOf(ECHO_SHARD)) { - NbtCompound tag = offhandStack.getOrCreateNbt(); + ItemStack offpawStack = sender.getStackInHand(vm.getEnv().getOtherHand()); + if (offpawStack.isOf(ECHO_SHARD)) { + NbtCompound tag = offpawStack.getOrCreateNbt(); NbtList queuedPatterns = tag.getList("hexic:memory", NbtElement.COMPOUND_TYPE); queuedPatterns.add(IotaType.serialize(new PatternIota(msg.pattern()))); tag.put("hexic:memory", queuedPatterns); diff --git a/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala b/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala index 5596117816..63f4ecadf0 100644 --- a/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala +++ b/project/hexic/src/main/scala/org/eu/net/pool/hexic/views.scala @@ -35,6 +35,8 @@ import net.minecraft.world.{BlockView, TeleportTarget, World} import org.eu.net.pool.phlib.{*, given} import org.slf4j.{Logger, LoggerFactory} +import ram.talia.hexal.api.casting.iota.MoteIota +import ram.talia.hexal.api.mediafieditems.MediafiedItemManager import ram.talia.moreiotas.api.casting.iota.{ItemStackIota, ItemTypeIota} import java.util.UUID @@ -88,6 +90,7 @@ override def isTruthy = views ∃(_.isTruthy) override def asText = views match case Seq() => "∅" + case h +: t => (Text.empty().append(h.asText) /: t) (_ `append` "+" `append` _.asText) override def serialize = val c = NbtCompound() val list = NbtList() @@ -131,7 +134,9 @@ view <- InventoryView.deserialize(c) yield view)*)) private given typeOfEntity: InventoryView.Type[OfEntity]: - override def deserialize(data: NbtCompound)(using ServerWorld): Option[OfEntity] = ??? + override def deserialize(data: NbtCompound)(using world: ServerWorld): Option[OfEntity] = + given MinecraftServer = world.getServer + Some(OfEntity(UUID(data.getLong("m"), data.getLong("l")))) private given typeOfBlock: InventoryView.Type[OfBlock]: override def deserialize(data: NbtCompound)(using ServerWorld): Option[OfBlock] = for @@ -302,6 +307,26 @@ setConceptScale[FluidVariant](81000) setConceptScale[SingletonVariant.media.type](10000) setConceptScale[SingletonVariant.heat.type](20) + Patterns.register("conceptavailable", sw"wedwqwdewwaqaa"): + Patterns.mkConstAction(2): + case Seq(BoxedView.Instance(target), VariantIota(typ, _)) => + Using.resource(Transaction.openOuter()): + case tx@given Transaction => + val amt = target.tryExtract(typ, Long.MaxValue) / conceptScale(ClassTag(typ.getClass)) + tx.abort() + Seq(DoubleIota(amt)) + case Seq(_: BoxedView.Instance, perp) => throw MishapInvalidIota(perp, 0, VariantIota.typeName) + case Seq(perp, _) => throw MishapInvalidIota(perp, 1, BoxedView.typeName) + Patterns.register("conceptremaining", sw"wedwqwdewadedd"): + Patterns.mkConstAction(2): + case Seq(BoxedView.Instance(target), VariantIota(typ, _)) => + Using.resource(Transaction.openOuter()): + case tx@given Transaction => + val amt = target.tryInsert(typ, Long.MaxValue) / conceptScale(ClassTag(typ.getClass)) + tx.abort() + Seq(DoubleIota(amt)) + case Seq(_: BoxedView.Instance, perp) => throw MishapInvalidIota(perp, 0, VariantIota.typeName) + case Seq(perp, _) => throw MishapInvalidIota(perp, 1, BoxedView.typeName) Patterns.register("moveconcept", se"wawdwawqdewewedqwawdwaw"): Patterns.mkConstAction(4): case Seq(isIota[BoxedView.Instance, 3](BoxedView.Instance(from)), isIota[BoxedView.Instance, 2](BoxedView.Instance(into)), typ: VariantIota[?], isIota[DoubleIota, 0](count)) => @@ -366,6 +391,12 @@ case s: ItemEntity => Seq(if s.getStack.getItem == Items.AIR then NullIota() else VariantIota(ItemVariant.of(s.getStack), RegistryKey.of(VariantIota.key, Identifier("item")))) case s: ItemFrameEntity => Seq(if s.getHeldItemStack.getItem == Items.AIR then NullIota() else VariantIota(ItemVariant.of(s.getHeldItemStack), RegistryKey.of(VariantIota.key, Identifier("item")))) case _ => dieOfBadType() + case m: MoteIota if MediafiedItemManager.contains(m.getItemIndex) => + Seq( + if m.getItem == Items.AIR then + NullIota() + else + VariantIota(ItemVariant.of(m.getItem, m.getTag), RegistryKey.of(VariantIota.key, Identifier("item")))) case _ => dieOfBadType() //noinspection UnstableApiUsage case class VariantIota[T: ClassTag](data: TransferVariant[T], key: RegistryKey[VariantIota.Reader]) extends Iota(VariantIota, data): @@ -426,6 +457,11 @@ type T = SingletonVariant def variant = SingletonVariant.media def display: Text = Text.literal("Media").styled(_.withColor(0x74b3f2))) + registry("heat") = c => + Some(new TaggedVariant: + type T = SingletonVariant + def variant = SingletonVariant.heat + def display: Text = Text.literal("Heat").styled(_.withColor(0xe08355))) //noinspection UnstableApiUsage class SingletonVariant extends TransferVariant[SingletonVariant]: diff --git a/settings.gradle.kts b/settings.gradle.kts index f959142aa5..c876aad35c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -22,6 +22,8 @@ id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } +rootProject.name = "hex-addons" + include("util") includeBuild("plugin") for (mod in listOf("hexic", "iotaworks", "hexxytounge")) { diff --git a/util/src/main/scala/org/eu/net/pool/phlib/main.scala b/util/src/main/scala/org/eu/net/pool/phlib/main.scala index 1ec2991e8d..6ba3456877 100644 --- a/util/src/main/scala/org/eu/net/pool/phlib/main.scala +++ b/util/src/main/scala/org/eu/net/pool/phlib/main.scala @@ -1,56 +1,47 @@ package org.eu.net.pool package phlib -import at.petrak.hexcasting.api.utils.HexUtils -import com.google.gson.JsonElement -import com.mojang.serialization.{Codec, DynamicOps, JsonOps} -import net.minecraft.nbt.{NbtByte, NbtByteArray, NbtDouble, NbtEnd, NbtFloat, NbtInt, NbtIntArray, NbtList, NbtLong, NbtLongArray, NbtOps, NbtShort, NbtString, NbtType} -import net.minecraft.util.dynamic.Codecs -import at.petrak.hexcasting.api.addldata.ADMediaHolder -import scala.collection.{IterableOnceOps, IterableOps} -import at.petrak.hexcasting.api.casting.{ActionRegistryEntry, ParticleSpray, RenderedSpell, SpellList} -import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic -import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator -import at.petrak.hexcasting.api.casting.castables.{Action, ConstMediaAction, OperationAction, SpecialHandler, SpellAction} -import at.petrak.hexcasting.api.casting.eval.env.PlayerBasedCastEnv -import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect.DoMishap +import at.petrak.hexcasting.api.casting.ActionRegistryEntry +import at.petrak.hexcasting.api.casting.castables.{Action, ConstMediaAction, OperationAction} import at.petrak.hexcasting.api.casting.eval.sideeffects.{EvalSound, OperatorSideEffect} -import at.petrak.hexcasting.api.casting.eval.vm.{CastingImage, CastingVM, ContinuationFrame, FrameEvaluate, SpellContinuation} -import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, CastingEnvironmentComponent, MishapEnvironment, OperationResult, ResolvedPattern, ResolvedPatternType} +import at.petrak.hexcasting.api.casting.eval.vm.{CastingImage, CastingVM, SpellContinuation} +import at.petrak.hexcasting.api.casting.eval.{CastResult, CastingEnvironment, CastingEnvironmentComponent, OperationResult} import at.petrak.hexcasting.api.casting.iota.* import at.petrak.hexcasting.api.casting.math.{HexDir, HexPattern} -import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapBadCaster, MishapBadOffhandItem, MishapInvalidIota, MishapInvalidOperatorArgs, MishapNotEnoughArgs, MishapOthersName, MishapTooManyCloseParens} +import at.petrak.hexcasting.api.casting.mishaps.{Mishap, MishapInvalidIota, MishapNotEnoughArgs} +import at.petrak.hexcasting.api.utils.HexUtils import at.petrak.hexcasting.common.lib.HexRegistries import at.petrak.hexcasting.fabric.cc.HexCardinalComponents +import com.google.gson.JsonElement import com.mojang.brigadier.builder.{LiteralArgumentBuilder, RequiredArgumentBuilder} +import com.mojang.serialization.{Codec, DynamicOps, JsonOps} import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback +import net.minecraft.command.argument.{EntityArgumentType, NbtElementArgumentType, RegistryEntryArgumentType} import net.minecraft.command.{CommandException, EntitySelector} -import net.minecraft.command.argument.{EntityArgumentType, NbtElementArgumentType, RegistryEntryArgumentType} -import net.minecraft.nbt.{NbtCompound, NbtElement} +import net.minecraft.nbt.* import net.minecraft.server.command.ServerCommandSource import net.minecraft.server.network.ServerPlayerEntity import net.minecraft.server.world.ServerWorld import net.minecraft.util.Hand +import net.minecraft.util.dynamic.Codecs import scala.annotation.tailrec +import scala.collection.{IterableOnceOps, IterableOps} import scala.math.Ordered.orderingToOrdered import scala.reflect.ClassTag import scala.util.{Failure, Success, Try} export scala.collection.convert.ImplicitConversions.* export scala.util.chaining._ -import java.util +import at.petrak.hexcasting.xplat.IXplatAbstractions +import net.fabricmc.fabric.api.event.{Event, EventFactory} import net.fabricmc.loader.api.FabricLoader +import net.minecraft.registry.{Registry, RegistryKey} +import net.minecraft.text.{MutableText, Text} import net.minecraft.util.Identifier +import org.slf4j.{Logger, LoggerFactory} + +import java.util import scala.util.boundary -import org.slf4j.LoggerFactory -import org.slf4j.Logger -import at.petrak.hexcasting.xplat.IXplatAbstractions -import net.minecraft.registry.Registry -import net.minecraft.registry.RegistryKey -import net.minecraft.text.MutableText -import net.minecraft.text.Text -import net.fabricmc.fabric.api.event.Event -import net.fabricmc.fabric.api.event.EventFactory val fabric = FabricLoader.getInstance val isDev = fabric.isDevelopmentEnvironment @@ -254,7 +245,6 @@ package mixin: import net.minecraft.block.Block import net.minecraft.item.Item - import org.spongepowered.asm.mixin.injection.{At, Inject} import org.spongepowered.asm.mixin.Mixin @Mixin(value = Array(classOf[Item], classOf[Block])) private[phlib] class AllocationTrackerMixin() extends AnyRef with AllocationTracked: ```
poolcritter force-pushed push-qprrktmrmnup from bb2f6cc16a to 067d408682 2026-04-17 01:02:01 -04:00 Compare
poolcritter changed title from hexic 2.1.0+6afea87f [kwlznnky] to WIP: hexic 2.1.0+6afea87f [kwlznnky] 2026-04-17 01:09:32 -04:00
This pull request is marked as a work in progress.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u push-qprrktmrmnup:poolcritter-push-qprrktmrmnup
git switch poolcritter-push-qprrktmrmnup

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff poolcritter-push-qprrktmrmnup
git switch poolcritter-push-qprrktmrmnup
git rebase main
git switch main
git merge --ff-only poolcritter-push-qprrktmrmnup
git switch poolcritter-push-qprrktmrmnup
git rebase main
git switch main
git merge --no-ff poolcritter-push-qprrktmrmnup
git switch main
git merge --squash poolcritter-push-qprrktmrmnup
git switch main
git merge --ff-only poolcritter-push-qprrktmrmnup
git switch main
git merge poolcritter-push-qprrktmrmnup
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
teal-wolf-25/Hexwoven!5
No description provided.