Make it so that the code to execute patterns is contained in PatternIota, enabling other Iotas to be executable if we want.
This commit is contained in:
parent
8396c90c5f
commit
e7cac1e30d
3 changed files with 131 additions and 112 deletions
|
@ -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<OperatorSideEffect>()
|
||||
var stack2: List<Iota>? = 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.
|
||||
*/
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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<ActionRegistryEntry> 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<PatternIota> TYPE = new IotaType<>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public PatternIota deserialize(Tag tag, ServerLevel world) throws IllegalArgumentException {
|
||||
return PatternIota.deserialize(tag);
|
||||
|
|
Loading…
Reference in a new issue