From b5dc2499f28aeea45e31c7da6d0c66f131bb896e Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:26:51 -0400 Subject: [PATCH 1/8] Implement seven-field streamcodec --- .../petrak/hexcasting/api/utils/HexUtils.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt index 061ae2793..715e16b5e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt @@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.casting.iota.NullIota import at.petrak.hexcasting.api.casting.math.HexCoord import at.petrak.hexcasting.api.casting.validateSubIotas import at.petrak.hexcasting.api.mod.HexTags +import com.mojang.datafixers.util.Function6 import net.minecraft.ChatFormatting import net.minecraft.core.HolderLookup import net.minecraft.core.Registry @@ -16,6 +17,7 @@ import net.minecraft.nbt.* import net.minecraft.network.chat.Component import net.minecraft.network.chat.MutableComponent import net.minecraft.network.chat.Style +import net.minecraft.network.codec.StreamCodec import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerLevel @@ -28,6 +30,7 @@ import net.minecraft.world.phys.Vec2 import net.minecraft.world.phys.Vec3 import java.lang.ref.WeakReference import java.util.* +import java.util.function.Function import kotlin.math.absoluteValue import kotlin.math.max import kotlin.math.min @@ -330,3 +333,38 @@ fun validateIotaList(iotaList: List, serverLevel: ServerLevel): Li return iotaList.map { validateIota(it, serverLevel) } } + +// vanilla's StreamCodec.composite() only supports up to six fields in 1.21 +fun compositeCodecSeven( + streamCodec1: StreamCodec, function1: Function, + streamCodec2: StreamCodec, function2: Function, + streamCodec3: StreamCodec, function3: Function, + streamCodec4: StreamCodec, function4: Function, + streamCodec5: StreamCodec, function5: Function, + streamCodec6: StreamCodec, function6: Function, + streamCodec7: StreamCodec, function7: Function, + createFunction: Function7 +): StreamCodec { + return object : StreamCodec { + override fun decode(stream: B): C { + val field1 = streamCodec1.decode(stream) + val field2 = streamCodec2.decode(stream) + val field3 = streamCodec3.decode(stream) + val field4 = streamCodec4.decode(stream) + val field5 = streamCodec5.decode(stream) + val field6 = streamCodec6.decode(stream) + val field7 = streamCodec7.decode(stream) + return createFunction.invoke(field1, field2, field3, field4, field5, field6, field7) + } + + override fun encode(stream: B, obj: C) { + streamCodec1.encode(stream, function1.apply(obj)) + streamCodec2.encode(stream, function2.apply(obj)) + streamCodec3.encode(stream, function3.apply(obj)) + streamCodec4.encode(stream, function4.apply(obj)) + streamCodec5.encode(stream, function5.apply(obj)) + streamCodec6.encode(stream, function6.apply(obj)) + streamCodec7.encode(stream, function7.apply(obj)) + } + } +} From 5b6438d0ac4fdbfe1e4147e5cbafd4730a54ade5 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:27:10 -0400 Subject: [PATCH 2/8] Internal setup for mishap detection --- .../api/casting/eval/vm/CastingImage.kt | 16 ++++++++------ .../api/casting/eval/vm/CastingVM.kt | 21 +++++++++++++++++-- .../directrix/BlockBooleanDirectrix.java | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt index c8658157f..627eed736 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.IotaType import at.petrak.hexcasting.api.utils.getOrCreateCompound import at.petrak.hexcasting.api.utils.putCompound +import at.petrak.hexcasting.api.utils.compositeCodecSeven import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.nbt.CompoundTag @@ -22,10 +23,11 @@ data class CastingImage( val parenCount: Int, val parenthesized: List, val escapeNext: Boolean, + val simulateNext: Boolean, val opsConsumed: Long, val userData: CompoundTag ) { - constructor() : this(listOf(), 0, listOf(), false, 0, CompoundTag()) + constructor() : this(listOf(), 0, listOf(), false, false, 0, CompoundTag()) /** * `escaped` is used by [OpUndo][at.petrak.hexcasting.common.casting.actions.escaping.OpUndo] to determine whether the paren count @@ -95,22 +97,24 @@ data class CastingImage( Codec.INT.fieldOf("open_parens").forGetter { it.parenCount }, ParenthesizedIota.CODEC.listOf().fieldOf("parenthesized").forGetter { it.parenthesized }, Codec.BOOL.fieldOf("escape_next").forGetter { it.escapeNext }, + Codec.BOOL.fieldOf("catch_mishap").forGetter { it.simulateNext }, Codec.LONG.fieldOf("ops_consumed").forGetter { it.opsConsumed }, CompoundTag.CODEC.fieldOf("userData").forGetter { it.userData } - ).apply(inst) { a, b, c, d, e, f -> - CastingImage(a, b, c, d, e, f) + ).apply(inst) { a, b, c, d, e, f, g -> + CastingImage(a, b, c, d, e, f, g) } }.orElseGet(::CastingImage) @JvmStatic - val STREAM_CODEC = StreamCodec.composite( + val STREAM_CODEC = compositeCodecSeven( IotaType.TYPED_STREAM_CODEC.apply(ByteBufCodecs.list()), CastingImage::stack, ByteBufCodecs.VAR_INT, CastingImage::parenCount, ParenthesizedIota.STREAM_CODEC.apply(ByteBufCodecs.list()), CastingImage::parenthesized, ByteBufCodecs.BOOL, CastingImage::escapeNext, + ByteBufCodecs.BOOL, CastingImage::simulateNext, ByteBufCodecs.VAR_LONG, CastingImage::opsConsumed, ByteBufCodecs.COMPOUND_TAG, { it.userData }, - { a, b, c, d, e, f -> - CastingImage(a, b, c, d, e, f) + { a, b, c, d, e, f, g -> + CastingImage(a, b, c, d, e, f, g) } ) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index ca1962531..6ee58b522 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.SpellList import at.petrak.hexcasting.api.casting.eval.* import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect import at.petrak.hexcasting.api.casting.eval.vm.CastingImage.ParenthesizedIota +import at.petrak.hexcasting.api.casting.iota.BooleanIota import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.IotaType import at.petrak.hexcasting.api.casting.iota.ListIota @@ -150,12 +151,28 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.ESCAPED, HexEvalSounds.NORMAL_EXECUTE) } + var result: CastResult if (this.image.parenCount > 0) { // Handle parens escaping - return iota.executeInParens(this, world, continuation) + result = iota.executeInParens(this, world, continuation) } else { // Handle normal execution behavior - return iota.execute(this, world, continuation) + result = iota.execute(this, world, continuation) + } + + if (this.image.simulateNext) { + // push a bool based on whether the cast would have succeeded; do not perform any side effects from the cast + val success = result.sideEffects.none { it is OperatorSideEffect.DoMishap } + val newStack = this.image.stack.toMutableList() + newStack.add(BooleanIota(success)) + val newImage = this.image.copy( + stack = newStack, + simulateNext = false + ) + return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.EVALUATED, HexEvalSounds.NORMAL_EXECUTE) + } else { + // return a standard CastResult that does include the side effects from the cast + return result } } catch (exception: Exception) { // This means something very bad has happened diff --git a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/directrix/BlockBooleanDirectrix.java b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/directrix/BlockBooleanDirectrix.java index c72555282..76f2971f1 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/directrix/BlockBooleanDirectrix.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/blocks/circles/directrix/BlockBooleanDirectrix.java @@ -62,7 +62,7 @@ public ControlFlow acceptControlFlow(CastingImage imageIn, CircleCastEnv env, Di ? bs.getValue(FACING).getOpposite() : bs.getValue(FACING); var imageOut = imageIn.copy(stack, imageIn.getParenCount(), imageIn.getParenthesized(), - imageIn.getEscapeNext(), imageIn.getOpsConsumed(), imageIn.getUserData()); + imageIn.getEscapeNext(), imageIn.getSimulateNext(), imageIn.getOpsConsumed(), imageIn.getUserData()); return new ControlFlow.Continue(imageOut, List.of(this.exitPositionFromDirection(pos, outputDir))); } From 8823f66122d07a9db6f48b2aebdd05f38e6ae51c Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 19:04:41 -0400 Subject: [PATCH 3/8] Mishap detection pattern --- .../casting/actions/escaping/OpSimulate.kt | 17 ++++++++++++++++ .../hexcasting/common/lib/hex/HexActions.java | 3 +++ .../hexcasting/lang/en_us.flatten.json5 | 10 +++++++++- .../entries/patterns/mishap_avoidance.json | 20 +++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 Common/src/main/java/at/petrak/hexcasting/common/casting/actions/escaping/OpSimulate.kt create mode 100644 Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/mishap_avoidance.json diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/escaping/OpSimulate.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/escaping/OpSimulate.kt new file mode 100644 index 000000000..270b20620 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/escaping/OpSimulate.kt @@ -0,0 +1,17 @@ +package at.petrak.hexcasting.common.casting.actions.escaping + +import at.petrak.hexcasting.api.casting.castables.Action +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.eval.OperationResult +import at.petrak.hexcasting.api.casting.eval.vm.CastingImage +import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation +import at.petrak.hexcasting.common.lib.hex.HexEvalSounds + +object OpSimulate : Action { + override fun operate(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation): OperationResult { + val image2 = image.copy( + simulateNext = true + ) + return OperationResult(image2, listOf(), continuation, HexEvalSounds.NORMAL_EXECUTE) + } +} \ No newline at end of file diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java index eb049a8e7..21a1e6971 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java @@ -397,6 +397,9 @@ public class HexActions { public static final ActionRegistryEntry UNDO = make("undo", new ActionRegistryEntry(HexPattern.fromAngles("eeedw", HexDir.EAST), OpUndo.INSTANCE)); + public static final ActionRegistryEntry SIMULATE = make("simulate", + new ActionRegistryEntry(HexPattern.fromAngles("deaq", HexDir.EAST), OpSimulate.INSTANCE)); + // http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf // eval being a space filling curve feels apt doesn't it public static final ActionRegistryEntry EVAL = make("eval", diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index 528f82646..dcfcd7de7 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -918,6 +918,8 @@ open_paren: "Introspection", close_paren: "Retrospection", undo: "Evanition", + + simulate: "Simulate", eval: "Hermes' Gambit", "eval/cc": "Iris' Gambit", @@ -1311,6 +1313,7 @@ patterns_as_iotas: "Escaping Patterns", readwrite: "Reading and Writing", meta: "Meta-Evaluation", + mishap_avoidance: "Mishap Avoidance", circle_patterns: "Spell Circle Patterns", akashic_patterns: "Akashic Patterns", @@ -2012,10 +2015,15 @@ "thanatos.1": "Adds the number of patterns a _Hex is still capable of evaluating to the stack. This is reduced by one for each pattern cast by the _Hex." }, + + mishap_avoidance: { + "1": "$(l:casting/mishaps)$(thing)Mishaps/$ can be very annoying. Thankfully, I have found a way to mitigate them. The following pattern can be used to simulate any other pattern, allowing me to find out if it would have succeeded without actually executing it.$(br2)Note that simulating a pattern like $(l:patterns/meta)$(action)Hermes' Gambit/$ will not simulate the resulting meta-evaluation, only the pattern itself.", + simulate: "Causes the next pattern drawn to be simulated rather than actually executed. A simulated pattern does not change the stack, and has no effects apart from pushing a boolean value representing whether it $(o)would/$ have successfully resolved.", + }, circle_patterns: { disclaimer: "These patterns must be cast from a $(l:greatwork/spellcircles)$(item)Spell Circle/$; trying to cast them through a $(l:items/staff)$(item)Staff/$ will fail rather spectacularly.", - + "circle/impetus_pos": "Returns the position of the $(l:greatwork/impetus)$(item)Impetus/$ of this spell circle.", "circle/impetus_dir": "Returns the direction the $(l:greatwork/impetus)$(item)Impetus/$ of this spell circle is facing as a unit vector.", "circle/bounds/min": "Returns the position of the lower-north-west corner of the bounds of this spell circle.", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/mishap_avoidance.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/mishap_avoidance.json new file mode 100644 index 000000000..94fb77b76 --- /dev/null +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/mishap_avoidance.json @@ -0,0 +1,20 @@ +{ + "name": "hexcasting.entry.mishap_avoidance", + "category": "hexcasting:patterns", + "icon": "minecraft:tripwire_hook", + "sortnum": 13, + "advancement": "hexcasting:root", + "read_by_default": true, + "pages": [ + { + "type": "patchouli:text", + "text": "hexcasting.page.mishap_avoidance.1" + }, + { + "type": "hexcasting:pattern", + "op_id": "hexcasting:simulate", + "anchor": "hexcasting:simulate", + "text": "hexcasting.page.mishap_avoidance.simulate" + } + ] +} \ No newline at end of file From 6672ee2f308628b9fd5e709cef75b6e4225afece Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 19:30:00 -0400 Subject: [PATCH 4/8] Make simulated patterns orange, keep grid open while simulating --- .../hexcasting/api/casting/eval/ResolvedPatternType.kt | 1 + .../at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/ResolvedPatternType.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/ResolvedPatternType.kt index 8e332bb80..2705861fa 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/ResolvedPatternType.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/ResolvedPatternType.kt @@ -6,6 +6,7 @@ enum class ResolvedPatternType(val color: Int, val fadeColor: Int, val success: UNRESOLVED(0x7f7f7f, 0xcccccc, false), EVALUATED(0x7385de, 0xfecbe6, true), ESCAPED(0xddcc73, 0xfffae5, true), + SIMULATED(0xed9d64, 0xffecde, true), UNDONE(0xb26b6b, 0xcca88e, true), // TODO: Pick better colours ERRORED(0xde6262, 0xffc7a0, false), INVALID(0xb26b6b, 0xcca88e, false); diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 6ee58b522..2b2ecdf5e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -112,7 +112,11 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { ravenmind = IotaType.TYPED_CODEC.encodeStart(NbtOps.INSTANCE, newIota).getOrThrow() as CompoundTag? } - val isStackClear = image.stack.isEmpty() && image.parenCount == 0 && !image.escapeNext && ravenmind == null + val isStackClear = image.stack.isEmpty() + && image.parenCount == 0 + && !image.escapeNext + && !image.simulateNext + && ravenmind == null this.env.postCast(image) return ExecutionClientView(isStackClear, lastResolutionType, image.stack, ravenmind) @@ -169,7 +173,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { stack = newStack, simulateNext = false ) - return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.EVALUATED, HexEvalSounds.NORMAL_EXECUTE) + return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.SIMULATED, HexEvalSounds.NORMAL_EXECUTE) } else { // return a standard CastResult that does include the side effects from the cast return result From 8c585dd459201d872fe364369753d2ee1eb2efdb Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 19:38:49 -0400 Subject: [PATCH 5/8] Account for stack-size mishap --- .../java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 2b2ecdf5e..6b8865cf9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -167,8 +167,9 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { if (this.image.simulateNext) { // push a bool based on whether the cast would have succeeded; do not perform any side effects from the cast val success = result.sideEffects.none { it is OperatorSideEffect.DoMishap } + val tooBig = result.newData != null && IotaType.isTooLargeToSerialize(result.newData.stack) val newStack = this.image.stack.toMutableList() - newStack.add(BooleanIota(success)) + newStack.add(BooleanIota(success && !tooBig)) val newImage = this.image.copy( stack = newStack, simulateNext = false From c6dd389efebecbae85ba2361ad9b22f358852628 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 19:44:32 -0400 Subject: [PATCH 6/8] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5289464a..2732d4974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). - Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @slava110 - Added the `hex_unbreakable` tag for blocks that should be immune to Break Block regardless of the configured mining tier ([#1186](https://github.com/FallingColors/HexMod/pull/1186)) @Robotgiggle @slava110 +- Added Simulate, which causes the next pattern drawn to be simulated (to check for mishaps) rather than executed ([#1194](https://github.com/FallingColors/HexMod/pull/1194)) @Robotgiggle ### Fixed From 0b30e11df9d152ebabb8b5e3397c7515608f7cb6 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 19:52:12 -0400 Subject: [PATCH 7/8] Remove Auditor and Assessor patterns since you can just use Simulate --- .../common/casting/actions/rw/OpReadable.kt | 26 --------------- .../casting/actions/rw/OpTheCoolerReadable.kt | 29 ----------------- .../casting/actions/rw/OpTheCoolerWritable.kt | 28 ---------------- .../common/casting/actions/rw/OpWritable.kt | 23 ------------- .../hexcasting/common/lib/hex/HexActions.java | 8 ----- .../hexcasting/lang/en_us.flatten.json5 | 6 +--- .../en_us/entries/patterns/readwrite.json | 32 ------------------- 7 files changed, 1 insertion(+), 151 deletions(-) delete mode 100644 Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt delete mode 100644 Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerReadable.kt delete mode 100644 Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerWritable.kt delete mode 100644 Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt deleted file mode 100644 index 93d234dfc..000000000 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt +++ /dev/null @@ -1,26 +0,0 @@ -package at.petrak.hexcasting.common.casting.actions.rw - -import at.petrak.hexcasting.api.casting.asActionResult -import at.petrak.hexcasting.api.casting.castables.ConstMediaAction -import at.petrak.hexcasting.api.casting.eval.CastingEnvironment -import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.xplat.IXplatAbstractions - -object OpReadable : ConstMediaAction { - override val argc = 0 - - override fun execute(args: List, env: CastingEnvironment): List { - val (handStack) = env.getHeldItemToOperateOn { - IXplatAbstractions.INSTANCE.findDataHolder(it) != null - } ?: return false.asActionResult - - val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) - ?: return false.asActionResult - - // If the datum contains no iota, return whether it has a default empty iota. - datumHolder.readIota() - ?: return (datumHolder.emptyIota() != null).asActionResult - - return true.asActionResult - } -} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerReadable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerReadable.kt deleted file mode 100644 index 2b191da48..000000000 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerReadable.kt +++ /dev/null @@ -1,29 +0,0 @@ -package at.petrak.hexcasting.common.casting.actions.rw - -import at.petrak.hexcasting.api.casting.asActionResult -import at.petrak.hexcasting.api.casting.castables.ConstMediaAction -import at.petrak.hexcasting.api.casting.eval.CastingEnvironment -import at.petrak.hexcasting.api.casting.getEntity -import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.xplat.IXplatAbstractions - -object OpTheCoolerReadable : ConstMediaAction { - override val argc = 1 - - override fun execute( - args: List, - env: CastingEnvironment - ): List { - val target = args.getEntity(env.world, 0, argc) - env.assertEntityInRange(target) - - val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(target) - ?: return false.asActionResult - - datumHolder.readIota() - ?: datumHolder.emptyIota() - ?: return false.asActionResult - - return true.asActionResult - } -} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerWritable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerWritable.kt deleted file mode 100644 index 3fac90b52..000000000 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpTheCoolerWritable.kt +++ /dev/null @@ -1,28 +0,0 @@ -package at.petrak.hexcasting.common.casting.actions.rw - -import at.petrak.hexcasting.api.casting.asActionResult -import at.petrak.hexcasting.api.casting.castables.ConstMediaAction -import at.petrak.hexcasting.api.casting.eval.CastingEnvironment -import at.petrak.hexcasting.api.casting.getEntity -import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.api.casting.iota.NullIota -import at.petrak.hexcasting.xplat.IXplatAbstractions - -object OpTheCoolerWritable : ConstMediaAction { - override val argc = 1 - - override fun execute( - args: List, - env: CastingEnvironment - ): List { - val target = args.getEntity(env.world, 0, argc) - env.assertEntityInRange(target) - - val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(target) - ?: return false.asActionResult - - val success = datumHolder.writeIota(NullIota(), true) - - return success.asActionResult - } -} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt deleted file mode 100644 index f0a3d0da1..000000000 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpWritable.kt +++ /dev/null @@ -1,23 +0,0 @@ -package at.petrak.hexcasting.common.casting.actions.rw - -import at.petrak.hexcasting.api.casting.asActionResult -import at.petrak.hexcasting.api.casting.castables.ConstMediaAction -import at.petrak.hexcasting.api.casting.eval.CastingEnvironment -import at.petrak.hexcasting.api.casting.iota.Iota -import at.petrak.hexcasting.xplat.IXplatAbstractions - -object OpWritable : ConstMediaAction { - override val argc = 0 - - override fun execute(args: List, env: CastingEnvironment): List { - val (handStack) = env.getHeldItemToOperateOn { - val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(it) - - datumHolder != null - } ?: return false.asActionResult - - val datumHolder = IXplatAbstractions.INSTANCE.findDataHolder(handStack) ?: return false.asActionResult - val success = datumHolder.writeable() - return success.asActionResult - } -} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java index 21a1e6971..7feab3947 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexActions.java @@ -417,14 +417,6 @@ public class HexActions { new ActionRegistryEntry(HexPattern.fromAngles("deeeee", HexDir.EAST), OpWrite.INSTANCE)); public static final ActionRegistryEntry WRITE$ENTITY = make("write/entity", new ActionRegistryEntry(HexPattern.fromAngles("wdwewewewewew", HexDir.EAST), OpTheCoolerWrite.INSTANCE)); - public static final ActionRegistryEntry READABLE = make("readable", - new ActionRegistryEntry(HexPattern.fromAngles("aqqqqqe", HexDir.EAST), OpReadable.INSTANCE)); - public static final ActionRegistryEntry READABLE$ENTITY = make("readable/entity", - new ActionRegistryEntry(HexPattern.fromAngles("wawqwqwqwqwqwew", HexDir.EAST), OpTheCoolerReadable.INSTANCE)); - public static final ActionRegistryEntry WRITABLE = make("writable", - new ActionRegistryEntry(HexPattern.fromAngles("deeeeeq", HexDir.EAST), OpWritable.INSTANCE)); - public static final ActionRegistryEntry WRITABLE$ENTITY = make("writable/entity", - new ActionRegistryEntry(HexPattern.fromAngles("wdwewewewewewqw", HexDir.EAST), OpTheCoolerWritable.INSTANCE)); public static final ActionRegistryEntry READ$LOCAL = make("read/local", new ActionRegistryEntry(HexPattern.fromAngles("qeewdweddw", HexDir.NORTH_EAST), OpPeekLocal.INSTANCE)); diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 index dcfcd7de7..e70a5192d 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.flatten.json5 @@ -845,11 +845,7 @@ write: "Scribe's Gambit", "write/entity": "Chronicler's Gambit", "write/local": "Huginn's Gambit", - - readable: "Auditor's Reflection", - "readable/entity": "Auditor's Purification", - writable: "Assessor's Reflection", - "writable/entity": "Assessor's Purification", + "akashic/read": "Akasha's Distillation", "akashic/write": "Akasha's Gambit", diff --git a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json index c661d10d7..a0ea97d9e 100644 --- a/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json +++ b/Common/src/main/resources/assets/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/readwrite.json @@ -40,38 +40,6 @@ "output": "", "text": "hexcasting.page.readwrite.write/entity" }, - { - "type": "hexcasting:pattern", - "op_id": "hexcasting:readable", - "anchor": "hexcasting:readable", - "input": "", - "output": "bool", - "text": "hexcasting.page.readwrite.readable" - }, - { - "type": "hexcasting:pattern", - "op_id": "hexcasting:readable/entity", - "anchor": "hexcasting:readable/entity", - "input": "entity", - "output": "bool", - "text": "hexcasting.page.readwrite.readable/entity" - }, - { - "type": "hexcasting:pattern", - "op_id": "hexcasting:writable", - "anchor": "hexcasting:writable", - "input": "", - "output": "bool", - "text": "hexcasting.page.readwrite.writable" - }, - { - "type": "hexcasting:pattern", - "op_id": "hexcasting:writable/entity", - "anchor": "hexcasting:writable/entity", - "input": "entity", - "output": "bool", - "text": "hexcasting.page.readwrite.writable/entity" - }, { "type": "patchouli:text", "anchor": "hexcasting:local", From b4275cb2a0d1ac055683058b65b2272b4a060ff1 Mon Sep 17 00:00:00 2001 From: Robotgiggle <88736742+Robotgiggle@users.noreply.github.com> Date: Thu, 9 Jul 2026 23:56:33 -0400 Subject: [PATCH 8/8] Address comments --- .../api/casting/eval/vm/CastingImage.kt | 2 +- .../api/casting/eval/vm/CastingVM.kt | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt index 627eed736..89d0f003a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt @@ -97,7 +97,7 @@ data class CastingImage( Codec.INT.fieldOf("open_parens").forGetter { it.parenCount }, ParenthesizedIota.CODEC.listOf().fieldOf("parenthesized").forGetter { it.parenthesized }, Codec.BOOL.fieldOf("escape_next").forGetter { it.escapeNext }, - Codec.BOOL.fieldOf("catch_mishap").forGetter { it.simulateNext }, + Codec.BOOL.fieldOf("simulate_next").forGetter { it.simulateNext }, Codec.LONG.fieldOf("ops_consumed").forGetter { it.opsConsumed }, CompoundTag.CODEC.fieldOf("userData").forGetter { it.userData } ).apply(inst) { a, b, c, d, e, f, g -> diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt index 6b8865cf9..1004bd14c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingVM.kt @@ -155,30 +155,28 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.ESCAPED, HexEvalSounds.NORMAL_EXECUTE) } - var result: CastResult - if (this.image.parenCount > 0) { + val result = if (this.image.parenCount > 0) { // Handle parens escaping - result = iota.executeInParens(this, world, continuation) + iota.executeInParens(this, world, continuation) } else { // Handle normal execution behavior - result = iota.execute(this, world, continuation) + iota.execute(this, world, continuation) } + // if simulating, push a bool for whether the cast would have succeeded; do not perform any side effects if (this.image.simulateNext) { - // push a bool based on whether the cast would have succeeded; do not perform any side effects from the cast - val success = result.sideEffects.none { it is OperatorSideEffect.DoMishap } val tooBig = result.newData != null && IotaType.isTooLargeToSerialize(result.newData.stack) val newStack = this.image.stack.toMutableList() - newStack.add(BooleanIota(success && !tooBig)) + newStack.add(BooleanIota(result.resolutionType.success && !tooBig)) val newImage = this.image.copy( stack = newStack, simulateNext = false ) return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.SIMULATED, HexEvalSounds.NORMAL_EXECUTE) - } else { - // return a standard CastResult that does include the side effects from the cast - return result } + + // otherwise, return the original CastResult to perform all the side effects, stack manip, etc + return result } catch (exception: Exception) { // This means something very bad has happened exception.printStackTrace()