From 73cc6f2d2d7e517dc35db7c395a4a68db3d10b49 Mon Sep 17 00:00:00 2001 From: Skye Date: Thu, 28 Nov 2024 17:32:41 +0900 Subject: [PATCH 1/2] Bump stack limit to 8k and also include current continuation size and escaped iota size in stack limit --- .../api/casting/eval/vm/CastingImage.kt | 22 +++++++++++++ .../api/casting/eval/vm/CastingVM.kt | 7 +++- .../api/casting/eval/vm/ContinuationFrame.kt | 1 + .../api/casting/eval/vm/FrameEvaluate.kt | 18 ++++++++++- .../api/casting/eval/vm/FrameFinishEval.kt | 1 + .../api/casting/eval/vm/FrameForEach.kt | 32 ++++++++++++++++++- .../api/casting/eval/vm/SpellContinuation.kt | 14 ++++++-- .../api/casting/iota/ContinuationIota.java | 13 +++----- .../common/lib/hex/HexIotaTypes.java | 2 +- 9 files changed, 96 insertions(+), 14 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 3ffd771bcd..826f504498 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 @@ -12,6 +12,7 @@ import net.minecraft.nbt.ListTag import net.minecraft.nbt.Tag import net.minecraft.server.level.ServerLevel import net.minecraft.world.entity.Entity +import kotlin.math.max /** * The state of a casting VM, containing the stack and all @@ -35,6 +36,27 @@ data class CastingImage private constructor( } } + private val size: Int + private val depth: Int + + init { + var maxChildDepth = 0 + var totalSize = 1 + for (iota in stack) { + totalSize += iota.size() + maxChildDepth = max(maxChildDepth, iota.depth()) + } + for (iota in parenthesized) { + totalSize += iota.iota.size() + maxChildDepth = max(maxChildDepth, iota.iota.depth()) + } + depth = maxChildDepth + size = totalSize + } + + fun size(): Int = size + fun depth(): Int = depth + /** * Returns an empty list if it's too complicated. */ 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 587500355b..7ed7abd2c5 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 @@ -15,8 +15,10 @@ import at.petrak.hexcasting.api.casting.math.HexPattern import at.petrak.hexcasting.api.casting.mishaps.* import at.petrak.hexcasting.api.utils.* import at.petrak.hexcasting.common.lib.hex.HexEvalSounds +import at.petrak.hexcasting.common.lib.hex.HexIotaTypes import net.minecraft.nbt.CompoundTag import net.minecraft.server.level.ServerLevel +import kotlin.math.max /** * The virtual machine! This is the glue that determines the next iteration of a [CastingImage], using a @@ -52,7 +54,10 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { // get caught and folded into CastResult by evaluate. val image2 = next.evaluate(continuation.next, world, this).let { result -> // if stack is unable to be serialized, have the result be an error - if (result.newData != null && IotaType.isTooLargeToSerialize(result.newData.stack)) { + val data = result.newData ?: this.image + val size = data.size() + result.continuation.size() + val depth = max(data.depth(), result.continuation.depth()) + if (depth >= HexIotaTypes.MAX_SERIALIZATION_DEPTH || size >= HexIotaTypes.MAX_SERIALIZATION_TOTAL) { result.copy( newData = null, sideEffects = listOf(OperatorSideEffect.DoMishap(MishapStackSize(), Mishap.Context(null, null))), diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt index 8000ec09aa..f0f3fda6ff 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt @@ -46,6 +46,7 @@ interface ContinuationFrame { * Return the number of iotas contained inside this frame, used for determining whether it is valid to serialise. */ fun size(): Int + fun depth(): Int val type: Type<*> diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt index 141148dfdc..34dd0548dc 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt @@ -13,6 +13,7 @@ import at.petrak.hexcasting.common.lib.hex.HexIotaTypes import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.Tag import net.minecraft.server.level.ServerLevel +import kotlin.math.max /** * A list of patterns to be evaluated in sequence. @@ -53,7 +54,22 @@ data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : Cont "isMetacasting" %= isMetacasting } - override fun size() = list.size() + private val size: Int + private val depth: Int + + init { + var maxChildDepth = 0 + var totalSize = 1 + for (iota in list) { + totalSize += iota.size() + maxChildDepth = max(maxChildDepth, iota.depth()) + } + depth = maxChildDepth + size = totalSize + } + + override fun size() = size + override fun depth() = depth override val type: ContinuationFrame.Type<*> = TYPE diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt index 72bbb8c80c..90370dd146 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt @@ -36,6 +36,7 @@ object FrameFinishEval : ContinuationFrame { override fun serializeToNBT() = CompoundTag() override fun size() = 0 + override fun depth() = 0 @JvmField val TYPE: ContinuationFrame.Type = object : ContinuationFrame.Type { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt index 0221c1f36d..c377e0f3f0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt @@ -14,6 +14,7 @@ import at.petrak.hexcasting.common.lib.hex.HexIotaTypes import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.Tag import net.minecraft.server.level.ServerLevel +import kotlin.math.max /** * A frame representing all the state for a Thoth evaluation. @@ -89,7 +90,36 @@ data class FrameForEach( "accumulator" %= acc.serializeToNBT() } - override fun size() = data.size() + code.size() + acc.size + (baseStack?.size ?: 0) + private val size: Int + private val depth: Int + + init { + var maxChildDepth = 0 + var totalSize = 1 + for (iota in data) { + totalSize += iota.size() + maxChildDepth = max(maxChildDepth, iota.depth()) + } + for (iota in code) { + totalSize += iota.size() + maxChildDepth = max(maxChildDepth, iota.depth()) + } + for (iota in acc) { + totalSize += iota.size() + maxChildDepth = max(maxChildDepth, iota.depth()) + } + if (baseStack != null) { + for (iota in baseStack) { + totalSize += iota.size() + maxChildDepth = max(maxChildDepth, iota.depth()) + } + } + depth = maxChildDepth + size = totalSize + } + + override fun size() = size + override fun depth() = depth override val type: ContinuationFrame.Type<*> = TYPE diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt index ec706c2858..4f600886a9 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt @@ -5,17 +5,27 @@ import at.petrak.hexcasting.api.utils.getList import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.Tag import net.minecraft.server.level.ServerLevel +import kotlin.math.max /** * A continuation during the execution of a spell. */ sealed interface SpellContinuation { - object Done : SpellContinuation + object Done : SpellContinuation { + override fun size(): Int = 0 + override fun depth(): Int = 0 + } - data class NotDone(val frame: ContinuationFrame, val next: SpellContinuation) : SpellContinuation + data class NotDone(val frame: ContinuationFrame, val next: SpellContinuation) : SpellContinuation { + override fun size(): Int = frame.size() + next.size() + override fun depth(): Int = max(frame.depth(), next.depth()) + } fun pushFrame(frame: ContinuationFrame): SpellContinuation = NotDone(frame, this) + fun size(): Int + fun depth(): Int + fun serializeToNBT() = NBTBuilder { TAG_FRAME %= list(getNBTFrames()) } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java index 13764c4675..3cd023206e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java @@ -58,15 +58,12 @@ public boolean executable() { @Override public int size() { - var continuation = this.getContinuation(); - var size = 0; - while (continuation instanceof SpellContinuation.NotDone notDone) { - size += 1; - size += notDone.component1().size(); - continuation = notDone.component2(); - } + return Math.min(this.getContinuation().size(), 1); + } - return Math.min(size, 1); + @Override + public int depth() { + return this.getContinuation().depth() + 1; } public static IotaType TYPE = new IotaType<>() { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexIotaTypes.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexIotaTypes.java index 0526e9ac56..03f55a5527 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexIotaTypes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexIotaTypes.java @@ -23,7 +23,7 @@ public class HexIotaTypes { KEY_TYPE = HexAPI.MOD_ID + ":type", KEY_DATA = HexAPI.MOD_ID + ":data"; public static final int MAX_SERIALIZATION_DEPTH = 256; - public static final int MAX_SERIALIZATION_TOTAL = 1024; + public static final int MAX_SERIALIZATION_TOTAL = 8192; public static void registerTypes(BiConsumer, ResourceLocation> r) { for (var e : TYPES.entrySet()) { From 6c5798b821c7295aa9ba27b35de3b7f1d5aa6777 Mon Sep 17 00:00:00 2001 From: Skye Date: Thu, 28 Nov 2024 17:44:50 +0900 Subject: [PATCH 2/2] Implement subIotas for ContinuationIota --- .../api/casting/eval/vm/ContinuationFrame.kt | 1 + .../api/casting/eval/vm/FrameEvaluate.kt | 1 + .../api/casting/eval/vm/FrameFinishEval.kt | 1 + .../hexcasting/api/casting/eval/vm/FrameForEach.kt | 5 +++++ .../api/casting/eval/vm/SpellContinuation.kt | 14 ++++++++++++++ .../api/casting/iota/ContinuationIota.java | 6 ++++++ 6 files changed, 28 insertions(+) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt index f0f3fda6ff..8b2f669f5b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/ContinuationFrame.kt @@ -47,6 +47,7 @@ interface ContinuationFrame { */ fun size(): Int fun depth(): Int + fun subIotas(): Iterable? val type: Type<*> diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt index 34dd0548dc..ccd0cb26cd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameEvaluate.kt @@ -70,6 +70,7 @@ data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : Cont override fun size() = size override fun depth() = depth + override fun subIotas(): Iterable = list override val type: ContinuationFrame.Type<*> = TYPE diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt index 90370dd146..94cd7b4087 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameFinishEval.kt @@ -37,6 +37,7 @@ object FrameFinishEval : ContinuationFrame { override fun size() = 0 override fun depth() = 0 + override fun subIotas(): Iterable? = null @JvmField val TYPE: ContinuationFrame.Type = object : ContinuationFrame.Type { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt index c377e0f3f0..eb84b2d7f0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/FrameForEach.kt @@ -120,6 +120,11 @@ data class FrameForEach( override fun size() = size override fun depth() = depth + override fun subIotas(): Iterable = + if (baseStack != null) + listOf(data, code, acc, baseStack).flatten() + else + listOf(data, code, acc).flatten() override val type: ContinuationFrame.Type<*> = TYPE diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt index 4f600886a9..52e8fc6694 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/eval/vm/SpellContinuation.kt @@ -1,5 +1,6 @@ package at.petrak.hexcasting.api.casting.eval.vm +import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.utils.NBTBuilder import at.petrak.hexcasting.api.utils.getList import net.minecraft.nbt.CompoundTag @@ -14,15 +15,28 @@ sealed interface SpellContinuation { object Done : SpellContinuation { override fun size(): Int = 0 override fun depth(): Int = 0 + override fun subIotas(): Iterable? = null } data class NotDone(val frame: ContinuationFrame, val next: SpellContinuation) : SpellContinuation { override fun size(): Int = frame.size() + next.size() override fun depth(): Int = max(frame.depth(), next.depth()) + override fun subIotas(): Iterable { + val list: MutableList> = mutableListOf() + var current: SpellContinuation = this + while (current is NotDone) { + val subIotas = current.frame.subIotas() + if (subIotas != null) + list.add(subIotas) + current = current.next + } + return list.flatten() + } } fun pushFrame(frame: ContinuationFrame): SpellContinuation = NotDone(frame, this) + fun subIotas(): Iterable? fun size(): Int fun depth(): Int diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java index 3cd023206e..e97ca66bae 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/ContinuationIota.java @@ -13,6 +13,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -56,6 +57,11 @@ public boolean executable() { return true; } + @Override + public @Nullable Iterable subIotas() { + return this.getContinuation().subIotas(); + } + @Override public int size() { return Math.min(this.getContinuation().size(), 1);