diff --git a/src/main/java/at/petrak/hexcasting/api/cap/SpellHolder.java b/src/main/java/at/petrak/hexcasting/api/cap/SpellHolder.java index 23667a42..d92d40d1 100644 --- a/src/main/java/at/petrak/hexcasting/api/cap/SpellHolder.java +++ b/src/main/java/at/petrak/hexcasting/api/cap/SpellHolder.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.cap; -import at.petrak.hexcasting.api.spell.math.HexPattern; +import at.petrak.hexcasting.api.spell.SpellDatum; +import net.minecraft.server.level.ServerLevel; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -9,10 +10,12 @@ public interface SpellHolder { boolean canDrawManaFromInventory(); + boolean hasSpell(); + @Nullable - List getPatterns(); + List> getPatterns(ServerLevel level); - void writePatterns(List patterns, int mana); + void writePatterns(List> patterns, int mana); void clearPatterns(); } diff --git a/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java b/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java index cd15d519..8e21dd2f 100644 --- a/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java +++ b/src/main/java/at/petrak/hexcasting/api/circle/BlockEntityAbstractImpetus.java @@ -7,6 +7,7 @@ import at.petrak.hexcasting.api.mod.HexApiSounds; import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.api.player.HexPlayerDataHelper; import at.petrak.hexcasting.api.spell.ParticleSpray; +import at.petrak.hexcasting.api.spell.SpellDatum; import at.petrak.hexcasting.api.spell.casting.CastingContext; import at.petrak.hexcasting.api.spell.casting.CastingHarness; import at.petrak.hexcasting.api.spell.casting.SpellCircleContext; @@ -310,7 +311,7 @@ public abstract class BlockEntityAbstractImpetus extends PaucalBlockEntity imple if (bs.getBlock() instanceof BlockCircleComponent cc) { var newPattern = cc.getPattern(tracked, bs, this.level); if (newPattern != null) { - var info = harness.executeNewPattern(newPattern, splayer.getLevel()); + var info = harness.executeNewIota(SpellDatum.make(newPattern), splayer.getLevel()); if (info.getWasSpellCast()) { castSpell = true; if (info.getHasCastingSound()) { diff --git a/src/main/java/at/petrak/hexcasting/api/item/SpellHolderItem.java b/src/main/java/at/petrak/hexcasting/api/item/SpellHolderItem.java index 14b6d084..0d971ed2 100644 --- a/src/main/java/at/petrak/hexcasting/api/item/SpellHolderItem.java +++ b/src/main/java/at/petrak/hexcasting/api/item/SpellHolderItem.java @@ -1,6 +1,7 @@ package at.petrak.hexcasting.api.item; -import at.petrak.hexcasting.api.spell.math.HexPattern; +import at.petrak.hexcasting.api.spell.SpellDatum; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -10,10 +11,12 @@ public interface SpellHolderItem extends ManaHolderItem { boolean canDrawManaFromInventory(ItemStack stack); - @Nullable - List getPatterns(ItemStack stack); + boolean hasSpell(ItemStack stack); - void writePatterns(ItemStack stack, List patterns, int mana); + @Nullable + List> getSpell(ItemStack stack, ServerLevel level); + + void writePatterns(ItemStack stack, List> patterns, int mana); void clearPatterns(ItemStack stack); } diff --git a/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt b/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt index a6331c04..694567e0 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt @@ -9,15 +9,10 @@ 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.player.HexPlayerDataHelper -import at.petrak.hexcasting.api.spell.Operator -import at.petrak.hexcasting.api.spell.ParticleSpray -import at.petrak.hexcasting.api.spell.SpellDatum -import at.petrak.hexcasting.api.spell.Widget +import at.petrak.hexcasting.api.spell.* +import at.petrak.hexcasting.api.spell.math.HexDir import at.petrak.hexcasting.api.spell.math.HexPattern -import at.petrak.hexcasting.api.spell.mishaps.Mishap -import at.petrak.hexcasting.api.spell.mishaps.MishapDisallowedSpell -import at.petrak.hexcasting.api.spell.mishaps.MishapError -import at.petrak.hexcasting.api.spell.mishaps.MishapTooManyCloseParens +import at.petrak.hexcasting.api.spell.mishaps.* import at.petrak.hexcasting.api.utils.HexDamageSources import at.petrak.hexcasting.api.utils.ManaHelper import at.petrak.hexcasting.api.utils.asCompound @@ -39,7 +34,7 @@ class CastingHarness private constructor( var stack: MutableList>, var localIota: SpellDatum<*>, var parenCount: Int, - var parenthesized: List, + var parenthesized: List>, var escapeNext: Boolean, val ctx: CastingContext, val prepackagedColorizer: FrozenColorizer? // for trinkets with colorizers @@ -52,33 +47,46 @@ class CastingHarness private constructor( ) : this(mutableListOf(), SpellDatum.make(Widget.NULL), 0, mutableListOf(), false, ctx, prepackagedColorizer) /** - * Given a pattern, do all the updating/side effects/etc required. + * Given an iota, do all the updating/side effects/etc required. */ - fun executeNewPattern(newPat: HexPattern, world: ServerLevel): ControllerInfo { - val result = this.getUpdate(newPat, world) + fun executeNewIota(iota: SpellDatum<*>, world: ServerLevel): ControllerInfo { + val result = this.getUpdate(iota, world) this.applyFunctionalData(result.newData) return this.performSideEffects(result.sideEffects) } + fun getUpdate(iota: SpellDatum<*>, world: ServerLevel): CastResult { + // wouldn't it be nice to be able to go paren' + // i guess i'll call it paren2 + val paren2 = this.handleParentheses(iota) + if (paren2 != null) { + return CastResult( + paren2, + listOf() + ) + } + + return if (iota.getType() == DatumType.PATTERN) { + updateWithPattern(iota.payload as HexPattern, world) + } else { + CastResult( + this.getFunctionalData(), + listOf(OperatorSideEffect.DoMishap(MishapUnescapedValue(iota), + Mishap.Context(HexPattern(HexDir.WEST), null))), + ) + } + } + /** * When the server gets a packet from the client with a new pattern, * handle it functionally. */ - fun getUpdate(newPat: HexPattern, world: ServerLevel): CastResult { + fun updateWithPattern(newPat: HexPattern, world: ServerLevel): CastResult { if (this.ctx.spellCircle == null) this.ctx.caster.awardStat(HexStatistics.PATTERNS_DRAWN) var operatorIdPair: Pair? = null try { - // wouldn't it be nice to be able to go paren' - // i guess i'll call it paren2 - val paren2 = this.handleParentheses(newPat) - if (paren2 != null) { - return CastResult( - paren2, - listOf(), - ) - } // Don't catch this one operatorIdPair = PatternRegistry.matchPatternAndID(newPat, world) @@ -186,17 +194,19 @@ class CastingHarness private constructor( * Return a non-null value if we handled this in some sort of parenthesey way, * either escaping it onto the stack or changing the parenthese-handling state. */ - private fun handleParentheses(newPat: HexPattern): FunctionalData? { - val operator = try { - PatternRegistry.matchPattern(newPat, this.ctx.world) - } catch (mishap: Mishap) { - null + private fun handleParentheses(iota: SpellDatum<*>): FunctionalData? { + val operator = (iota.payload as? HexPattern)?.let { + try { + PatternRegistry.matchPattern(it, this.ctx.world) + } catch (mishap: Mishap) { + null + } } return if (this.parenCount > 0) { if (this.escapeNext) { val newParens = this.parenthesized.toMutableList() - newParens.add(newPat) + newParens.add(iota) this.getFunctionalData().copy( escapeNext = false, parenthesized = newParens @@ -208,7 +218,7 @@ class CastingHarness private constructor( } else if (operator == Widget.OPEN_PAREN) { // we have escaped the parens onto the stack; we just also record our count. val newParens = this.parenthesized.toMutableList() - newParens.add(newPat) + newParens.add(iota) this.getFunctionalData().copy( parenthesized = newParens, parenCount = this.parenCount + 1 @@ -217,7 +227,7 @@ class CastingHarness private constructor( val newParenCount = this.parenCount - 1 if (newParenCount == 0) { val newStack = this.stack.toMutableList() - newStack.add(SpellDatum.make(this.parenthesized.map { SpellDatum.make(it) })) + newStack.add(SpellDatum.make(this.parenthesized.toList())) this.getFunctionalData().copy( stack = newStack, parenCount = newParenCount, @@ -229,7 +239,7 @@ class CastingHarness private constructor( // we have this situation: "(()" // we need to add the close paren val newParens = this.parenthesized.toMutableList() - newParens.add(newPat) + newParens.add(iota) this.getFunctionalData().copy( parenCount = newParenCount, parenthesized = newParens @@ -237,14 +247,14 @@ class CastingHarness private constructor( } } else { val newParens = this.parenthesized.toMutableList() - newParens.add(newPat) + newParens.add(iota) this.getFunctionalData().copy( parenthesized = newParens ) } } else if (this.escapeNext) { val newStack = this.stack.toMutableList() - newStack.add(SpellDatum.make(newPat)) + newStack.add(iota) this.getFunctionalData().copy( stack = newStack, escapeNext = false, @@ -390,10 +400,13 @@ class CastingHarness private constructor( val localTag = nbt.getCompound(TAG_LOCAL) val localIota = SpellDatum.DeserializeFromNBT(localTag, ctx.world) - val parenthesized = mutableListOf() + val parenthesized = mutableListOf>() val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND) for (subtag in parenTag) { - parenthesized.add(HexPattern.DeserializeFromNBT(subtag.asCompound)) + if (subtag.asCompound.size() > 1) + parenthesized.add(SpellDatum.make(HexPattern.DeserializeFromNBT(subtag.asCompound))) + else + parenthesized.add(SpellDatum.DeserializeFromNBT(nbt, ctx.world)) } val parenCount = nbt.getInt(TAG_PAREN_COUNT) diff --git a/src/main/java/at/petrak/hexcasting/api/spell/casting/FunctionalData.kt b/src/main/java/at/petrak/hexcasting/api/spell/casting/FunctionalData.kt index 67c16de7..a5839e76 100644 --- a/src/main/java/at/petrak/hexcasting/api/spell/casting/FunctionalData.kt +++ b/src/main/java/at/petrak/hexcasting/api/spell/casting/FunctionalData.kt @@ -1,7 +1,6 @@ package at.petrak.hexcasting.api.spell.casting import at.petrak.hexcasting.api.spell.SpellDatum -import at.petrak.hexcasting.api.spell.math.HexPattern /** * A change to the data in a CastHarness after a pattern is drawn. @@ -11,7 +10,7 @@ import at.petrak.hexcasting.api.spell.math.HexPattern data class FunctionalData( val stack: List>, val parenCount: Int, - val parenthesized: List, + val parenthesized: List>, val escapeNext: Boolean, ) { /** diff --git a/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapUnescapedValue.kt b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapUnescapedValue.kt new file mode 100644 index 00000000..1de55c98 --- /dev/null +++ b/src/main/java/at/petrak/hexcasting/api/spell/mishaps/MishapUnescapedValue.kt @@ -0,0 +1,31 @@ +package at.petrak.hexcasting.api.spell.mishaps + +import at.petrak.hexcasting.api.misc.FrozenColorizer +import at.petrak.hexcasting.api.spell.DatumType +import at.petrak.hexcasting.api.spell.SpellDatum +import at.petrak.hexcasting.api.spell.Widget +import at.petrak.hexcasting.api.spell.casting.CastingContext +import net.minecraft.network.chat.Component +import net.minecraft.world.item.DyeColor + +/** + * The value was a naked iota without being Considered or Retrospected. + */ +class MishapUnescapedValue( + val perpetrator: SpellDatum<*> +) : Mishap() { + override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer = + dyeColor(DyeColor.GRAY) + + override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList>) { + val idx = stack.indexOfLast { it.getType() == DatumType.LIST } + if (idx != -1) + stack[idx] = SpellDatum.make(Widget.GARBAGE) + } + + override fun errorMessage(ctx: CastingContext, errorCtx: Context): Component = + error( + "unescaped", + perpetrator.display() + ) +} diff --git a/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java b/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java index 3c723880..3154d2d1 100644 --- a/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java +++ b/src/main/java/at/petrak/hexcasting/client/RegisterClientStuff.java @@ -277,7 +277,7 @@ public class RegisterClientStuff { private static void registerPackagedSpellOverrides(ItemPackagedSpell item) { ItemProperties.register(item, ItemPackagedSpell.HAS_PATTERNS_PRED, (stack, level, holder, holderID) -> - item.getPatterns(stack) != null ? 1f : 0f + item.hasSpell(stack) ? 1f : 0f ); } diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt index e29a59ac..f33acc1b 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpEval.kt @@ -7,9 +7,6 @@ import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingHarness import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect -import at.petrak.hexcasting.api.spell.math.HexPattern -import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota -import net.minecraft.network.chat.TranslatableComponent object OpEval : Operator { override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { @@ -23,13 +20,8 @@ object OpEval : Operator { val sideEffects = mutableListOf() - for (pat in instrs) { - val pattern = if (pat.payload is HexPattern) { - pat.payload - } else { - throw MishapInvalidIota(SpellDatum.make(instrs), 0, TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern")) - } - val res = harness.getUpdate(pattern, ctx.world) + for (insn in instrs) { + val res = harness.getUpdate(insn, ctx.world) sideEffects.addAll(res.sideEffects) if (res.sideEffects.any { it is OperatorSideEffect.DoMishap }) { break diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt index 2dffda08..22504c6d 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/eval/OpForEach.kt @@ -7,10 +7,7 @@ import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.CastingHarness import at.petrak.hexcasting.api.spell.casting.OperatorSideEffect -import at.petrak.hexcasting.api.spell.math.HexPattern -import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs -import net.minecraft.network.chat.TranslatableComponent object OpForEach : Operator { override fun operate(stack: MutableList>, local: SpellDatum<*>, ctx: CastingContext): OperationResult { @@ -33,17 +30,8 @@ object OpForEach : Operator { harness.stack.addAll(stack) harness.stack.add(subdatum) harness.localIota = localIota - for (pat in instrs) { - val pattern = if (pat.payload is HexPattern) { - pat.payload - } else { - throw MishapInvalidIota( - SpellDatum.make(instrs), - 1, - TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern") - ) - } - val res = harness.getUpdate(pattern, ctx.world) + for (insn in instrs) { + val res = harness.getUpdate(insn, ctx.world) sideEffects.addAll(res.sideEffects) if (res.sideEffects.any { it is OperatorSideEffect.DoMishap }) { return OperationResult(harness.stack, harness.localIota, sideEffects) diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpErase.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpErase.kt index 51949fa7..852f5339 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpErase.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpErase.kt @@ -20,13 +20,13 @@ class OpErase : SpellOperator { val spellHolder = HexCapabilities.getCapability(it, HexCapabilities.SPELL) val datumHolder = HexCapabilities.getCapability(it, HexCapabilities.DATUM) - (spellHolder.isPresent && spellHolder.get().patterns != null) || + (spellHolder.isPresent && spellHolder.get().hasSpell()) || (datumHolder.isPresent && datumHolder.get().writeDatum(null, true)) } val spellHolder = HexCapabilities.getCapability(handStack, HexCapabilities.SPELL) val datumHolder = HexCapabilities.getCapability(handStack, HexCapabilities.DATUM) - if ((!spellHolder.isPresent || spellHolder.get().patterns == null) && + if ((!spellHolder.isPresent || !spellHolder.get().hasSpell()) && (!datumHolder.isPresent || datumHolder.get().readDatum(ctx.world) == null || !datumHolder.get().writeDatum(null, true))) { throw MishapBadOffhandItem.of(handStack, hand, "eraseable") @@ -41,13 +41,13 @@ class OpErase : SpellOperator { val spellHolder = HexCapabilities.getCapability(it, HexCapabilities.SPELL) val datumHolder = HexCapabilities.getCapability(it, HexCapabilities.DATUM) - (spellHolder.isPresent && spellHolder.get().patterns != null) || + (spellHolder.isPresent && spellHolder.get().hasSpell()) || (datumHolder.isPresent && datumHolder.get().writeDatum(null, true)) } val spellHolder = HexCapabilities.getCapability(handStack, HexCapabilities.SPELL) val datumHolder = HexCapabilities.getCapability(handStack, HexCapabilities.DATUM) - if (spellHolder.isPresent && spellHolder.get().patterns != null) + if (spellHolder.isPresent && spellHolder.get().hasSpell()) spellHolder.get().clearPatterns() if (datumHolder.isPresent && datumHolder.get().writeDatum(null, true)) diff --git a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpMakePackagedSpell.kt b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpMakePackagedSpell.kt index 70ee955c..d095e4e1 100644 --- a/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpMakePackagedSpell.kt +++ b/src/main/java/at/petrak/hexcasting/common/casting/operators/spells/OpMakePackagedSpell.kt @@ -7,13 +7,10 @@ import at.petrak.hexcasting.api.spell.RenderedSpell import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.SpellOperator import at.petrak.hexcasting.api.spell.casting.CastingContext -import at.petrak.hexcasting.api.spell.math.HexPattern import at.petrak.hexcasting.api.spell.mishaps.MishapBadItem import at.petrak.hexcasting.api.spell.mishaps.MishapBadOffhandItem -import at.petrak.hexcasting.api.spell.mishaps.MishapInvalidIota import at.petrak.hexcasting.api.utils.ManaHelper import at.petrak.hexcasting.common.items.magic.ItemPackagedSpell -import net.minecraft.network.chat.TranslatableComponent import net.minecraft.world.entity.item.ItemEntity class OpMakePackagedSpell(val itemType: T, val cost: Int) : SpellOperator { @@ -23,18 +20,17 @@ class OpMakePackagedSpell(val itemType: T, val cost: Int) ctx: CastingContext ): Triple> { val entity = args.getChecked(0) - val patternsRaw = args.getChecked>>(1) + val patterns = args.getChecked>>(1) - val patterns = patternsRaw.map { - if (it.payload is HexPattern) - it.payload - else - throw MishapInvalidIota(SpellDatum.make(patternsRaw), 0, TranslatableComponent("hexcasting.mishap.invalid_value.list.pattern")) + val (handStack, hand) = ctx.getHeldItemToOperateOn { + val spellHolder = HexCapabilities.getCapability(it, HexCapabilities.SPELL) + it.`is`(itemType) && spellHolder.isPresent && !spellHolder.get().hasSpell() } - - val (handStack, hand) = ctx.getHeldItemToOperateOn { it.`is`(itemType) } + val spellHolder = HexCapabilities.getCapability(handStack, HexCapabilities.SPELL) if (!handStack.`is`(itemType)) { throw MishapBadOffhandItem(handStack, hand, itemType.description) + } else if (spellHolder.get().hasSpell()) { + throw MishapBadOffhandItem.of(handStack, hand, "iota.write") } ctx.assertEntityInRange(entity) @@ -53,12 +49,12 @@ class OpMakePackagedSpell(val itemType: T, val cost: Int) return Triple(Spell(entity, patterns), cost, listOf(ParticleSpray.Burst(entity.position(), 0.5))) } - private inner class Spell(val itemEntity: ItemEntity, val patterns: List) : RenderedSpell { + private inner class Spell(val itemEntity: ItemEntity, val patterns: List>) : RenderedSpell { override fun cast(ctx: CastingContext) { val (handStack) = ctx.getHeldItemToOperateOn { it.`is`(itemType) } val spellHolder = HexCapabilities.getCapability(handStack, HexCapabilities.SPELL) if (spellHolder.isPresent - && spellHolder.get().patterns == null + && !spellHolder.get().hasSpell() && itemEntity.isAlive ) { val entityStack = itemEntity.item.copy() diff --git a/src/main/java/at/petrak/hexcasting/common/items/magic/ItemPackagedSpell.java b/src/main/java/at/petrak/hexcasting/common/items/magic/ItemPackagedSpell.java index 72c17c91..b7d03e3c 100644 --- a/src/main/java/at/petrak/hexcasting/common/items/magic/ItemPackagedSpell.java +++ b/src/main/java/at/petrak/hexcasting/common/items/magic/ItemPackagedSpell.java @@ -2,6 +2,7 @@ package at.petrak.hexcasting.common.items.magic; import at.petrak.hexcasting.HexMod; import at.petrak.hexcasting.api.item.SpellHolderItem; +import at.petrak.hexcasting.api.spell.SpellDatum; import at.petrak.hexcasting.api.spell.casting.CastingContext; import at.petrak.hexcasting.api.spell.casting.CastingHarness; import at.petrak.hexcasting.api.utils.NBTHelper; @@ -11,6 +12,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stat; @@ -50,23 +52,32 @@ public abstract class ItemPackagedSpell extends ItemManaHolder implements SpellH } @Override - public @Nullable List getPatterns(ItemStack stack) { + public boolean hasSpell(ItemStack stack) { + return NBTHelper.hasCompound(stack, TAG_PATTERNS); + } + + @Override + public @Nullable List> getSpell(ItemStack stack, ServerLevel level) { var patsTag = NBTHelper.getList(stack, TAG_PATTERNS, Tag.TAG_COMPOUND); if (patsTag == null) return null; - var out = new ArrayList(); + var out = new ArrayList>(); for (var patTag : patsTag) { - out.add(HexPattern.DeserializeFromNBT((CompoundTag) patTag)); + CompoundTag tag = NBTHelper.getAsCompound(patTag); + if (tag.size() > 1) + out.add(SpellDatum.make(HexPattern.DeserializeFromNBT(tag))); + else + out.add(SpellDatum.DeserializeFromNBT(tag, level)); } return out; } @Override - public void writePatterns(ItemStack stack, List patterns, int mana) { + public void writePatterns(ItemStack stack, List> patterns, int mana) { ListTag patsTag = new ListTag(); - for (HexPattern pat : patterns) + for (SpellDatum pat : patterns) patsTag.add(pat.serializeToNBT()); NBTHelper.putList(stack, TAG_PATTERNS, patsTag); @@ -83,19 +94,23 @@ public abstract class ItemPackagedSpell extends ItemManaHolder implements SpellH @Override public InteractionResultHolder use(Level world, Player player, InteractionHand usedHand) { var stack = player.getItemInHand(usedHand); - List patterns = getPatterns(stack); - if (patterns == null) { + if (!hasSpell(stack)) { return InteractionResultHolder.fail(stack); } if (world.isClientSide) { return InteractionResultHolder.success(stack); } + + List> instrs = getSpell(stack, (ServerLevel) world); + if (instrs == null) { + return InteractionResultHolder.fail(stack); + } var sPlayer = (ServerPlayer) player; var ctx = new CastingContext(sPlayer, usedHand); var harness = new CastingHarness(ctx); - for (var pattern : patterns) { - var info = harness.executeNewPattern(pattern, sPlayer.getLevel()); + for (var insn : instrs) { + var info = harness.executeNewIota(insn, sPlayer.getLevel()); if (info.getWasPrevPatternInvalid()) { break; } diff --git a/src/main/java/at/petrak/hexcasting/common/lib/HexCapabilityHandler.java b/src/main/java/at/petrak/hexcasting/common/lib/HexCapabilityHandler.java index 69408690..68cc3091 100644 --- a/src/main/java/at/petrak/hexcasting/common/lib/HexCapabilityHandler.java +++ b/src/main/java/at/petrak/hexcasting/common/lib/HexCapabilityHandler.java @@ -1,15 +1,13 @@ package at.petrak.hexcasting.common.lib; -import at.petrak.hexcasting.api.cap.Colorizer; -import at.petrak.hexcasting.api.cap.DataHolder; -import at.petrak.hexcasting.api.cap.ManaHolder; -import at.petrak.hexcasting.api.cap.SpellHolder; +import at.petrak.hexcasting.api.cap.*; +import at.petrak.hexcasting.api.item.ColorizerItem; +import at.petrak.hexcasting.api.item.DataHolderItem; +import at.petrak.hexcasting.api.item.ManaHolderItem; +import at.petrak.hexcasting.api.item.SpellHolderItem; import at.petrak.hexcasting.api.mod.HexConfig; -import at.petrak.hexcasting.api.item.*; import at.petrak.hexcasting.api.spell.SpellDatum; -import at.petrak.hexcasting.api.cap.HexCapabilities; import at.petrak.hexcasting.common.items.HexItems; -import at.petrak.hexcasting.api.spell.math.HexPattern; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; @@ -18,7 +16,9 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.ForgeConfigSpec; -import net.minecraftforge.common.capabilities.*; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.NonNullSupplier; import net.minecraftforge.event.AttachCapabilitiesEvent; @@ -51,44 +51,48 @@ public class HexCapabilityHandler { public static void attachCaps(AttachCapabilitiesEvent evt) { ItemStack stack = evt.getObject(); if (stack.getItem() instanceof ManaHolderItem holder) - evt.addCapability(MANA_HOLDER_CAPABILITY, provide(HexCapabilities.MANA, + evt.addCapability(MANA_HOLDER_CAPABILITY, provide(stack, HexCapabilities.MANA, () -> new ItemBasedManaHolder(holder, stack))); else if (stack.is(HexItems.AMETHYST_DUST.get())) - evt.addCapability(MANA_ITEM_CAPABILITY, provide(HexCapabilities.MANA, + evt.addCapability(MANA_ITEM_CAPABILITY, provide(stack, HexCapabilities.MANA, () -> new StaticManaHolder(HexConfig.dustManaAmount, 3, stack))); else if (stack.is(Items.AMETHYST_SHARD)) - evt.addCapability(MANA_ITEM_CAPABILITY, provide(HexCapabilities.MANA, + evt.addCapability(MANA_ITEM_CAPABILITY, provide(stack, HexCapabilities.MANA, () -> new StaticManaHolder(HexConfig.shardManaAmount, 2, stack))); else if (stack.is(HexItems.CHARGED_AMETHYST.get())) - evt.addCapability(MANA_ITEM_CAPABILITY, provide(HexCapabilities.MANA, + evt.addCapability(MANA_ITEM_CAPABILITY, provide(stack, HexCapabilities.MANA, () -> new StaticManaHolder(HexConfig.chargedCrystalManaAmount, 1, stack))); if (stack.getItem() instanceof DataHolderItem holder) - evt.addCapability(DATA_HOLDER_CAPABILITY, provide(HexCapabilities.DATUM, + evt.addCapability(DATA_HOLDER_CAPABILITY, provide(stack, HexCapabilities.DATUM, () -> new ItemBasedDataHolder(holder, stack))); else if (stack.is(Items.PUMPKIN_PIE)) // haha yes - evt.addCapability(DATA_ITEM_CAPABILITY, provide(HexCapabilities.DATUM, + evt.addCapability(DATA_ITEM_CAPABILITY, provide(stack, HexCapabilities.DATUM, () -> new StaticDatumHolder((s) -> SpellDatum.make(Math.PI * s.getCount()), stack))); if (stack.getItem() instanceof SpellHolderItem holder) - evt.addCapability(SPELL_HOLDER_CAPABILITY, provide(HexCapabilities.SPELL, + evt.addCapability(SPELL_HOLDER_CAPABILITY, provide(stack, HexCapabilities.SPELL, () -> new ItemBasedSpellHolder(holder, stack))); if (stack.getItem() instanceof ColorizerItem colorizer) - evt.addCapability(COLORIZER_CAPABILITY, provide(HexCapabilities.COLOR, + evt.addCapability(COLORIZER_CAPABILITY, provide(stack, HexCapabilities.COLOR, () -> new ItemBasedColorizer(colorizer, stack))); } - private static SimpleProvider provide(Capability capability, NonNullSupplier supplier) { - return new SimpleProvider<>(capability, LazyOptional.of(supplier)); + private static SimpleProvider provide(ItemStack stack, Capability capability, NonNullSupplier supplier) { + return new SimpleProvider<>(stack, capability, LazyOptional.of(supplier)); } - private record SimpleProvider(Capability capability, + private record SimpleProvider(ItemStack stack, + Capability capability, LazyOptional instance) implements ICapabilityProvider { @NotNull @Override public LazyOptional getCapability(@NotNull Capability cap, @Nullable Direction side) { + if (stack.isEmpty()) + return LazyOptional.empty(); + return cap == capability ? instance.cast() : LazyOptional.empty(); } } @@ -245,12 +249,17 @@ public class HexCapabilityHandler { } @Override - public @Nullable List getPatterns() { - return holder.getPatterns(stack); + public boolean hasSpell() { + return holder.hasSpell(stack); } @Override - public void writePatterns(List patterns, int mana) { + public @Nullable List> getPatterns(ServerLevel level) { + return holder.getSpell(stack, level); + } + + @Override + public void writePatterns(List> patterns, int mana) { holder.writePatterns(stack, patterns, mana); } diff --git a/src/main/java/at/petrak/hexcasting/common/network/MsgNewSpellPatternSyn.java b/src/main/java/at/petrak/hexcasting/common/network/MsgNewSpellPatternSyn.java index e9419c0f..45499214 100644 --- a/src/main/java/at/petrak/hexcasting/common/network/MsgNewSpellPatternSyn.java +++ b/src/main/java/at/petrak/hexcasting/common/network/MsgNewSpellPatternSyn.java @@ -1,12 +1,13 @@ package at.petrak.hexcasting.common.network; +import at.petrak.hexcasting.api.mod.HexItemTags; import at.petrak.hexcasting.api.player.HexPlayerDataHelper; +import at.petrak.hexcasting.api.spell.SpellDatum; import at.petrak.hexcasting.api.spell.casting.ControllerInfo; import at.petrak.hexcasting.api.spell.casting.ResolvedPattern; import at.petrak.hexcasting.api.spell.casting.ResolvedPatternValidity; import at.petrak.hexcasting.api.spell.math.HexCoord; import at.petrak.hexcasting.api.spell.math.HexPattern; -import at.petrak.hexcasting.api.mod.HexItemTags; import at.petrak.hexcasting.common.lib.HexSounds; import io.netty.buffer.ByteBuf; import net.minecraft.network.FriendlyByteBuf; @@ -74,7 +75,7 @@ public record MsgNewSpellPatternSyn(InteractionHand handUsed, HexPattern pattern if (autoFail) { clientInfo = new ControllerInfo(false, false, harness.getStack().isEmpty(), true, harness.generateDescs()); } else { - clientInfo = harness.executeNewPattern(this.pattern, sender.getLevel()); + clientInfo = harness.executeNewIota(SpellDatum.make(this.pattern), sender.getLevel()); if (clientInfo.getWasSpellCast() && clientInfo.getHasCastingSound()) { sender.level.playSound(null, sender.getX(), sender.getY(), sender.getZ(), diff --git a/src/main/resources/assets/hexcasting/lang/en_us.json b/src/main/resources/assets/hexcasting/lang/en_us.json index 935cd4fd..9df4f79f 100644 --- a/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/src/main/resources/assets/hexcasting/lang/en_us.json @@ -336,6 +336,7 @@ "hexcasting.spell.unknown": "Special Handler", "hexcasting.mishap.invalid_pattern": "That pattern isn't associated with any action", + "hexcasting.mishap.unescaped": "Expected to evaluate a pattern, but evaluated %s instead", "hexcasting.mishap.invalid_value": "%s expected %s at index %s of the stack, but got %s", "hexcasting.mishap.invalid_value.class.double": "a number", "hexcasting.mishap.invalid_value.class.vector": "a vector",