From 71c3cade9b0664516590112ce5173cf45beff30d Mon Sep 17 00:00:00 2001 From: gamma-delta <29877714+gamma-delta@users.noreply.github.com> Date: Mon, 13 Jun 2022 22:02:50 -0500 Subject: [PATCH] and now for the part of the show where we refactor every single operator --- .../circle/BlockEntityAbstractImpetus.java | 4 +- .../hexcasting/api/spell/ConstManaOperator.kt | 10 +- .../petrak/hexcasting/api/spell/Operator.kt | 8 +- .../hexcasting/api/spell/OperatorUtils.kt | 205 +++++++++++++++--- .../at/petrak/hexcasting/api/spell/Widget.kt | 29 --- .../api/spell/casting/CastingHarness.kt | 26 +-- .../api/spell/casting/ContinuationFrame.kt | 4 +- .../hexcasting/api/spell/iota/EntityIota.java | 12 +- .../api/spell/iota/GarbageIota.java | 1 + .../hexcasting/api/spell/iota/Iota.java | 7 +- .../hexcasting/api/spell/iota/IotaType.java | 4 - .../hexcasting/api/spell/iota/ListIota.java | 7 +- .../hexcasting/api/spell/iota/NullIota.java | 2 + .../api/spell/mishaps/MishapDivideByZero.kt | 26 ++- .../api/spell/mishaps/MishapInvalidIota.kt | 43 ++-- .../petrak/hexcasting/api/utils/HexUtils.kt | 3 +- .../operators/spells/OpPotionEffect.kt | 2 +- .../hexcasting/common/items/ItemScroll.java | 9 +- .../hexcasting/common/lib/HexIotaTypes.java | 16 +- .../assets/hexcasting/lang/en_us.json | 4 +- 20 files changed, 275 insertions(+), 147 deletions(-) delete mode 100644 Common/src/main/java/at/petrak/hexcasting/api/spell/Widget.kt diff --git a/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java b/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java index 0a815b4f..20fa8906 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/block/circle/BlockEntityAbstractImpetus.java @@ -5,10 +5,10 @@ import at.petrak.hexcasting.api.misc.FrozenColorizer; import at.petrak.hexcasting.api.misc.ManaConstants; import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.api.spell.ParticleSpray; -import at.petrak.hexcasting.api.spell.iota.Iota; import at.petrak.hexcasting.api.spell.casting.CastingContext; import at.petrak.hexcasting.api.spell.casting.CastingHarness; import at.petrak.hexcasting.api.spell.casting.SpellCircleContext; +import at.petrak.hexcasting.api.spell.iota.PatternIota; import at.petrak.hexcasting.api.utils.ManaHelper; import at.petrak.hexcasting.common.lib.HexItems; import at.petrak.hexcasting.common.lib.HexSounds; @@ -287,7 +287,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen if (bs.getBlock() instanceof BlockCircleComponent cc) { var newPattern = cc.getPattern(tracked, bs, this.level); if (newPattern != null) { - var info = harness.executeIota(LegacySpellDatum.make(newPattern), splayer.getLevel()); + var info = harness.executeIota(new PatternIota(newPattern), splayer.getLevel()); if (info.getMakesCastSound()) { makeSound = true; } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt index a9f2770f..e8d19246 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/ConstManaOperator.kt @@ -1,8 +1,9 @@ package at.petrak.hexcasting.api.spell import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.casting.SpellContinuation import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect +import at.petrak.hexcasting.api.spell.casting.SpellContinuation +import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs /** @@ -15,7 +16,12 @@ interface ConstManaOperator : Operator { fun execute(args: List, ctx: CastingContext): List - override fun operate(continuation: SpellContinuation, stack: MutableList, local: Iota, ctx: CastingContext): OperationResult { + override fun operate( + continuation: SpellContinuation, + stack: MutableList, + local: Iota, + ctx: CastingContext + ): OperationResult { if (this.argc > stack.size) throw MishapNotEnoughArgs(this.argc, stack.size) val args = stack.takeLast(this.argc) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt index 96886c2b..8ec15b03 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt @@ -2,6 +2,7 @@ package at.petrak.hexcasting.api.spell import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.SpellContinuation +import at.petrak.hexcasting.api.spell.iota.Iota import net.minecraft.world.phys.Vec3 /** @@ -21,7 +22,12 @@ interface Operator { * * A particle effect at the cast site and various messages and advancements are done automagically. */ - fun operate(continuation: SpellContinuation, stack: MutableList, local: Iota, ctx: CastingContext): OperationResult + fun operate( + continuation: SpellContinuation, + stack: MutableList, + local: Iota, + ctx: CastingContext + ): OperationResult /** * Do you need to be enlightened to use this operator? (i.e. is this operator a Great Pattern) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/OperatorUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/OperatorUtils.kt index b02c6da2..af068d90 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/OperatorUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/OperatorUtils.kt @@ -2,6 +2,7 @@ package at.petrak.hexcasting.api.spell +import at.petrak.hexcasting.api.spell.iota.* import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs @@ -9,14 +10,20 @@ import at.petrak.hexcasting.api.utils.asTranslatedComponent import com.mojang.datafixers.util.Either import com.mojang.math.Vector3f import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.item.ItemEntity +import net.minecraft.world.entity.npc.Villager import net.minecraft.world.phys.Vec3 import kotlin.math.abs +import kotlin.math.roundToInt +import kotlin.math.roundToLong fun numOrVec(datum: Iota, reverseIdx: Int): Either = - when (datum.payload) { - is Double -> Either.left(datum.payload) - is Vec3 -> Either.right(datum.payload) + when (datum) { + is DoubleIota -> Either.left(datum.double) + is Vec3Iota -> Either.right(datum.vec3) else -> throw MishapInvalidIota( datum, reverseIdx, @@ -25,9 +32,9 @@ fun numOrVec(datum: Iota, reverseIdx: Int): Either = } fun numOrList(datum: Iota, reverseIdx: Int): Either = - when (datum.payload) { - is Double -> Either.left(datum.payload) - is SpellList -> Either.right(datum.payload) + when (datum) { + is DoubleIota -> Either.left(datum.double) + is ListIota -> Either.right(datum.list) else -> throw MishapInvalidIota( datum, reverseIdx, @@ -35,38 +42,176 @@ fun numOrList(datum: Iota, reverseIdx: Int): Either = ) } -fun spellListOf(vararg vs: Any): List { - val out = ArrayList(vs.size) - for (v in vs) { - out.add(LegacySpellDatum.make(v)) - } - return out -} - -inline fun List.getChecked(idx: Int, argc: Int = 0): T { +fun List.getDouble(idx: Int, argc: Int = 0): Double { val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } - if (x.payload is T) - return x.payload - else - throw MishapInvalidIota.ofClass(x, if (argc == 0) idx else argc - (idx + 1), T::class.java) + if (x is DoubleIota) { + return x.double + } else { + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "double") + } } +fun List.getEntity(idx: Int, argc: Int = 0): Entity { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is EntityIota) { + return x.entity + } else { + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity") + } +} -inline val Boolean.asSpellResult get() = spellListOf(if (this) 1.0 else 0.0) -inline val Double.asSpellResult get() = spellListOf(this) -inline val Number.asSpellResult get() = spellListOf(this.toDouble()) +fun List.getList(idx: Int, argc: Int = 0): SpellList { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is ListIota) { + return x.list + } else { + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "list") + } +} -inline val SpellList.asSpellResult get() = spellListOf(this) -inline val List.asSpellResult get() = spellListOf(this) +fun List.getPattern(idx: Int, argc: Int = 0): HexPattern { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is PatternIota) { + return x.pattern + } else { + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "pattern") + } +} -inline val Widget.asSpellResult get() = spellListOf(this) +fun List.getVec3(idx: Int, argc: Int = 0): Vec3 { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is Vec3Iota) { + return x.vec3 + } else { + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "vector") + } +} -inline val BlockPos.asSpellResult get() = spellListOf(Vec3.atCenterOf(this)) -inline val Vector3f.asSpellResult get() = spellListOf(Vec3(this)) -inline val Vec3.asSpellResult get() = spellListOf(this) +// Helpers -inline val Entity?.asSpellResult get() = spellListOf(this ?: Widget.NULL) -inline val HexPattern.asSpellResult get() = spellListOf(this) +fun List.getItemEntity(idx: Int, argc: Int = 0): ItemEntity { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is EntityIota) { + val e = x.entity + if (e is ItemEntity) + return e + } + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.item") +} + +fun List.getPlayer(idx: Int, argc: Int = 0): ServerPlayer { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is EntityIota) { + val e = x.entity + if (e is ServerPlayer) + return e + } + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.player") +} + +fun List.getVillager(idx: Int, argc: Int = 0): Villager { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is EntityIota) { + val e = x.entity + if (e is Villager) + return e + } + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.villager") +} + +fun List.getLivingEntity(idx: Int, argc: Int = 0): LivingEntity { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is EntityIota) { + val e = x.entity + if (e is LivingEntity) + return e + } + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.living") +} + +fun List.getPositiveDoubleB(idx: Int, argc: Int = 0): Double { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is DoubleIota) { + val double = x.double + if (0 <= double) { + return double + } + } + throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "double.positive") +} + +fun List.getDoubleBetween(idx: Int, min: Double, max: Double, argc: Int = 0): Double { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is DoubleIota) { + val double = x.double + if (double in min..max) { + return double + } + } + throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "double.between", min, max) +} + +fun List.getInt(idx: Int, argc: Int = 0): Int { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is DoubleIota) { + val double = x.double + val rounded = double.roundToInt() + if (abs(double - rounded) <= DoubleIota.TOLERANCE) { + return rounded + } + } + throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "int") +} + +fun List.getLong(idx: Int, argc: Int = 0): Long { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is DoubleIota) { + val double = x.double + val rounded = double.roundToLong() + if (abs(double - rounded) <= DoubleIota.TOLERANCE) { + return rounded + } + } + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "int") // shh we're lying +} + +fun List.getPositiveInt(idx: Int, argc: Int = 0): Int { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is DoubleIota) { + val double = x.double + val rounded = double.roundToInt() + if (abs(double - rounded) <= DoubleIota.TOLERANCE && rounded > 0) { + return rounded + } + } + throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "int.positive") +} + +fun List.getIntBetween(idx: Int, min: Int, max: Int, argc: Int = 0): Int { + val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) } + if (x is DoubleIota) { + val double = x.double + val rounded = double.roundToInt() + if (abs(double - rounded) <= DoubleIota.TOLERANCE && rounded in min..max) { + return rounded + } + } + throw MishapInvalidIota.of(x, if (argc == 0) idx else argc - (idx + 1), "double.between", min, max) +} + +inline val Boolean.asSpellResult get() = listOf(DoubleIota(if (this) 1.0 else 0.0)) +inline val Double.asSpellResult get() = listOf(DoubleIota(this)) +inline val Number.asSpellResult get() = listOf(DoubleIota(this.toDouble())) + +inline val SpellList.asSpellResult get() = listOf(ListIota(this)) +inline val List.asSpellResult get() = listOf(ListIota(this)) + +inline val BlockPos.asSpellResult get() = listOf(Vec3Iota(Vec3.atCenterOf(this))) +inline val Vector3f.asSpellResult get() = listOf(Vec3Iota(Vec3(this))) +inline val Vec3.asSpellResult get() = listOf(Vec3Iota(this)) + +inline val Entity?.asSpellResult get() = listOf(if (this == null) NullIota.INSTANCE else EntityIota(this)) +inline val HexPattern.asSpellResult get() = listOf(PatternIota(this)) private const val TOLERANCE = 0.0001 diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/Widget.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/Widget.kt deleted file mode 100644 index f8410df8..00000000 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/Widget.kt +++ /dev/null @@ -1,29 +0,0 @@ -package at.petrak.hexcasting.api.spell - -import at.petrak.hexcasting.api.spell.casting.CastingContext -import java.util.* - -/** - * Miscellaneous spell datums used as markers, etc. - * - * They act as operators that push themselves. - */ -enum class Widget : ConstManaOperator { - NULL, - OPEN_PAREN, CLOSE_PAREN, ESCAPE, - GARBAGE; - - override val argc: Int - get() = 0 - - override fun execute(args: List, ctx: CastingContext): List = - this.asSpellResult - - companion object { - @JvmStatic - fun fromString(key: String): Widget { - val lowercaseKey = key.lowercase(Locale.ROOT) - return values().firstOrNull { it.name.lowercase(Locale.ROOT) == lowercaseKey } ?: GARBAGE - } - } -} diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt index 16bffa03..18226506 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt @@ -8,8 +8,12 @@ import at.petrak.hexcasting.api.misc.HexDamageSources import at.petrak.hexcasting.api.mod.HexConfig import at.petrak.hexcasting.api.mod.HexItemTags import at.petrak.hexcasting.api.mod.HexStatistics -import at.petrak.hexcasting.api.spell.* +import at.petrak.hexcasting.api.spell.Operator +import at.petrak.hexcasting.api.spell.ParticleSpray +import at.petrak.hexcasting.api.spell.SpellList +import at.petrak.hexcasting.api.spell.Widget import at.petrak.hexcasting.api.spell.iota.Iota +import at.petrak.hexcasting.api.spell.iota.ListIota import at.petrak.hexcasting.api.spell.iota.NullIota import at.petrak.hexcasting.api.spell.iota.PatternIota import at.petrak.hexcasting.api.spell.math.HexDir @@ -17,6 +21,7 @@ import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.mishaps.* import at.petrak.hexcasting.api.utils.* import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker +import at.petrak.hexcasting.common.lib.HexIotaTypes import at.petrak.hexcasting.xplat.IXplatAbstractions import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.Tag @@ -240,7 +245,7 @@ class CastingHarness private constructor( } } - fun generateDescs() = stack.map { it.type.display(it) } + fun generateDescs() = stack.map(Iota::display) /** * Return the functional update represented by the current state (for use with `copy`) @@ -300,7 +305,7 @@ class CastingHarness private constructor( val newParenCount = this.parenCount - 1 if (newParenCount == 0) { val newStack = this.stack.toMutableList() - newStack.add(LegacySpellDatum.make(this.parenthesized.toList())) + newStack.add(ListIota(this.parenthesized.toList())) this.getFunctionalData().copy( stack = newStack, parenCount = newParenCount, @@ -438,7 +443,7 @@ class CastingHarness private constructor( fun serializeToNBT() = NBTBuilder { TAG_STACK %= stack.serializeToNBT() - TAG_LOCAL %= ravenmind.serializeToNBT() + TAG_LOCAL %= HexIotaTypes.serialize(ravenmind) TAG_PAREN_COUNT %= parenCount TAG_ESCAPE_NEXT %= escapeNext @@ -463,23 +468,16 @@ class CastingHarness private constructor( val stack = mutableListOf() val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND) for (subtag in stackTag) { - val datum = LegacySpellDatum.fromNBT(subtag.asCompound, ctx.world) + val datum = HexIotaTypes.deserialize(subtag.asCompound, ctx.world) stack.add(datum) } - val localTag = nbt.getCompound(TAG_LOCAL) - val localIota = - if (localTag.size() == 1) LegacySpellDatum.fromNBT(localTag, ctx.world) else LegacySpellDatum.make( - Widget.NULL - ) + val localIota = HexIotaTypes.deserialize(nbt.getCompound(TAG_LOCAL), ctx.world) val parenthesized = mutableListOf() val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND) for (subtag in parenTag) { - if (subtag.asCompound.size() != 1) - parenthesized.add(LegacySpellDatum.make(HexPattern.fromNBT(subtag.asCompound))) - else - parenthesized.add(LegacySpellDatum.fromNBT(subtag.asCompound, ctx.world)) + parenthesized.add(HexIotaTypes.deserialize(nbt.getCompound(TAG_LOCAL), ctx.world)) } val parenCount = nbt.getInt(TAG_PAREN_COUNT) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt index e810d0f3..071a74ae 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/ContinuationFrame.kt @@ -127,7 +127,7 @@ sealed interface ContinuationFrame { override fun breakDownwards(stack: List): Pair> { val newStack = baseStack?.toMutableList() ?: mutableListOf() acc.addAll(stack) - newStack.add(ListIota(SpellList.LList(acc))) + newStack.add(ListIota(acc)) return true to newStack } @@ -157,7 +157,7 @@ sealed interface ContinuationFrame { .pushFrame(Evaluate(code)) } else { // Else, dump our final list onto the stack. - ListIota(SpellList.LList(acc)) to continuation + ListIota(acc) to continuation } val tStack = stack.toMutableList() tStack.add(stackTop) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/EntityIota.java b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/EntityIota.java index 01a95186..05a389b0 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/EntityIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/EntityIota.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class EntityIota extends Iota { - protected EntityIota(@NotNull Entity e) { + public EntityIota(@NotNull Entity e) { super(HexIotaTypes.ENTITY, e); } @@ -36,6 +36,11 @@ public class EntityIota extends Iota { return out; } + @Override + public Component display() { + return this.getEntity().getName(); + } + public static IotaType TYPE = new IotaType<>() { @Nullable @Override @@ -65,11 +70,6 @@ public class EntityIota extends Iota { return Component.Serializer.fromJsonLenient(nameJson); } - @Override - public Component display(EntityIota iota) { - return iota.getEntity().getName(); - } - @Override public int color() { return 0; diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/GarbageIota.java b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/GarbageIota.java index fac3bfe9..275e79fa 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/GarbageIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/GarbageIota.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.Nullable; public class GarbageIota extends Iota { private static final Object NULL_SUBSTITUTE = new Object(); + public static final GarbageIota INSTANCE = new GarbageIota(); public GarbageIota() { // We have to pass *something* here, but there's nothing that actually needs to go there, diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/Iota.java b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/Iota.java index 298e814e..558e055e 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/Iota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/Iota.java @@ -2,13 +2,14 @@ package at.petrak.hexcasting.api.spell.iota; import at.petrak.hexcasting.common.lib.HexIotaTypes; import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; public abstract class Iota { @NotNull protected final Object payload; @NotNull - private final IotaType type; + protected final IotaType type; protected Iota(@NotNull IotaType type, @NotNull Object payload) { this.type = type; @@ -37,6 +38,10 @@ public abstract class Iota { */ abstract public @NotNull Tag serialize(); + public Component display() { + return this.type.display(this.serialize()); + } + /** * Helper method to see if two iotas have the same type. */ diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/IotaType.java b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/IotaType.java index 7426568b..6c864afd 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/IotaType.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/IotaType.java @@ -26,10 +26,6 @@ public abstract class IotaType { */ public abstract Component display(Tag tag); - public Component display(T iota) { - return this.display(iota.serialize()); - } - /** * Get the color associated with this datum type. */ diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/ListIota.java b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/ListIota.java index 3993dcae..32c44f8d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/ListIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/ListIota.java @@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.List; /** * This is a wrapper for {@link SpellList}. @@ -21,6 +22,10 @@ public class ListIota extends Iota { super(HexIotaTypes.LIST, list); } + public ListIota(@NotNull List list) { + this(new SpellList.LList(list)); + } + public SpellList getList() { return (SpellList) this.payload; } @@ -78,7 +83,7 @@ public class ListIota extends Iota { out.add(subiota); } - return new ListIota(new SpellList.LList(out)); + return new ListIota(out); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/NullIota.java b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/NullIota.java index 41122bef..86e25557 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/NullIota.java +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/iota/NullIota.java @@ -14,6 +14,8 @@ import org.jetbrains.annotations.Nullable; public class NullIota extends Iota { private static final Object NULL_SUBSTITUTE = new Object(); + public static final NullIota INSTANCE = new NullIota(); + public NullIota() { // We have to pass *something* here, but there's nothing that actually needs to go there, // so we just do this i guess diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapDivideByZero.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapDivideByZero.kt index 8694bc3c..a6a9fb65 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapDivideByZero.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapDivideByZero.kt @@ -2,9 +2,11 @@ package at.petrak.hexcasting.api.spell.mishaps import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.misc.HexDamageSources -import at.petrak.hexcasting.api.spell.iota.Iota -import at.petrak.hexcasting.api.spell.Widget import at.petrak.hexcasting.api.spell.casting.CastingContext +import at.petrak.hexcasting.api.spell.iota.DoubleIota +import at.petrak.hexcasting.api.spell.iota.GarbageIota +import at.petrak.hexcasting.api.spell.iota.Iota +import at.petrak.hexcasting.api.spell.iota.Vec3Iota import at.petrak.hexcasting.api.utils.asTranslatedComponent import net.minecraft.network.chat.Component import net.minecraft.world.item.DyeColor @@ -16,7 +18,7 @@ class MishapDivideByZero(val operand1: Component, val operand2: Component, val s dyeColor(DyeColor.RED) override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList) { - stack.add(LegacySpellDatum.make(Widget.GARBAGE)) + stack.add(GarbageIota.INSTANCE) trulyHurt(ctx.caster, HexDamageSources.OVERCAST, ctx.caster.health / 2) } @@ -27,14 +29,14 @@ class MishapDivideByZero(val operand1: Component, val operand2: Component, val s private const val PREFIX = "hexcasting.mishap.divide_by_zero" @JvmStatic - fun of(operand1: Any, operand2: Any, suffix: String = "divide"): MishapDivideByZero { + fun of(operand1: Iota, operand2: Iota, suffix: String = "divide"): MishapDivideByZero { if (suffix == "exponent") return MishapDivideByZero(translate(operand1), powerOf(operand2), suffix) return MishapDivideByZero(translate(operand1), translate(operand2), suffix) } @JvmStatic - fun tan(angle: Double): MishapDivideByZero { + fun tan(angle: DoubleIota): MishapDivideByZero { val translatedAngle = translate(angle) return MishapDivideByZero( "$PREFIX.sin".asTranslatedComponent(translatedAngle), @@ -58,16 +60,16 @@ class MishapDivideByZero(val operand1: Component, val operand2: Component, val s fun powerOf(power: Component) = "$PREFIX.power".asTranslatedComponent(power) @JvmStatic - fun powerOf(datum: Any) = when (datum) { - 0.0 -> zerothPower - else -> powerOf(LegacySpellDatum.make(datum).display()) + fun powerOf(datum: Iota): Component = when { + datum is DoubleIota && datum.double == 0.0 -> zerothPower + else -> datum.display() } @JvmStatic - fun translate(datum: Any): Component = when (datum) { - 0.0 -> zero - Vec3.ZERO -> zeroVector - else -> LegacySpellDatum.make(datum).display() + fun translate(datum: Iota): Component = when { + datum is DoubleIota && datum.double == 0.0 -> zero + datum is Vec3Iota && datum.vec3 == Vec3.ZERO -> zeroVector + else -> datum.display() } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt index 3fa0edac..fadd4551 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapInvalidIota.kt @@ -1,20 +1,12 @@ package at.petrak.hexcasting.api.spell.mishaps import at.petrak.hexcasting.api.misc.FrozenColorizer -import at.petrak.hexcasting.api.spell.iota.Iota -import at.petrak.hexcasting.api.spell.SpellList -import at.petrak.hexcasting.api.spell.Widget import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.math.HexPattern +import at.petrak.hexcasting.api.spell.iota.GarbageIota +import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.utils.asTranslatedComponent import net.minecraft.network.chat.Component -import net.minecraft.world.entity.Entity -import net.minecraft.world.entity.LivingEntity -import net.minecraft.world.entity.item.ItemEntity -import net.minecraft.world.entity.npc.Villager -import net.minecraft.world.entity.player.Player import net.minecraft.world.item.DyeColor -import net.minecraft.world.phys.Vec3 /** * The value failed some kind of predicate. @@ -30,32 +22,25 @@ class MishapInvalidIota( dyeColor(DyeColor.GRAY) override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList) { - stack[stack.size - 1 - reverseIdx] = LegacySpellDatum.make(Widget.GARBAGE) + stack[stack.size - 1 - reverseIdx] = GarbageIota.INSTANCE; } override fun errorMessage(ctx: CastingContext, errorCtx: Context) = - error("invalid_value", actionName(errorCtx.action), expected, reverseIdx, - perpetrator.display()) + error( + "invalid_value", actionName(errorCtx.action), expected, reverseIdx, + perpetrator.display() + ) companion object { @JvmStatic - fun ofClass(perpetrator: Iota, reverseIdx: Int, cls: Class<*>): MishapInvalidIota { - val key = "hexcasting.mishap.invalid_value.class." + when { - Double::class.java.isAssignableFrom(cls) || Double::class.javaObjectType.isAssignableFrom(cls) -> "double" - Vec3::class.java.isAssignableFrom(cls) -> "vector" - SpellList::class.java.isAssignableFrom(cls) -> "list" - Widget::class.java.isAssignableFrom(cls) -> "widget" - HexPattern::class.java.isAssignableFrom(cls) -> "pattern" + fun ofType(perpetrator: Iota, reverseIdx: Int, name: String): MishapInvalidIota { + return of(perpetrator, reverseIdx, "class.$name") + } - ItemEntity::class.java.isAssignableFrom(cls) -> "entity.item" - Player::class.java.isAssignableFrom(cls) -> "entity.player" - Villager::class.java.isAssignableFrom(cls) -> "entity.villager" - LivingEntity::class.java.isAssignableFrom(cls) -> "entity.living" - Entity::class.java.isAssignableFrom(cls) -> "entity" - - else -> "unknown" - } - return MishapInvalidIota(perpetrator, reverseIdx, key.asTranslatedComponent) + @JvmStatic + fun of(perpetrator: Iota, reverseIdx: Int, name: String, vararg translations: Any): MishapInvalidIota { + val key = "hexcasting.mishap.invalid_value.$name" + return MishapInvalidIota(perpetrator, reverseIdx, key.asTranslatedComponent(*translations)) } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt index 601514ff..abd08eb2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt @@ -2,7 +2,6 @@ package at.petrak.hexcasting.api.utils -import at.petrak.hexcasting.api.spell.SpellList import at.petrak.hexcasting.api.spell.iota.Iota import at.petrak.hexcasting.api.spell.iota.ListIota import at.petrak.hexcasting.api.spell.math.HexCoord @@ -237,7 +236,7 @@ fun Iterable.serializeToNBT() = if (HexIotaTypes.isTooLargeToSerialize(this)) ListTag() else - ListIota(SpellList.LList(this.toList())).serialize() + ListIota(this.toList()).serialize() // Copy the impl from forge fun ItemStack.serializeToNBT(): CompoundTag { diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPotionEffect.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPotionEffect.kt index 84679576..2c1dd6b2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPotionEffect.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpPotionEffect.kt @@ -25,7 +25,7 @@ class OpPotionEffect( ): Triple> { val target = args.getChecked(0, argc) if (target is ArmorStand) - throw MishapInvalidIota.ofClass(LegacySpellDatum.make(target), 0, LivingEntity::class.java) + throw MishapInvalidIota.ofType(LegacySpellDatum.make(target), 0, LivingEntity::class.java) val duration = max(args.getChecked(1, argc), 0.0) ctx.assertEntityInRange(target) val potency = if (this.allowPotency) diff --git a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java index 61fb19fb..b37f131b 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/items/ItemScroll.java @@ -1,12 +1,13 @@ package at.petrak.hexcasting.common.items; import at.petrak.hexcasting.api.item.IotaHolderItem; -import at.petrak.hexcasting.api.spell.DatumType; import at.petrak.hexcasting.api.spell.iota.Iota; +import at.petrak.hexcasting.api.spell.iota.PatternIota; import at.petrak.hexcasting.api.spell.math.HexPattern; import at.petrak.hexcasting.api.utils.NBTHelper; import at.petrak.hexcasting.client.gui.PatternTooltipGreeble; import at.petrak.hexcasting.common.entities.EntityWallScroll; +import at.petrak.hexcasting.common.lib.HexIotaTypes; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; @@ -54,14 +55,16 @@ public class ItemScroll extends Item implements IotaHolderItem { if (pattern == null) { return null; } + // We store only the data part of the iota; pretend the rest of it's there var out = new CompoundTag(); - out.put(LegacySpellDatum.TAG_PATTERN, pattern); + out.putString(HexIotaTypes.KEY_TYPE, "hexcasting:pattern"); + out.put(HexIotaTypes.KEY_DATA, pattern); return out; } @Override public boolean canWrite(ItemStack stack, Iota datum) { - return datum != null && datum.getType() == DatumType.PATTERN && !NBTHelper.hasCompound(stack, TAG_PATTERN); + return datum instanceof PatternIota && !NBTHelper.hasCompound(stack, TAG_PATTERN); } @Override diff --git a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexIotaTypes.java b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexIotaTypes.java index 4415293c..06eea6be 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/lib/HexIotaTypes.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/lib/HexIotaTypes.java @@ -14,10 +14,7 @@ import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -import java.util.ArrayDeque; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.function.BiConsumer; import static at.petrak.hexcasting.api.HexAPI.modLoc; @@ -112,7 +109,6 @@ public class HexIotaTypes { * } * */ - @Nullable public static Iota deserialize(CompoundTag tag, ServerLevel world) { var type = getTypeFromTag(tag); if (type == null) { @@ -122,10 +118,16 @@ public class HexIotaTypes { if (dataKey == null) { return null; } - return type.deserialize(tag, world); + Iota deserialized; + try { + deserialized = Objects.requireNonNullElse(type.deserialize(tag, world), NullIota.INSTANCE); + } catch (IllegalArgumentException exn) { + HexAPI.LOGGER.warn("Caught an exception deserializing an iota", exn); + deserialized = GarbageIota.INSTANCE; + } + return deserialized; } - @Nullable public static Component getDisplay(CompoundTag tag) { var type = getTypeFromTag(tag); if (type == null) { diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.json b/Common/src/main/resources/assets/hexcasting/lang/en_us.json index 267fc472..3aa9cd08 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.json @@ -386,8 +386,10 @@ "hexcasting.mishap.invalid_value.numvec": "a number or vector", "hexcasting.mishap.invalid_value.numlist": "a number or list", "hexcasting.mishap.invalid_value.list.pattern": "a list of patterns", - "hexcasting.mishap.invalid_value.int": "an integer", + "hexcasting.mishap.invalid_value.double.positive": "a positive number", "hexcasting.mishap.invalid_value.double.between": "a number between %d and %d", + "hexcasting.mishap.invalid_value.int": "an integer", + "hexcasting.mishap.invalid_value.int.positive": "a positive integer", "hexcasting.mishap.invalid_value.int.between": "an integer between %d and %d", "hexcasting.mishap.not_enough_args": "%s expected %s or more arguments but the stack was only %s tall", "hexcasting.mishap.too_many_close_parens": "Used Retrospection without first using Introspection",