fix up mishaps some more and fix a few spells
This commit is contained in:
parent
2233c7697d
commit
1750f29a69
12 changed files with 120 additions and 85 deletions
|
@ -112,6 +112,12 @@ public interface HexAPI {
|
|||
* Location in the userdata of the ravenmind
|
||||
*/
|
||||
String RAVENMIND_USERDATA = modLoc("ravenmind").toString();
|
||||
/**
|
||||
* Location in the userdata of the evaluation depth
|
||||
*/
|
||||
String EVAL_DEPTH_USERDATA = modLoc("eval_depth").toString();
|
||||
|
||||
String MARKED_MOVED_USERDATA = modLoc("impulsed").toString();
|
||||
|
||||
static HexAPI instance() {
|
||||
return INSTANCE.get();
|
||||
|
|
|
@ -22,6 +22,12 @@ interface SpellAction : Action {
|
|||
ctx: CastingEnvironment
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>>?
|
||||
|
||||
fun executeWithUserdata(
|
||||
args: List<Iota>, ctx: CastingEnvironment, userData: CompoundTag
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
|
||||
return this.execute(args, ctx)
|
||||
}
|
||||
|
||||
override fun operate(
|
||||
env: CastingEnvironment,
|
||||
stack: MutableList<Iota>,
|
||||
|
@ -32,7 +38,8 @@ interface SpellAction : Action {
|
|||
throw MishapNotEnoughArgs(this.argc, stack.size)
|
||||
val args = stack.takeLast(this.argc)
|
||||
for (_i in 0 until this.argc) stack.removeLast()
|
||||
val executeResult = this.execute(args, env) ?: return OperationResult(stack, userData, listOf(), continuation)
|
||||
val executeResult = this.executeWithUserdata(args, env, userData)
|
||||
?: return OperationResult(stack, userData, listOf(), continuation)
|
||||
val (spell, media, particles) = executeResult
|
||||
|
||||
val sideEffects = mutableListOf<OperatorSideEffect>()
|
||||
|
|
|
@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapEntityTooFarAway;
|
|||
import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import at.petrak.hexcasting.api.mod.HexConfig;
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
@ -20,9 +21,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
|
@ -32,12 +31,9 @@ import java.util.function.Predicate;
|
|||
*/
|
||||
public abstract class CastingEnvironment {
|
||||
protected final ServerLevel world;
|
||||
// TODO move this to the env?
|
||||
protected final Set<Entity> entitiesGivenMotion;
|
||||
|
||||
protected CastingEnvironment(ServerLevel world) {
|
||||
this.world = world;
|
||||
this.entitiesGivenMotion = new HashSet<>();
|
||||
}
|
||||
|
||||
public final ServerLevel getWorld() {
|
||||
|
@ -59,8 +55,7 @@ public abstract class CastingEnvironment {
|
|||
public abstract MishapEnvironment getMishapEnvironment();
|
||||
|
||||
/**
|
||||
* Get the sound that this I/O module makes.
|
||||
* <p>
|
||||
* Get the sound that this I/O module makes upon receiving a pattern
|
||||
*/
|
||||
public abstract EvalSound getSoundType();
|
||||
|
||||
|
@ -162,12 +157,10 @@ public abstract class CastingEnvironment {
|
|||
}
|
||||
}
|
||||
|
||||
public void markEntityAsImpulsed(Entity e) {
|
||||
this.entitiesGivenMotion.add(e);
|
||||
}
|
||||
public abstract InteractionHand castingHand();
|
||||
|
||||
public boolean hasBeenGivenMotion(Entity e) {
|
||||
return this.entitiesGivenMotion.contains(e);
|
||||
public InteractionHand otherHand() {
|
||||
return HexUtils.otherHand(this.castingHand());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,10 +3,13 @@ package at.petrak.hexcasting.api.casting.eval.vm
|
|||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.casting.iota.Iota
|
||||
import at.petrak.hexcasting.api.casting.iota.IotaType
|
||||
import at.petrak.hexcasting.api.casting.mishaps.MishapEvalTooDeep
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.Entity
|
||||
|
||||
/**
|
||||
* The state of a casting VM, containing the stack and all
|
||||
|
@ -18,10 +21,9 @@ data class CastingImage private constructor(
|
|||
val parenthesized: List<Iota>,
|
||||
val escapeNext: Boolean,
|
||||
|
||||
val iterationSteps: Int,
|
||||
val userData: CompoundTag
|
||||
) {
|
||||
public constructor() : this(listOf(), 0, listOf(), false, CompoundTag())
|
||||
constructor() : this(listOf(), 0, listOf(), false, CompoundTag())
|
||||
|
||||
fun serializeToNbt() = NBTBuilder {
|
||||
TAG_STACK %= stack.serializeToNBT()
|
||||
|
@ -33,17 +35,6 @@ data class CastingImage private constructor(
|
|||
TAG_USERDATA %= userData
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if we get too deep.
|
||||
*/
|
||||
fun incDepth(): CastingImage {
|
||||
val maxAllowedDepth = HexConfig.server().maxRecurseDepth()
|
||||
if (this.iterationSteps + 1 > maxAllowedDepth) {
|
||||
throw MishapEvalTooDeep()
|
||||
}
|
||||
return copy(iterationSteps = iterationSteps + 1)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG_STACK = "stack"
|
||||
const val TAG_PAREN_COUNT = "open_parens"
|
||||
|
@ -87,5 +78,31 @@ data class CastingImage private constructor(
|
|||
CastingImage()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if we get too deep.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun incDepth(userData: CompoundTag): CompoundTag {
|
||||
val maxAllowedDepth = HexConfig.server().maxRecurseDepth()
|
||||
val depth = userData.getInt(HexAPI.EVAL_DEPTH_USERDATA)
|
||||
if (depth + 1 > maxAllowedDepth) {
|
||||
throw MishapEvalTooDeep()
|
||||
}
|
||||
|
||||
userData.putInt(HexAPI.EVAL_DEPTH_USERDATA, depth + 1)
|
||||
return userData
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun checkAndMarkGivenMotion(userData: CompoundTag, entity: Entity): Boolean {
|
||||
val marked = userData.getOrCreateCompound(HexAPI.MARKED_MOVED_USERDATA)
|
||||
return if (marked.contains(entity.stringUUID)) {
|
||||
true
|
||||
} else {
|
||||
marked.putBoolean(entity.stringUUID, true)
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
|
|||
// ALSO TODO need to add reader macro-style things
|
||||
try {
|
||||
this.handleParentheses(iota)?.let { (data, resolutionType) ->
|
||||
return@executeInner CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.OPERATOR)
|
||||
return@executeInner CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.ADD_PATTERN)
|
||||
}
|
||||
} catch (e: MishapTooManyCloseParens) {
|
||||
// This is ridiculous and needs to be fixed
|
||||
|
|
|
@ -12,7 +12,7 @@ class MishapImmuneEntity(val entity: Entity) : Mishap() {
|
|||
dyeColor(DyeColor.BLUE)
|
||||
|
||||
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
|
||||
yeetHeldItemsTowards(ctx, entity.position())
|
||||
ctx.mishapEnvironment.yeetHeldItemsTowards(entity.position())
|
||||
}
|
||||
|
||||
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =
|
||||
|
|
|
@ -5,6 +5,8 @@ import at.petrak.hexcasting.api.addldata.ADMediaHolder;
|
|||
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers;
|
||||
import at.petrak.hexcasting.api.casting.ParticleSpray;
|
||||
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
|
||||
import at.petrak.hexcasting.api.casting.eval.MishapEnvironment;
|
||||
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
|
||||
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
|
@ -13,6 +15,7 @@ import at.petrak.hexcasting.api.mod.HexConfig;
|
|||
import at.petrak.hexcasting.api.mod.HexStatistics;
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import at.petrak.hexcasting.api.utils.MediaHelper;
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
@ -44,6 +47,11 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
return this.caster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvalSound getSoundType() {
|
||||
return HexEvalSounds.ADD_PATTERN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ItemStack> getUsableStacks(StackDiscoveryMode mode) {
|
||||
return switch (mode) {
|
||||
|
@ -167,9 +175,13 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
return this.caster.position();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MishapEnvironment getMishapEnvironment() {
|
||||
return new PlayerBasedMishapEnv(this.caster);
|
||||
}
|
||||
|
||||
protected void sendMishapMsgToPlayer(OperatorSideEffect.DoMishap mishap) {
|
||||
var msg = mishap.getMishap().errorMessageWithName(this, mishap.getErrorCtx());
|
||||
this.caster.sendSystemMessage(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,13 +4,11 @@ import at.petrak.hexcasting.api.HexAPI;
|
|||
import at.petrak.hexcasting.api.casting.eval.CastResult;
|
||||
import at.petrak.hexcasting.api.casting.eval.ExecutionClientView;
|
||||
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern;
|
||||
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType;
|
||||
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect;
|
||||
import at.petrak.hexcasting.api.casting.iota.PatternIota;
|
||||
import at.petrak.hexcasting.api.casting.math.HexCoord;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import at.petrak.hexcasting.api.mod.HexStatistics;
|
||||
import at.petrak.hexcasting.api.mod.HexTags;
|
||||
import at.petrak.hexcasting.common.network.MsgNewSpellPatternAck;
|
||||
import at.petrak.hexcasting.common.network.MsgNewSpellPatternSyn;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
|
@ -51,52 +49,45 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
|
|||
}
|
||||
|
||||
public static void handleNewPatternOnServer(ServerPlayer sender, MsgNewSpellPatternSyn msg) {
|
||||
var held = sender.getItemInHand(msg.handUsed());
|
||||
if (held.is(HexTags.Items.STAVES)) {
|
||||
boolean autoFail = false;
|
||||
boolean cheatedPatternOverlap = false;
|
||||
|
||||
List<ResolvedPattern> resolvedPatterns = msg.resolvedPatterns();
|
||||
if (!resolvedPatterns.isEmpty()) {
|
||||
var allPoints = new HashSet<HexCoord>();
|
||||
for (int i = 0; i < resolvedPatterns.size() - 1; i++) {
|
||||
ResolvedPattern pat = resolvedPatterns.get(i);
|
||||
allPoints.addAll(pat.getPattern().positions(pat.getOrigin()));
|
||||
}
|
||||
var currentResolvedPattern = resolvedPatterns.get(resolvedPatterns.size() - 1);
|
||||
var currentSpellPoints = currentResolvedPattern.getPattern()
|
||||
.positions(currentResolvedPattern.getOrigin());
|
||||
if (currentSpellPoints.stream().anyMatch(allPoints::contains)) {
|
||||
autoFail = true;
|
||||
}
|
||||
List<ResolvedPattern> resolvedPatterns = msg.resolvedPatterns();
|
||||
if (!resolvedPatterns.isEmpty()) {
|
||||
var allPoints = new HashSet<HexCoord>();
|
||||
for (int i = 0; i < resolvedPatterns.size() - 1; i++) {
|
||||
ResolvedPattern pat = resolvedPatterns.get(i);
|
||||
allPoints.addAll(pat.getPattern().positions(pat.getOrigin()));
|
||||
}
|
||||
|
||||
sender.awardStat(HexStatistics.PATTERNS_DRAWN);
|
||||
|
||||
var harness = IXplatAbstractions.INSTANCE.getStaffHarness(sender, msg.handUsed());
|
||||
|
||||
ExecutionClientView clientInfo;
|
||||
if (autoFail) {
|
||||
var descs = harness.generateDescs();
|
||||
clientInfo = new ExecutionClientView(harness.getStack().isEmpty(), ResolvedPatternType.INVALID,
|
||||
descs.getFirst(), descs.getSecond(), descs.getThird(), harness.getParenCount());
|
||||
} else {
|
||||
clientInfo = harness.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
|
||||
var currentResolvedPattern = resolvedPatterns.get(resolvedPatterns.size() - 1);
|
||||
var currentSpellPoints = currentResolvedPattern.getPattern()
|
||||
.positions(currentResolvedPattern.getOrigin());
|
||||
if (currentSpellPoints.stream().anyMatch(allPoints::contains)) {
|
||||
cheatedPatternOverlap = true;
|
||||
}
|
||||
|
||||
if (clientInfo.isStackClear()) {
|
||||
IXplatAbstractions.INSTANCE.setHarness(sender, null);
|
||||
IXplatAbstractions.INSTANCE.setPatterns(sender, List.of());
|
||||
} else {
|
||||
IXplatAbstractions.INSTANCE.setHarness(sender, harness);
|
||||
if (!resolvedPatterns.isEmpty()) {
|
||||
resolvedPatterns.get(resolvedPatterns.size() - 1).setType(clientInfo.getResolutionType());
|
||||
}
|
||||
IXplatAbstractions.INSTANCE.setPatterns(sender, resolvedPatterns);
|
||||
}
|
||||
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(sender,
|
||||
new MsgNewSpellPatternAck(clientInfo, resolvedPatterns.size() - 1));
|
||||
}
|
||||
|
||||
if (cheatedPatternOverlap) {
|
||||
return;
|
||||
}
|
||||
|
||||
sender.awardStat(HexStatistics.PATTERNS_DRAWN);
|
||||
|
||||
var harness = IXplatAbstractions.INSTANCE.getStaffHarness(sender, msg.handUsed());
|
||||
|
||||
ExecutionClientView clientInfo = harness.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
|
||||
|
||||
if (clientInfo.isStackClear()) {
|
||||
IXplatAbstractions.INSTANCE.setHarness(sender, null);
|
||||
IXplatAbstractions.INSTANCE.setPatterns(sender, List.of());
|
||||
} else {
|
||||
IXplatAbstractions.INSTANCE.setHarness(sender, harness);
|
||||
if (!resolvedPatterns.isEmpty()) {
|
||||
resolvedPatterns.get(resolvedPatterns.size() - 1).setType(clientInfo.getResolutionType());
|
||||
}
|
||||
IXplatAbstractions.INSTANCE.setPatterns(sender, resolvedPatterns);
|
||||
}
|
||||
|
||||
IXplatAbstractions.INSTANCE.sendPacketToPlayer(sender,
|
||||
new MsgNewSpellPatternAck(clientInfo, resolvedPatterns.size() - 1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package at.petrak.hexcasting.common.casting.operators.eval
|
||||
|
||||
import at.petrak.hexcasting.api.casting.SpellList
|
||||
import at.petrak.hexcasting.api.casting.asActionResult
|
||||
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.FrameEvaluate
|
||||
import at.petrak.hexcasting.api.casting.eval.vm.FrameFinishEval
|
||||
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
|
||||
|
@ -23,9 +25,9 @@ object OpEval : Action {
|
|||
val datum = stack.removeLastOrNull() ?: throw MishapNotEnoughArgs(1, 0)
|
||||
val instrs = evaluatable(datum, 0)
|
||||
|
||||
val stack = instrs.ifRight {
|
||||
// FIXME: Casting depth increment not implemented yet
|
||||
//env.incDepth()
|
||||
instrs.ifRight {
|
||||
CastingImage.incDepth(userData)
|
||||
it.asActionResult
|
||||
}
|
||||
|
||||
// if not installed already...
|
||||
|
@ -39,6 +41,6 @@ object OpEval : Action {
|
|||
|
||||
val instrsList = instrs.map({ SpellList.LList(0, listOf(PatternIota(it))) }, { it })
|
||||
val frame = FrameEvaluate(instrsList, true)
|
||||
return OperationResult(stack, userData, listOf(), newCont.pushFrame(frame))
|
||||
return OperationResult(listOf(), userData, listOf(), newCont.pushFrame(frame))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,10 +4,12 @@ import at.petrak.hexcasting.api.casting.ParticleSpray
|
|||
import at.petrak.hexcasting.api.casting.RenderedSpell
|
||||
import at.petrak.hexcasting.api.casting.castables.SpellAction
|
||||
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
|
||||
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage
|
||||
import at.petrak.hexcasting.api.casting.getEntity
|
||||
import at.petrak.hexcasting.api.casting.getVec3
|
||||
import at.petrak.hexcasting.api.casting.iota.Iota
|
||||
import at.petrak.hexcasting.api.misc.MediaConstants
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
|
@ -18,17 +20,18 @@ object OpAddMotion : SpellAction {
|
|||
// for bug #387
|
||||
val MAX_MOTION: Double = 8192.0
|
||||
|
||||
override fun execute(
|
||||
override fun executeWithUserdata(
|
||||
args: List<Iota>,
|
||||
ctx: CastingEnvironment
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>> {
|
||||
ctx: CastingEnvironment,
|
||||
userData: CompoundTag
|
||||
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
|
||||
val target = args.getEntity(0, argc)
|
||||
val motion = args.getVec3(1, argc)
|
||||
ctx.assertEntityInRange(target)
|
||||
|
||||
var motionForCost = motion.lengthSqr()
|
||||
if (ctx.hasBeenGivenMotion(target))
|
||||
if (CastingImage.checkAndMarkGivenMotion(userData, target))
|
||||
motionForCost++
|
||||
ctx.markEntityAsMotionAdded(target)
|
||||
|
||||
val shrunkMotion = if (motion.lengthSqr() > MAX_MOTION * MAX_MOTION)
|
||||
motion.normalize().scale(MAX_MOTION)
|
||||
|
@ -48,6 +51,10 @@ object OpAddMotion : SpellAction {
|
|||
)
|
||||
}
|
||||
|
||||
override fun execute(args: List<Iota>, ctx: CastingEnvironment): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
|
||||
private data class Spell(val target: Entity, val motion: Vec3) : RenderedSpell {
|
||||
override fun cast(ctx: CastingEnvironment) {
|
||||
target.push(motion.x, motion.y, motion.z)
|
||||
|
|
|
@ -49,7 +49,7 @@ class OpCreateFluid(val cost: Int, val bucket: Item, val cauldron: BlockState, v
|
|||
ctx.world.setBlock(pos, cauldron, 3)
|
||||
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
|
||||
ctx.world,
|
||||
ctx.castingHand,
|
||||
ctx.castingHand(),
|
||||
pos,
|
||||
fluid
|
||||
) && bucket is BucketItem) {
|
||||
|
|
|
@ -15,14 +15,14 @@ public class HexEvalSounds {
|
|||
|
||||
public static final EvalSound NOTHING = make("nothing",
|
||||
new EvalSound(null, Integer.MIN_VALUE));
|
||||
public static final EvalSound OPERATOR = make("operator",
|
||||
public static final EvalSound ADD_PATTERN = make("operator",
|
||||
new EvalSound(HexSounds.ADD_PATTERN, 0));
|
||||
public static final EvalSound SPELL = make("spell",
|
||||
new EvalSound(HexSounds.ACTUALLY_CAST, 1000));
|
||||
public static final EvalSound HERMES = make("hermes",
|
||||
new EvalSound(HexSounds.CAST_HERMES, 2000));
|
||||
public static final EvalSound THOTH = make("thoth",
|
||||
new EvalSound(HexSounds.CAST_THOTH, 2000));
|
||||
new EvalSound(HexSounds.CAST_THOTH, 2500));
|
||||
|
||||
public static final EvalSound MUTE = make("mute",
|
||||
new EvalSound(null, 3000));
|
||||
|
|
Loading…
Reference in a new issue