diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/TripleIterable.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/TripleIterable.java new file mode 100644 index 00000000..e066a106 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/TripleIterable.java @@ -0,0 +1,43 @@ +package at.petrak.hexcasting.api.casting.arithmetic; + +import org.apache.commons.lang3.function.TriFunction; +import org.jetbrains.annotations.NotNull; + +import java.util.Iterator; + +public class TripleIterable implements Iterable { + private final Iterable iterableA; + private final Iterable iterableB; + private final Iterable iterableC; + + private final TriFunction map; + + public TripleIterable(Iterable iterableA, Iterable iterableB, Iterable iterableC, TriFunction map) { + this.iterableA = iterableA; + this.iterableB = iterableB; + this.iterableC = iterableC; + this.map = map; + } + + @NotNull + @Override + public Iterator iterator() { + return new TripleIterator(); + } + + class TripleIterator implements Iterator { + private final Iterator iteratorA = iterableA.iterator(); + private final Iterator iteratorB = iterableB.iterator(); + private final Iterator iteratorC = iterableC.iterator(); + + @Override + public boolean hasNext() { + return iteratorA.hasNext() && iteratorB.hasNext() && iteratorC.hasNext(); + } + + @Override + public D next() { + return map.apply(iteratorA.next(), iteratorB.next(), iteratorC.next()); + } + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/ArithmeticEngine.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/ArithmeticEngine.java index 7a898051..cd1cac0b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/ArithmeticEngine.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/ArithmeticEngine.java @@ -2,8 +2,17 @@ package at.petrak.hexcasting.api.casting.arithmetic.engine; import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic; import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator; +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.SpellContinuation; import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.math.HexPattern; +import at.petrak.hexcasting.api.casting.mishaps.Mishap; +import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidOperatorArgs; +import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs; +import at.petrak.hexcasting.common.lib.hex.HexEvalSounds; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -42,15 +51,33 @@ public class ArithmeticEngine { return operators.keySet(); } - public @Nullable Iota run(HexPattern operator, Stack iotas) { + @Nullable + public OperationResult operate(@NotNull HexPattern operator, @NotNull CastingEnvironment env, @NotNull CastingImage image, @NotNull SpellContinuation continuation) throws Mishap { + var stackList = image.getStack(); + var stack = new Stack(); + stack.addAll(stackList); + var startingLength = stackList.size(); + try { + var ret = run(operator, stack, startingLength); + ret.forEach(stack::add); + var image2 = image.copy(stack, image.getParenCount(), image.getParenthesized(), image.getEscapeNext(), image.getOpsConsumed() + 1, image.getUserData()); + return new OperationResult(image2, List.of(), continuation, HexEvalSounds.NORMAL_EXECUTE); + } catch (InvalidOperatorException e) { + return null; + } catch (NoOperatorCandidatesException e) { + throw new MishapInvalidOperatorArgs(e.args, e.pattern); + } + } + + public Iterable run(HexPattern operator, Stack iotas, int startingLength) throws Mishap { var candidates = operators.get(operator); if (candidates == null) - return null; // not an operator + throw new InvalidOperatorException("the pattern " + operator + " is not an operator."); // HashCons hash = new HashCons.Pattern(operator); var args = new ArrayList(candidates.arity()); for (var i = 0; i < candidates.arity(); i++) { if (iotas.isEmpty()) { - throw new IllegalStateException("Not enough args on stack for operator: " + operator); + throw new MishapNotEnoughArgs(candidates.arity, startingLength); } var iota = iotas.pop(); hash = new HashCons.Pair(iota.getType(), hash); @@ -68,7 +95,7 @@ public class ArithmeticEngine { return op; } } - throw new IllegalArgumentException("No implementation candidates for op " + candidates.pattern() + " on args: " + args); + throw new NoOperatorCandidatesException(candidates.pattern(), args, "No implementation candidates for op " + candidates.pattern() + " on args: " + args); }); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/InvalidOperatorException.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/InvalidOperatorException.java new file mode 100644 index 00000000..1d826da6 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/InvalidOperatorException.java @@ -0,0 +1,18 @@ +package at.petrak.hexcasting.api.casting.arithmetic.engine; + +public class InvalidOperatorException extends RuntimeException { + public InvalidOperatorException() { + } + + public InvalidOperatorException(String s) { + super(s); + } + + public InvalidOperatorException(String message, Throwable cause) { + super(message, cause); + } + + public InvalidOperatorException(Throwable cause) { + super(cause); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/NoOperatorCandidatesException.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/NoOperatorCandidatesException.java new file mode 100644 index 00000000..479b9bd0 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/engine/NoOperatorCandidatesException.java @@ -0,0 +1,23 @@ +package at.petrak.hexcasting.api.casting.arithmetic.engine; + +import at.petrak.hexcasting.api.casting.iota.Iota; +import at.petrak.hexcasting.api.casting.math.HexPattern; + +import java.util.List; + +public class NoOperatorCandidatesException extends RuntimeException { + HexPattern pattern; + List args; + + public NoOperatorCandidatesException(HexPattern pattern, List args) { + this.pattern = pattern; + this.args = args; + } + + public NoOperatorCandidatesException(HexPattern pattern, List args, String s) { + super(s); + this.pattern = pattern; + this.args = args; + } + +} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/DoubleArithmetic.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/DoubleArithmetic.java index 1035c79d..47fe2654 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/DoubleArithmetic.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/DoubleArithmetic.java @@ -7,16 +7,14 @@ import at.petrak.hexcasting.api.casting.arithmetic.operator.Operator; import at.petrak.hexcasting.api.casting.arithmetic.operator.OperatorBinary; import at.petrak.hexcasting.api.casting.arithmetic.operator.OperatorUnary; import at.petrak.hexcasting.api.casting.iota.DoubleIota; -import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import java.util.List; import java.util.function.DoubleBinaryOperator; import java.util.function.DoubleUnaryOperator; import static at.petrak.hexcasting.api.casting.arithmetic.operator.Operator.downcast; -import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.*; +import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.DOUBLE; public enum DoubleArithmetic implements Arithmetic { INSTANCE; @@ -47,16 +45,24 @@ public enum DoubleArithmetic implements Arithmetic { @Override public Operator getOperator(HexPattern pattern) { - switch (pattern) { - case ADD: return make2(Double::sum); - case SUB: return make2((p, q) -> p - q); - case MUL: return make2((p, q) -> p * q); - case DIV: return make2((p, q) -> p / q); - case ABS: return make1(Math::abs); - case POW: return make2(Math::pow); - case FLOOR: return make1(Math::floor); - case CEIL: return make1(Math::ceil); - case MOD: return make2((p, q) -> p % q); + if (pattern.equals(ADD)) { + return make2(Double::sum); + } else if (pattern.equals(SUB)) { + return make2((p, q) -> p - q); + } else if (pattern.equals(MUL)) { + return make2((p, q) -> p * q); + } else if (pattern.equals(DIV)) { + return make2((p, q) -> p / q); + } else if (pattern.equals(ABS)) { + return make1(Math::abs); + } else if (pattern.equals(POW)) { + return make2(Math::pow); + } else if (pattern.equals(FLOOR)) { + return make1(Math::floor); + } else if (pattern.equals(CEIL)) { + return make1(Math::ceil); + } else if (pattern.equals(MOD)) { + return make2((p, q) -> p % q); } return null; } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/Vec3Arithmetic.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/Vec3Arithmetic.java index cb14098d..1fbd0275 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/Vec3Arithmetic.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/impls/Vec3Arithmetic.java @@ -3,11 +3,18 @@ package at.petrak.hexcasting.api.casting.arithmetic.impls; import at.petrak.hexcasting.api.casting.arithmetic.Arithmetic; import at.petrak.hexcasting.api.casting.arithmetic.IotaMultiPredicate; import at.petrak.hexcasting.api.casting.arithmetic.IotaPredicate; +import at.petrak.hexcasting.api.casting.arithmetic.operator.*; +import at.petrak.hexcasting.api.casting.iota.DoubleIota; +import at.petrak.hexcasting.api.casting.iota.Vec3Iota; import at.petrak.hexcasting.api.casting.math.HexPattern; +import net.minecraft.world.phys.Vec3; import java.util.ArrayList; import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Function; +import static at.petrak.hexcasting.api.casting.arithmetic.operator.Operator.downcast; import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.*; public enum Vec3Arithmetic implements Arithmetic { @@ -31,28 +38,43 @@ public enum Vec3Arithmetic implements Arithmetic { } @Override - public Iterable opTypes() { + public Iterable opTypes() { return OPS; } @Override - public Operator getOperator(Symbol name) { - switch (name.inner()) { - case "pack": return OperatorPack.INSTANCE; - case "add": return make2(name, null); - case "sub": return make2(name, null); - case "mul": return make2(name, Vec3::dot); - case "div": return make2(name, Vec3::cross); - case "abs": return make1(Vec3::len); - case "pow": return make2(name, Vec3::proj); - case "mod": return make2(name, null); + public Operator getOperator(HexPattern pattern) { + if (pattern.equals(PACK)) { + return OperatorPack.INSTANCE; + } else if (pattern.equals(UNPACK)) { + return OperatorUnpack.INSTANCE; + } else if (pattern.equals(ADD)) { + return make2Fallback(pattern); + } else if (pattern.equals(SUB)) { + return make2Fallback(pattern); + } else if (pattern.equals(MUL)) { + return make2Double(pattern, Vec3::dot); + } else if (pattern.equals(DIV)) { + return make2Vec(pattern, Vec3::cross); + } else if (pattern.equals(ABS)) { + return make1Double(Vec3::length); + } else if (pattern.equals(POW)) { + return make2Vec(pattern, (u, v) -> v.normalize().scale(u.dot(v.normalize()))); + } else if (pattern.equals(MOD)) { + return make2Fallback(pattern); } return null; } - public static OperatorUnary make1(Function op) { - return new OperatorUnary(ACCEPTS, i -> new Iota(op.apply(i.downcast(Vec3.class)))); + public static OperatorUnary make1Double(Function op) { + return new OperatorUnary(ACCEPTS, i -> new DoubleIota(op.apply(downcast(i, VEC3).getVec3()))); } - public static OperatorVec3Delegating make2(Symbol name, BiFunction op) { - return new OperatorVec3Delegating(op, name); + public static OperatorVec3Delegating make2Fallback(HexPattern pattern) { + return new OperatorVec3Delegating(null, pattern); + } + public static OperatorVec3Delegating make2Double(HexPattern pattern, BiFunction op) { + return new OperatorVec3Delegating(op.andThen(DoubleIota::new), pattern); + } + public static OperatorVec3Delegating make2Vec(HexPattern pattern, BiFunction op) { + return new OperatorVec3Delegating(op.andThen(Vec3Iota::new), pattern); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/Operator.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/Operator.java index cd4e249c..0be915f0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/Operator.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/Operator.java @@ -3,7 +3,6 @@ package at.petrak.hexcasting.api.casting.arithmetic.operator; import at.petrak.hexcasting.api.casting.arithmetic.IotaMultiPredicate; import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.iota.IotaType; -import at.petrak.hexcasting.api.casting.mishaps.MishapInvalidIota; public abstract class Operator { public final int arity; @@ -15,7 +14,7 @@ public abstract class Operator { this.accepts = accepts; } - public abstract Iota apply(Iterable iotas); + public abstract Iterable apply(Iterable iotas); @SuppressWarnings("unchecked") public static T downcast(Iota iota, IotaType iotaType) { diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorBinary.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorBinary.java index f5eb41b6..af7aff8e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorBinary.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorBinary.java @@ -4,6 +4,7 @@ package at.petrak.hexcasting.api.casting.arithmetic.operator; import at.petrak.hexcasting.api.casting.arithmetic.IotaMultiPredicate; import at.petrak.hexcasting.api.casting.iota.Iota; +import java.util.List; import java.util.function.BinaryOperator; public class OperatorBinary extends Operator { @@ -15,8 +16,8 @@ public class OperatorBinary extends Operator { } @Override - public Iota apply(Iterable iotas) { + public Iterable apply(Iterable iotas) { var it = iotas.iterator(); - return inner.apply(it.next(), it.next()); + return List.of(inner.apply(it.next(), it.next())); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorPack.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorPack.java index 95dc3656..4e558c7b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorPack.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorPack.java @@ -8,6 +8,8 @@ import at.petrak.hexcasting.api.casting.iota.Vec3Iota; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import net.minecraft.world.phys.Vec3; +import java.util.List; + public class OperatorPack extends Operator { private OperatorPack() { super(3, IotaMultiPredicate.all(IotaPredicate.ofType(HexIotaTypes.DOUBLE))); @@ -16,12 +18,12 @@ public class OperatorPack extends Operator { public static OperatorPack INSTANCE = new OperatorPack(); @Override - public Iota apply(Iterable iotas) { + public Iterable apply(Iterable iotas) { var it = iotas.iterator(); - return new Vec3Iota(new Vec3( + return List.of(new Vec3Iota(new Vec3( downcast(it.next(), HexIotaTypes.DOUBLE).getDouble(), downcast(it.next(), HexIotaTypes.DOUBLE).getDouble(), downcast(it.next(), HexIotaTypes.DOUBLE).getDouble() - )); + ))); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnary.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnary.java index 550848ee..8ea1fa2a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnary.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnary.java @@ -4,6 +4,7 @@ package at.petrak.hexcasting.api.casting.arithmetic.operator; import at.petrak.hexcasting.api.casting.arithmetic.IotaMultiPredicate; import at.petrak.hexcasting.api.casting.iota.Iota; +import java.util.List; import java.util.function.UnaryOperator; public class OperatorUnary extends Operator { @@ -15,7 +16,7 @@ public class OperatorUnary extends Operator { } @Override - public Iota apply(Iterable iotas) { - return inner.apply(iotas.iterator().next()); + public Iterable apply(Iterable iotas) { + return List.of(inner.apply(iotas.iterator().next())); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnpack.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnpack.java new file mode 100644 index 00000000..b1faf7f0 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorUnpack.java @@ -0,0 +1,27 @@ +package at.petrak.hexcasting.api.casting.arithmetic.operator; + + +import at.petrak.hexcasting.api.casting.arithmetic.IotaMultiPredicate; +import at.petrak.hexcasting.api.casting.arithmetic.IotaPredicate; +import at.petrak.hexcasting.api.casting.iota.DoubleIota; +import at.petrak.hexcasting.api.casting.iota.Iota; +import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; + +import java.util.List; + +import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.VEC3; + +public class OperatorUnpack extends Operator { + private OperatorUnpack() { + super(1, IotaMultiPredicate.all(IotaPredicate.ofType(HexIotaTypes.DOUBLE))); + } + + public static OperatorUnpack INSTANCE = new OperatorUnpack(); + + @Override + public Iterable apply(Iterable iotas) { + var it = iotas.iterator(); + var vec = downcast(it.next(), VEC3).getVec3(); + return List.of(new DoubleIota(vec.x), new DoubleIota(vec.y), new DoubleIota(vec.z)); + } +} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorVec3Delegating.java b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorVec3Delegating.java index e0bec5b6..54cb332e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorVec3Delegating.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/arithmetic/operator/OperatorVec3Delegating.java @@ -3,42 +3,46 @@ package at.petrak.hexcasting.api.casting.arithmetic.operator; import at.petrak.hexcasting.api.casting.arithmetic.IotaMultiPredicate; import at.petrak.hexcasting.api.casting.arithmetic.IotaPredicate; import at.petrak.hexcasting.api.casting.arithmetic.IterPair; +import at.petrak.hexcasting.api.casting.arithmetic.TripleIterable; import at.petrak.hexcasting.api.casting.arithmetic.impls.DoubleArithmetic; import at.petrak.hexcasting.api.casting.iota.DoubleIota; import at.petrak.hexcasting.api.casting.iota.Iota; import at.petrak.hexcasting.api.casting.iota.Vec3Iota; import at.petrak.hexcasting.api.casting.math.HexPattern; -import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; -import kotlin.Pair; import net.minecraft.world.phys.Vec3; +import java.util.List; import java.util.Objects; import java.util.function.BiFunction; +import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.DOUBLE; +import static at.petrak.hexcasting.common.lib.hex.HexIotaTypes.VEC3; + public class OperatorVec3Delegating extends Operator { private final BiFunction op; private final Operator fb; public OperatorVec3Delegating(BiFunction core, HexPattern fallback) { - super(2, IotaMultiPredicate.any(IotaPredicate.ofType(HexIotaTypes.VEC3), IotaPredicate.ofType(HexIotaTypes.DOUBLE))); + super(2, IotaMultiPredicate.any(IotaPredicate.ofType(VEC3), IotaPredicate.ofType(DOUBLE))); op = core; fb = Objects.requireNonNull(DoubleArithmetic.INSTANCE.getOperator(fallback)); } @Override - public Iota apply(Iterable iotas) { + public Iterable apply(Iterable iotas) { var it = iotas.iterator(); var left = it.next(); var right = it.next(); if (op != null && left instanceof Vec3Iota lh && right instanceof Vec3Iota rh) { - return op.apply(lh.getVec3(), rh.getVec3()); + return List.of(op.apply(lh.getVec3(), rh.getVec3())); } - var lh = left instanceof Vec3Iota l ? l.getVec3() : triplicate(downcast(left, HexIotaTypes.DOUBLE).getDouble()); - var rh = right instanceof Vec3Iota r ? r.getVec3() : triplicate(downcast(right, HexIotaTypes.DOUBLE).getDouble()); - return new Vec3Iota(new Vec3( - downcast(fb.apply(new IterPair<>(new DoubleIota(lh.x()), new DoubleIota(rh.x()))), HexIotaTypes.DOUBLE).getDouble(), - downcast(fb.apply(new IterPair<>(new DoubleIota(lh.y()), new DoubleIota(rh.y()))), HexIotaTypes.DOUBLE).getDouble(), - downcast(fb.apply(new IterPair<>(new DoubleIota(lh.z()), new DoubleIota(rh.z()))), HexIotaTypes.DOUBLE).getDouble() - )); + var lh = left instanceof Vec3Iota l ? l.getVec3() : triplicate(downcast(left, DOUBLE).getDouble()); + var rh = right instanceof Vec3Iota r ? r.getVec3() : triplicate(downcast(right, DOUBLE).getDouble()); + return new TripleIterable<>( + fb.apply(new IterPair<>(new DoubleIota(lh.x()), new DoubleIota(rh.x()))), + fb.apply(new IterPair<>(new DoubleIota(lh.y()), new DoubleIota(rh.y()))), + fb.apply(new IterPair<>(new DoubleIota(lh.z()), new DoubleIota(rh.z()))), + (x, y, z) -> new Vec3Iota(new Vec3(downcast(x, DOUBLE).getDouble(), downcast(y, DOUBLE).getDouble(), downcast(y, DOUBLE).getDouble())) + ); } public static Vec3 triplicate(double in) { 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 de3d6b30..fb625e46 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 @@ -97,4 +97,9 @@ public abstract class Iota { public static boolean tolerates(Iota a, Iota b) { return a.toleratesOther(b) || b.toleratesOther(a); } + + @Override + public int hashCode() { + return payload.hashCode(); + } } 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 18b94041..47c9e28e 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 @@ -17,6 +17,7 @@ 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.HexArithmetics; import at.petrak.hexcasting.common.lib.hex.HexEvalSounds; import at.petrak.hexcasting.common.lib.hex.HexIotaTypes; import at.petrak.hexcasting.xplat.IXplatAbstractions; @@ -68,38 +69,43 @@ public class PatternIota extends Iota { 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); + var result = HexArithmetics.ENGINE.operate(this.getPattern(), vm.getEnv(), vm.getImage(), continuation); - 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; - } + if (result == null) { + var lookup = PatternRegistryManifest.matchPattern(this.getPattern(), world, false); + vm.getEnv().precheckAction(lookup); - var reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), key, - HexTags.Actions.REQUIRES_ENLIGHTENMENT); + 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; + } - castedName = HexAPI.instance().getActionI18n(key, reqsEnlightenment); + var reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.getActionRegistry(), key, + HexTags.Actions.REQUIRES_ENLIGHTENMENT); - 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(); + 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(); + + // do the actual calculation!! + result = action.operate( + vm.getEnv(), + vm.getImage(), + continuation + ); + } - // do the actual calculation!! - var result = action.operate( - vm.getEnv(), - vm.getImage(), - continuation - ); if (result.getNewImage().getOpsConsumed() > HexConfig.server().maxOpCount()) { throw new MishapEvalTooMuch(); } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInvalidIotas.kt b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInvalidIotas.kt new file mode 100644 index 00000000..34a13f7a --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/api/casting/mishaps/MishapInvalidIotas.kt @@ -0,0 +1,32 @@ +package at.petrak.hexcasting.api.casting.mishaps + +import at.petrak.hexcasting.api.casting.eval.CastingEnvironment +import at.petrak.hexcasting.api.casting.iota.GarbageIota +import at.petrak.hexcasting.api.casting.iota.Iota +import at.petrak.hexcasting.api.casting.math.HexPattern +import at.petrak.hexcasting.api.pigment.FrozenPigment +import net.minecraft.network.chat.ComponentContents +import net.minecraft.network.chat.MutableComponent +import net.minecraft.world.item.DyeColor + +/** + * The value failed some kind of predicate. + */ +class MishapInvalidOperatorArgs( + val perpetrators: List, + val operator: HexPattern +) : Mishap() { + override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenPigment = + dyeColor(DyeColor.GRAY) + + override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList) { + for (i in perpetrators.indices) { + stack[stack.size - 1 - i] = GarbageIota() + } + } + + override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = + error( + "invalid_operator_args", operator, perpetrators.fold(MutableComponent.create(ComponentContents.EMPTY)) { mc, iota -> mc.append(iota.display()) } + ) +} diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexArithmetics.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexArithmetics.java new file mode 100644 index 00000000..8f283e19 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/hex/HexArithmetics.java @@ -0,0 +1,9 @@ +package at.petrak.hexcasting.common.lib.hex; + +import at.petrak.hexcasting.api.casting.arithmetic.engine.ArithmeticEngine; +import at.petrak.hexcasting.api.casting.arithmetic.impls.DoubleArithmetic; +import at.petrak.hexcasting.api.casting.arithmetic.impls.Vec3Arithmetic; + +public class HexArithmetics { + public static ArithmeticEngine ENGINE = new ArithmeticEngine(DoubleArithmetic.INSTANCE, Vec3Arithmetic.INSTANCE); +}