diff --git a/CHANGELOG.md b/CHANGELOG.md index d5289464a3..f1405a06f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @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 - 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 ### Fixed 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 8e332bb802..2705861fa3 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/CastingImage.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/CastingImage.kt index c8658157f5..89d0f003a3 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("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 -> - 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 ca19625311..1004bd14ce 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 @@ -111,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) @@ -150,13 +155,28 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.ESCAPED, HexEvalSounds.NORMAL_EXECUTE) } - if (this.image.parenCount > 0) { + val result = if (this.image.parenCount > 0) { // Handle parens escaping - return iota.executeInParens(this, world, continuation) + iota.executeInParens(this, world, continuation) } else { // Handle normal execution behavior - return 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) { + val tooBig = result.newData != null && IotaType.isTooLargeToSerialize(result.newData.stack) + val newStack = this.image.stack.toMutableList() + 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) + } + + // 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() 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 061ae27931..715e16b5e2 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)) + } + } +} 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 c72555282a..76f2971f19 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))); } 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 0000000000..270b206205 --- /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/casting/actions/rw/OpReadable.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/actions/rw/OpReadable.kt deleted file mode 100644 index 93d234dfc0..0000000000 --- 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 2b191da486..0000000000 --- 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 3fac90b52f..0000000000 --- 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 f0a3d0da10..0000000000 --- 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 eb049a8e78..7feab39471 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", @@ -414,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 528f826464..e70a5192d5 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", @@ -918,6 +914,8 @@ open_paren: "Introspection", close_paren: "Retrospection", undo: "Evanition", + + simulate: "Simulate", eval: "Hermes' Gambit", "eval/cc": "Iris' Gambit", @@ -1311,6 +1309,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 +2011,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 0000000000..94fb77b768 --- /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 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 c661d10d73..a0ea97d9eb 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",