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 e4513b6f..d772a397 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 @@ -1,14 +1,10 @@ package at.petrak.hexcasting.api.casting.eval.vm import at.petrak.hexcasting.api.HexAPI -import at.petrak.hexcasting.api.casting.PatternShapeMatch 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 -import at.petrak.hexcasting.api.casting.eval.vm.FrameEvaluate -import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.IotaType import at.petrak.hexcasting.api.casting.iota.ListIota @@ -16,14 +12,9 @@ import at.petrak.hexcasting.api.casting.iota.PatternIota import at.petrak.hexcasting.api.casting.math.HexDir import at.petrak.hexcasting.api.casting.math.HexPattern import at.petrak.hexcasting.api.casting.mishaps.* -import at.petrak.hexcasting.api.mod.HexConfig -import at.petrak.hexcasting.api.mod.HexTags import at.petrak.hexcasting.api.utils.* -import at.petrak.hexcasting.common.casting.PatternRegistryManifest import at.petrak.hexcasting.common.lib.hex.HexEvalSounds -import at.petrak.hexcasting.xplat.IXplatAbstractions import net.minecraft.nbt.CompoundTag -import net.minecraft.network.chat.Component import net.minecraft.server.level.ServerLevel /** @@ -109,22 +100,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { ) } - if (iota is PatternIota) { - return executePattern(iota.pattern, world, continuation) - } else { - return CastResult( - continuation, - null, - listOf( - OperatorSideEffect.DoMishap( - MishapUnescapedValue(iota), - Mishap.Context(HexPattern(HexDir.WEST), null) - ) - ), // Should never matter - ResolvedPatternType.INVALID, - HexEvalSounds.MISHAP - ) - } + return iota.execute(this, world, continuation) } catch (exception: Exception) { // This means something very bad has happened exception.printStackTrace() @@ -146,92 +122,6 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) { } } - /** - * When the server gets a packet from the client with a new pattern, - * handle it functionally. - */ - private fun executePattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult { - var castedName: Component? = null - try { - val lookup = PatternRegistryManifest.matchPattern(newPat, world, false) - this.env.precheckAction(lookup) - - val action = if (lookup is Normal || lookup is PerWorld) { - val key = when (lookup) { - is Normal -> lookup.key - is PerWorld -> lookup.key - else -> throw IllegalStateException() - } - - val reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.actionRegistry, key, HexTags.Actions.REQUIRES_ENLIGHTENMENT) - - castedName = HexAPI.instance().getActionI18n(key, reqsEnlightenment) - - IXplatAbstractions.INSTANCE.actionRegistry.get(key)!!.action - } else if (lookup is Special) { - castedName = lookup.handler.name - lookup.handler.act() - } else if (lookup is PatternShapeMatch.Nothing) { - throw MishapInvalidPattern() - } else throw IllegalStateException() - - val opCount = if (this.image.userData.contains(HexAPI.OP_COUNT_USERDATA)) { - this.image.userData.getInt(HexAPI.OP_COUNT_USERDATA) - } else { - this.image.userData.putInt(HexAPI.OP_COUNT_USERDATA, 0) - 0 - } - if (opCount + 1 > HexConfig.server().maxOpCount()) { - throw MishapEvalTooMuch() - } - this.image.userData.putInt(HexAPI.OP_COUNT_USERDATA, opCount + 1) - - val sideEffects = mutableListOf() - var stack2: List? = null - var cont2 = continuation - var userData2: CompoundTag? = null - - val result = action.operate( - this.env, - this.image.stack.toMutableList(), - this.image.userData.copy(), - continuation - ) - cont2 = result.newContinuation - stack2 = result.newStack - userData2 = result.newUserdata - // TODO parens also break prescience - sideEffects.addAll(result.sideEffects) - - val hereFd = this.image - val fd = if (stack2 != null) { - hereFd.copy( - stack = stack2, - userData = userData2, - ) - } else { - hereFd - } - - return CastResult( - cont2, - fd, - sideEffects, - ResolvedPatternType.EVALUATED, - env.soundType, - ) - - } catch (mishap: Mishap) { - return CastResult( - continuation, - null, - listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, castedName))), - mishap.resolutionType(env), - HexEvalSounds.MISHAP - ) - } - } - /** * Execute the side effects of a pattern, updating our aggregated info. */ diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/Iota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/Iota.java index 5d60e74f..084dfa6c 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/Iota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/Iota.java @@ -1,10 +1,23 @@ package at.petrak.hexcasting.api.casting.iota; +import at.petrak.hexcasting.api.casting.eval.CastResult; +import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType; +import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect; +import at.petrak.hexcasting.api.casting.eval.vm.CastingVM; +import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation; +import at.petrak.hexcasting.api.casting.math.HexDir; +import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.api.casting.mishaps.Mishap; +import at.petrak.hexcasting.api.casting.mishaps.MishapUnescapedValue; +import at.petrak.hexcasting.common.lib.hex.HexEvalSounds; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.NotNull; +import java.util.List; + public abstract class Iota { @NotNull protected final Object payload; @@ -34,6 +47,25 @@ public abstract class Iota { */ abstract public @NotNull Tag serialize(); + /** + * This method is called when this iota is executed (i.e. Hermes is run on a list containing it, unescaped). + * By default it will return a {@link CastResult} indicating an error has occurred. + */ + public @NotNull CastResult execute(CastingVM vm, ServerLevel world, SpellContinuation continuation) { + return new CastResult( + continuation, + null, + List.of( + new OperatorSideEffect.DoMishap( + new MishapUnescapedValue(this), + new Mishap.Context(new HexPattern(HexDir.WEST, List.of()), null) + ) + ), // Should never matter + ResolvedPatternType.INVALID, + HexEvalSounds.MISHAP + ); + } + public Component display() { return this.type.display(this.serialize()); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java index 0f9b10c3..2ebf4359 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/iota/PatternIota.java @@ -1,16 +1,40 @@ package at.petrak.hexcasting.api.casting.iota; +import at.petrak.hexcasting.api.HexAPI; +import at.petrak.hexcasting.api.casting.ActionRegistryEntry; +import at.petrak.hexcasting.api.casting.PatternShapeMatch; +import at.petrak.hexcasting.api.casting.castables.Action; +import at.petrak.hexcasting.api.casting.eval.CastResult; +import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType; +import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect; +import at.petrak.hexcasting.api.casting.eval.vm.CastingVM; +import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.api.casting.mishaps.Mishap; +import at.petrak.hexcasting.api.casting.mishaps.MishapEvalTooMuch; +import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidPattern; +import at.petrak.hexcasting.api.mod.HexConfig; +import at.petrak.hexcasting.api.mod.HexTags; import at.petrak.hexcasting.api.utils.HexUtils; +import at.petrak.hexcasting.common.casting.PatternRegistryManifest; +import at.petrak.hexcasting.common.lib.hex.HexEvalSounds; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; +import at.petrak.hexcasting.xplat.IXplatAbstractions; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static at.petrak.hexcasting.api.utils.HexUtils.isOfTag; + public class PatternIota extends Iota { public PatternIota(@NotNull HexPattern pattern) { super(HexIotaTypes.PATTERN, pattern); @@ -41,9 +65,82 @@ public class PatternIota extends Iota { return this.getPattern().serializeToNBT(); } + @Override + public @NotNull CastResult execute(CastingVM vm, ServerLevel world, SpellContinuation continuation) { + @Nullable Component castedName = null; + try { + var lookup = PatternRegistryManifest.matchPattern(this.getPattern(), world, false); + vm.getEnv().precheckAction(lookup); + + Action action; + if (lookup instanceof PatternShapeMatch.Normal || lookup instanceof PatternShapeMatch.PerWorld) { + ResourceKey key; + if (lookup instanceof PatternShapeMatch.Normal normal) { + key = normal.key; + } else { + PatternShapeMatch.PerWorld perWorld = (PatternShapeMatch.PerWorld) lookup; + key = perWorld.key; + } + + var reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), key, HexTags.Actions.REQUIRES_ENLIGHTENMENT); + + castedName = HexAPI.instance().getActionI18n(key, reqsEnlightenment); + + action = Objects.requireNonNull(IXplatAbstractions.INSTANCE.getActionRegistry().get(key)).action(); + } else if (lookup instanceof PatternShapeMatch.Special special) { + castedName = special.handler.getName(); + action = special.handler.act(); + } else if (lookup instanceof PatternShapeMatch.Nothing) { + throw new MishapInvalidPattern(); + } else throw new IllegalStateException(); + + var opCount = 0; + if (vm.getImage().getUserData().contains(HexAPI.OP_COUNT_USERDATA)) { + opCount = vm.getImage().getUserData().getInt(HexAPI.OP_COUNT_USERDATA); + } else + vm.getImage().getUserData().putInt(HexAPI.OP_COUNT_USERDATA, 0); + + if (opCount + 1 > HexConfig.server().maxOpCount()) { + throw new MishapEvalTooMuch(); + } + vm.getImage().getUserData().putInt(HexAPI.OP_COUNT_USERDATA, opCount + 1); + + var result = action.operate( + vm.getEnv(), + new ArrayList<>(vm.getImage().getStack()), + vm.getImage().getUserData().copy(), + continuation + ); + + var cont2 = result.getNewContinuation(); + var stack2 = result.getNewStack(); + var userData2 = result.getNewUserdata(); + // TODO parens also break prescience + var sideEffects = result.getSideEffects(); + + var hereFd = vm.getImage(); + hereFd = hereFd.copy(stack2, hereFd.getParenCount(), hereFd.getParenthesized(), hereFd.getEscapeNext(), userData2); + + return new CastResult( + cont2, + hereFd, + sideEffects, + ResolvedPatternType.EVALUATED, + vm.getEnv().getSoundType() + ); + + } catch (Mishap mishap) { + return new CastResult( + continuation, + null, + List.of(new OperatorSideEffect.DoMishap(mishap, new Mishap.Context(this.getPattern(), castedName))), + mishap.resolutionType(vm.getEnv()), + HexEvalSounds.MISHAP + ); + } + } public static IotaType TYPE = new IotaType<>() { - @Nullable @Override public PatternIota deserialize(Tag tag, ServerLevel world) throws IllegalArgumentException { return PatternIota.deserialize(tag);