made Evanition interact properly with unescaped and escaped introspection/retrospections.

This commit is contained in:
Talia-12 2023-06-04 17:17:33 +10:00
parent 798bb79acb
commit e50f233176
4 changed files with 65 additions and 12 deletions

View file

@ -1,10 +1,14 @@
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage.ParenthesizedIota.Companion.TAG_ESCAPED
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage.ParenthesizedIota.Companion.TAG_IOTAS
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.iota.ListIota
import at.petrak.hexcasting.api.utils.*
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag
import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.Entity
@ -16,7 +20,7 @@ data class CastingImage private constructor(
val stack: List<Iota>,
val parenCount: Int,
val parenthesized: List<Iota>,
val parenthesized: List<ParenthesizedIota>,
val escapeNext: Boolean,
val opsConsumed: Long,
@ -24,6 +28,30 @@ data class CastingImage private constructor(
) {
constructor() : this(listOf(), 0, listOf(), false, 0, CompoundTag())
data class ParenthesizedIota(val iota: Iota, val escaped: Boolean) {
companion object {
const val TAG_IOTAS = "iotas"
const val TAG_ESCAPED = "escaped"
}
}
/**
* Returns an empty list if it's too complicated.
*/
private fun Iterable<ParenthesizedIota>.serializeToNBT(): CompoundTag {
val tag = CompoundTag()
if (IotaType.isTooLargeToSerialize(this.map { it.iota })) {
tag.put(TAG_IOTAS, ListTag())
tag.put(TAG_ESCAPED, ListTag())
} else {
tag.put(TAG_IOTAS, ListIota(this.map { it.iota }).serialize())
tag.put(TAG_ESCAPED, this.map { it.escaped }.serializeToNBT())
}
return tag
}
/**
* Return a copy of this with the given number of ops additionally exhausted
*/
@ -74,10 +102,13 @@ data class CastingImage private constructor(
CompoundTag()
}
val parenthesized = mutableListOf<Iota>()
val parenTag = tag.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND)
for (subtag in parenTag) {
parenthesized.add(IotaType.deserialize(subtag.downcast(CompoundTag.TYPE), world))
val parenthesized = mutableListOf<ParenthesizedIota>()
val parenTag = tag.getCompound(TAG_PARENTHESIZED)
val parenIotasTag = parenTag.getList(TAG_IOTAS, Tag.TAG_COMPOUND)
val parenEscapedTag = parenTag.getByteArray(TAG_ESCAPED)
for ((subtag, isEscapedByte) in parenIotasTag.zipWithDefault(parenEscapedTag) { _ -> 0 }) {
parenthesized.add(ParenthesizedIota(IotaType.deserialize(subtag.downcast(CompoundTag.TYPE), world), isEscapedByte != 0.toByte()))
}
val parenCount = tag.getInt(TAG_PAREN_COUNT)

View file

@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.PatternShapeMatch.*
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.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.iota.ListIota
@ -156,7 +157,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
val out = if (displayDepth > 0) {
if (this.image.escapeNext) {
val newParens = this.image.parenthesized.toMutableList()
newParens.add(iota)
newParens.add(ParenthesizedIota(iota, true))
this.image.copy(
escapeNext = false,
parenthesized = newParens
@ -173,13 +174,18 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
SpecialPatterns.EVANITION.anglesSignature() -> {
val newParens = this.image.parenthesized.toMutableList()
val last = newParens.removeLastOrNull()
this.image.copy(parenthesized = newParens) to if (last == null) ResolvedPatternType.ERRORED else ResolvedPatternType.UNDONE
val newParenCount = this.image.parenCount + if (last == null || last.escaped || last.iota !is PatternIota) 0 else when (last.iota.pattern) {
SpecialPatterns.INTROSPECTION -> -1
SpecialPatterns.RETROSPECTION -> 1
else -> -1
}
this.image.copy(parenthesized = newParens, parenCount = newParenCount) to if (last == null) ResolvedPatternType.ERRORED else ResolvedPatternType.UNDONE
}
SpecialPatterns.INTROSPECTION.anglesSignature() -> {
// we have escaped the parens onto the stack; we just also record our count.
val newParens = this.image.parenthesized.toMutableList()
newParens.add(iota)
newParens.add(ParenthesizedIota(iota, false))
this.image.copy(
parenthesized = newParens,
parenCount = this.image.parenCount + 1
@ -191,7 +197,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
displayDepth--
if (newParenCount == 0) {
val newStack = this.image.stack.toMutableList()
newStack.add(ListIota(this.image.parenthesized.toList()))
newStack.add(ListIota(this.image.parenthesized.toList().map { it.iota }))
this.image.copy(
stack = newStack,
parenCount = newParenCount,
@ -203,7 +209,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
// we have this situation: "(()"
// we need to add the close paren
val newParens = this.image.parenthesized.toMutableList()
newParens.add(iota)
newParens.add(ParenthesizedIota(iota, false))
this.image.copy(
parenCount = newParenCount,
parenthesized = newParens
@ -213,7 +219,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
else -> {
val newParens = this.image.parenthesized.toMutableList()
newParens.add(iota)
newParens.add(ParenthesizedIota(iota, false))
this.image.copy(
parenthesized = newParens
) to ResolvedPatternType.ESCAPED

View file

@ -267,6 +267,22 @@ fun Iterable<Iota>.serializeToNBT() =
else
ListIota(this.toList()).serialize()
fun Iterable<Boolean>.serializeToNBT(): ByteArrayTag {
val out = ByteArray(if (this is Collection<*>) this.size else 10)
for ((i, b) in this.withIndex()) {
out[i] = if (b) 1 else 0
}
return ByteArrayTag(out)
}
fun <A> List<A>.zipWithDefault(array: ByteArray, default: (idx: Int) -> Byte): List<Pair<A, Byte>> {
val list = ArrayList<Pair<A, Byte>>(this.size)
var i = 0
for (element in this) list.add(element to array.getOrElse(i++, default))
return list
}
// Copy the impl from forge
fun ItemStack.serializeToNBT(): CompoundTag {
val out = CompoundTag()

View file

@ -69,7 +69,7 @@ class GuiSpellcasting constructor(
// TODO this is the kinda hacky bit
if (info.resolutionType == ResolvedPatternType.UNDONE) {
this.patterns.getOrNull(index - 1)?.let { it.type = ResolvedPatternType.UNDONE }
this.patterns.reversed().drop(1).firstOrNull { it.type == ResolvedPatternType.ESCAPED }?.let { it.type = ResolvedPatternType.UNDONE }
this.patterns.getOrNull(index)?.let { it.type = ResolvedPatternType.EVALUATED }
} else this.patterns.getOrNull(index)?.let {
it.type = info.resolutionType