aaaaaugh. also document things

This commit is contained in:
petrak@ 2023-02-04 11:35:26 -06:00
parent 117fbfb781
commit 24367669e5
39 changed files with 483 additions and 515 deletions

View file

@ -2,7 +2,7 @@ Hello, intrepid Github reader!
The "flavor text" words for things in this mod and the internal names are different. (Sorry.)
- A "Hex" is a `Cast`, cast through a [`CastingHarness`](api/casting/eval/CastingHarness.kt)
- A "Hex" is a `Cast`, cast through a [`CastingHarness`](api/casting/eval/vm/CastingVM.kt)
- A "Pattern" is a [`HexPattern`](api/casting/math/HexPattern.kt)
- An "Action" is an [`Operator`](api/casting/castables/Action.kt)
- An action that pushes a spell is a [`Spell`](api/casting/castables/SpellAction.kt)

View file

@ -108,6 +108,11 @@ public interface HexAPI {
return FrozenColorizer.DEFAULT.get();
}
/**
* Location in the userdata of the ravenmind
*/
ResourceLocation RAVENMIND_USERDATA = modLoc("ravenmind");
static HexAPI instance() {
return INSTANCE.get();
}

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.api.addldata;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import org.jetbrains.annotations.Nullable;
@ -14,7 +14,7 @@ public interface ADIotaHolder {
default Iota readIota(ServerLevel world) {
var tag = readIotaTag();
if (tag != null) {
return HexIotaTypes.deserialize(tag, world);
return IotaType.deserialize(tag, world);
} else {
return null;
}

View file

@ -1,14 +1,14 @@
package at.petrak.hexcasting.api.block.circle;
import at.petrak.hexcasting.api.block.HexBlockEntity;
import at.petrak.hexcasting.api.casting.ParticleSpray;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.SpellCircleContext;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import at.petrak.hexcasting.api.casting.iota.PatternIota;
import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.misc.MediaConstants;
import at.petrak.hexcasting.api.mod.HexConfig;
import at.petrak.hexcasting.api.casting.ParticleSpray;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.SpellCircleContext;
import at.petrak.hexcasting.api.casting.iota.PatternIota;
import at.petrak.hexcasting.api.utils.MediaHelper;
import at.petrak.hexcasting.common.items.magic.ItemCreativeUnlocker;
import at.petrak.hexcasting.common.lib.HexItems;
@ -284,7 +284,7 @@ public abstract class BlockEntityAbstractImpetus extends HexBlockEntity implemen
var ctx = new CastingEnvironment(splayer, InteractionHand.MAIN_HAND,
new SpellCircleContext(this.getBlockPos(), bounds, this.activatorAlwaysInRange()));
var harness = new CastingHarness(ctx);
var harness = new CastingVM(ctx);
BlockPos erroredPos = null;
for (var tracked : this.trackedBlocks) {
@ -292,7 +292,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(new PatternIota(newPattern), splayer.getLevel());
var info = harness.queueAndExecuteIota(new PatternIota(newPattern), splayer.getLevel());
if (!info.getResolutionType().getSuccess()) {
erroredPos = tracked;
break;

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.api.casting.eval;
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
import at.petrak.hexcasting.api.casting.ParticleSpray;
import at.petrak.hexcasting.api.casting.PatternShapeMatch;
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
import at.petrak.hexcasting.api.casting.mishaps.MishapDisallowedSpell;
import at.petrak.hexcasting.api.casting.mishaps.MishapEntityTooFarAway;
@ -9,7 +9,6 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway;
import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexConfig;
import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
@ -57,7 +56,7 @@ public abstract class CastingEnvironment {
* <p>
* This is used for stuff like requiring enlightenment and pattern denylists
*/
public void precheckAction(ResourceKey<ActionRegistryEntry> key) throws Mishap {
public void precheckAction(PatternShapeMatch match) throws Mishap {
if (!HexConfig.server().isActionAllowed(key.location())) {
throw new MishapDisallowedSpell();
}

View file

@ -1,16 +0,0 @@
package at.petrak.hexcasting.api.casting.eval
import net.minecraft.nbt.CompoundTag
/**
* Information for the sake of the GUI.
*/
data class ControllerInfo(
val isStackClear: Boolean,
val resolutionType: ResolvedPatternType,
val stack: List<CompoundTag>,
val parenthesized: List<CompoundTag>,
val ravenmind: CompoundTag?,
val parenCount: Int,
)

View file

@ -0,0 +1,15 @@
package at.petrak.hexcasting.api.casting.eval
import net.minecraft.network.chat.Component
/**
* Information sent back to the client
*/
data class ExecutionClientView(
val isStackClear: Boolean,
val resolutionType: ResolvedPatternType,
val stackDescs: List<Component>,
val ravenmind: Component?,
)

View file

@ -0,0 +1,74 @@
# How Casting Works
because I keep forgetting.
- [`CastingVM`][] is the casting virtual machine. It is what figures out what to do with an incoming iota to be
executed,
producing a functional state update. This is transient and is reconstructed every time the whole state needs to be
saved and loaded.
- [`CastingImage`][] is the state of the cast itself. If [`CastingVM`][] is an emulator, [`CastingImage`][] is a
snapshot of the
emulator's memory. This is the only thing serialized to NBT.
- [`CastingEnvironment`][] is what is doing the casting, abstractly. Stuff like "the player with a staff," "the player
with a trinket," "a spell circle." This is an abstract class that Hexcasting (and addons!) make subclasses of.
## Beware The Pipeline
1. An iota or list of iotas come to be executed. This is the entrypoint to the VM,
`CastingVM#queueAndExecuteIotas`, and returns an [`ExecutionClientView`][] (might change later).
2. Those iotas are put into a [`ContinuationFrame`][] (specifically, [`FrameEvaluate`][]).
3. While there are still frames, control flows to the top one.
4. The frame (usually) returns control flow back to the VM by calling `CastingVM#executeInner` with an iota.
5. `executeInner` first does some pre-checks with intro/retro/consideration (like escaping embedded iotas), but usually
makes sure that the passed iota is a pattern and passes *that* on to `executePattern`.
6. `executePattern` is where the execution actually happens. The pattern is matched to an action or special handler.
and executed.
7. That execution doesn't mutate anything, but returns a [`CastResult`]. It contains:
- the rest of the current continuation (read as: the patterns to execute next);
- the updated state of the [`CastingImage`];
- a list of `OperatorSideEffects`, like withdrawing media, casting spells or mishaping;
- misc display info like the color the pattern should be when drawn to the staff GUI and the sound.
8. Each of the side effects is applied to the world in turn. If any of them make the casting stop (like mishaping),
then it does!
9. If there's still iotas left in the current continuation, then control goes back to step 5, called on the next iota in
continuation.
10. Otherwise, control goes to the top frame of the stack (step 3). And if there are no stack frames, execution is
finished! What a ride.
## The Hell's A Continuation And A Continuation Frame
IDFK ask Alwinfy.
But as I understand it, a [continuation frame][ContinuationFrame] tells the VM what to do *next*.
While there are frames left on the stack (not the normal stack, a special execution stack), it is popped and
queried. It will then operate the VM into executing a [continuation][Continuation] in a certain way.
Continuations are just a linked list of iotas to execute. The VM goes through each one and executes them.
- For staffcasting, each pattern drawn spins up the VM with a `FrameEvaluate`, which will provide exactly one
continuation containing the pattern.
- For trinket casting, the VM gets a `FrameEvaluate` again, but the continuation list it provides has
all the patterns in the trinket.
- Hermes' Gambit pushes a new `FrameEvaluate` to the stack with the pattern list argument inside it. This doesn't clear
the continuation underneath, so once those patterns are through execution control goes right back to where it was
interrupted.
- Thoth's and Charon's do something with different kinds of stack frames, I don't really understand it.
- Iris' gambit is waaaay outside of my pay grade
[CastingVM]: vm/CastingVM.kt
[CastingImage]: vm/CastingImage.kt
[CastingEnvironment]: CastingEnvironment.java
[ExecutionClientView]: ExecutionClientView.kt
[ContinuationFrame]: vm/ContinuationFrame.kt
[Continuation]: vm/SpellContinuation.kt
[FrameEvaluate]: vm/FrameEvaluate.kt
[CastResult]: CastResult.kt

View file

@ -3,7 +3,7 @@ package at.petrak.hexcasting.api.casting.eval.sideeffects
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.RenderedSpell
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM
import at.petrak.hexcasting.api.casting.mishaps.Mishap
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.mod.HexStatistics
@ -18,10 +18,10 @@ import net.minecraft.world.item.ItemStack
*/
sealed class OperatorSideEffect {
/** Return whether to cancel all further [OperatorSideEffect] */
abstract fun performEffect(harness: CastingHarness): Boolean
abstract fun performEffect(harness: CastingVM): Boolean
data class RequiredEnlightenment(val awardStat: Boolean) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
override fun performEffect(harness: CastingVM): Boolean {
harness.ctx.caster?.sendSystemMessage("hexcasting.message.cant_great_spell".asTranslatedComponent)
if (awardStat)
@ -38,7 +38,7 @@ sealed class OperatorSideEffect {
val awardStat: Boolean = true
) :
OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
override fun performEffect(harness: CastingVM): Boolean {
this.spell.cast(harness.ctx)
if (awardStat)
harness.ctx.caster?.awardStat(HexStatistics.SPELLS_CAST)
@ -48,14 +48,14 @@ sealed class OperatorSideEffect {
}
data class ConsumeMedia(val amount: Int) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
override fun performEffect(harness: CastingVM): Boolean {
val leftoverMedia = harness.ctx.extractMedia(this.amount.toLong())
return leftoverMedia > 0
}
}
data class Particles(val spray: ParticleSpray) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
override fun performEffect(harness: CastingVM): Boolean {
harness.ctx.produceParticles(this.spray, harness.ctx.colorizer)
this.spray.sprayParticles(harness.ctx.world, harness.getColorizer())
@ -64,7 +64,7 @@ sealed class OperatorSideEffect {
}
data class DoMishap(val mishap: Mishap, val errorCtx: Mishap.Context) : OperatorSideEffect() {
override fun performEffect(harness: CastingHarness): Boolean {
override fun performEffect(harness: CastingVM): Boolean {
val spray = mishap.particleSpray(harness.ctx)
val color = mishap.accentColor(harness.ctx, errorCtx)
spray.sprayParticles(harness.ctx.world, color)

View file

@ -0,0 +1,78 @@
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.utils.*
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.server.level.ServerLevel
/**
* The state of a casting VM, containing the stack and all
*/
data class CastingImage private constructor(
val stack: List<Iota>,
val parenCount: Int,
val parenthesized: List<Iota>,
val escapeNext: Boolean,
val userData: CompoundTag
) {
public constructor() : this(listOf(), 0, listOf(), false, CompoundTag())
fun serializeToNbt() = NBTBuilder {
TAG_STACK %= stack.serializeToNBT()
TAG_PAREN_COUNT %= parenCount
TAG_ESCAPE_NEXT %= escapeNext
TAG_PARENTHESIZED %= parenthesized.serializeToNBT()
TAG_USERDATA %= userData
}
companion object {
const val TAG_STACK = "stack"
const val TAG_PAREN_COUNT = "open_parens"
const val TAG_PARENTHESIZED = "parenthesized"
const val TAG_ESCAPE_NEXT = "escape_next"
const val TAG_USERDATA = "userdata"
@JvmStatic
public fun loadFromNbt(tag: CompoundTag, world: ServerLevel): CastingImage {
return try {
val stack = mutableListOf<Iota>()
val stackTag = tag.getList(TAG_STACK, Tag.TAG_COMPOUND)
for (subtag in stackTag) {
val datum = IotaType.deserialize(subtag.asCompound, world)
stack.add(datum)
}
val userData = if (tag.contains(TAG_USERDATA)) {
tag.getCompound(TAG_USERDATA)
} else if (tag.contains("local")) {
NBTBuilder {
TAG_USERDATA %= tag.getCompound("local")
}
} else {
CompoundTag()
}
val parenthesized = mutableListOf<Iota>()
val parenTag = tag.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND)
for (subtag in parenTag) {
parenthesized.add(IotaType.deserialize(subtag.downcast(CompoundTag.TYPE), world))
}
val parenCount = tag.getInt(CastingVM.TAG_PAREN_COUNT)
val escapeNext = tag.getBoolean(CastingVM.TAG_ESCAPE_NEXT)
CastingImage(stack, parenCount, parenthesized, escapeNext, userData)
} catch (exn: Exception) {
HexAPI.LOGGER.warn("error while loading a CastingImage", exn)
CastingImage()
}
}
}
}

View file

@ -1,116 +1,64 @@
package at.petrak.hexcasting.api.casting.eval
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.PatternShapeMatch
import at.petrak.hexcasting.api.casting.PatternShapeMatch.*
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.castables.Action
import at.petrak.hexcasting.api.casting.eval.*
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.eval.vm.FrameEvaluate
import at.petrak.hexcasting.api.casting.eval.vm.FunctionalData
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.iota.ListIota
import at.petrak.hexcasting.api.casting.iota.PatternIota
import at.petrak.hexcasting.api.casting.math.HexDir
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.casting.mishaps.*
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.mod.HexTags
import at.petrak.hexcasting.api.utils.*
import at.petrak.hexcasting.common.casting.PatternRegistryManifest
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
import at.petrak.hexcasting.xplat.IXplatAbstractions
import com.mojang.datafixers.util.Either
import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerLevel
import net.minecraft.sounds.SoundSource
import net.minecraft.world.level.gameevent.GameEvent
import net.minecraft.world.phys.Vec3
/**
* Keeps track of a player casting a spell on the server.
* It's stored as NBT on the player.
*
* TODO oh god this entire class needs a gigantic refactor. why are there like 6 different entrypoints for casting
* a pattern. oh god.
* The virtual machine! This is the glue that determines the next iteration of a [CastingImage], using a
* [CastingEnvironment] to affect the world.
*/
class CastingHarness private constructor(
var stack: MutableList<Iota>,
var ravenmind: Iota?,
var parenCount: Int,
var parenthesized: List<Iota>,
var escapeNext: Boolean,
val ctx: CastingEnvironment,
val prepackagedColorizer: FrozenColorizer? // for trinkets with colorizers
) {
@JvmOverloads
constructor(
ctx: CastingEnvironment,
prepackagedColorizer: FrozenColorizer? = null
) : this(mutableListOf(), null, 0, mutableListOf(), false, ctx, prepackagedColorizer)
class CastingVM(val image: CastingImage, val env: CastingEnvironment) {
/**
* Execute a single iota.
*/
fun executeIota(iota: Iota, world: ServerLevel): ControllerInfo = executeIotas(listOf(iota), world)
private fun displayPatternDebug(escapeNext: Boolean, parenCount: Int, iotaRepresentation: Component) {
if (this.ctx.debugPatterns) {
val display = " ".repeat(parenCount).asTextComponent
if (escapeNext)
display.append("\\ ".asTextComponent.gold)
display.append(iotaRepresentation)
this.ctx.caster.sendSystemMessage(display)
}
}
fun queueAndExecuteIota(iota: Iota, world: ServerLevel): ExecutionClientView = queueAndExecuteIotas(listOf(iota), world)
/**
* Given a list of iotas, execute them in sequence.
* The main entrypoint to the VM. Given a list of iotas, execute them in sequence, and return whatever the client
* needs to see.
*/
fun executeIotas(iotas: List<Iota>, world: ServerLevel): ControllerInfo {
fun queueAndExecuteIotas(iotas: List<Iota>, world: ServerLevel): ExecutionClientView {
// Initialize the continuation stack to a single top-level eval for all iotas.
var continuation = SpellContinuation.Done.pushFrame(FrameEvaluate(SpellList.LList(0, iotas), false))
// Begin aggregating info
val info = TempControllerInfo(earlyExit = false)
var lastResolutionType = ResolvedPatternType.UNRESOLVED
var sound = HexEvalSounds.NOTHING
while (continuation is SpellContinuation.NotDone && !info.earlyExit) {
// Take the top of the continuation stack...
val next = continuation.frame
// ...and execute it.
// TODO there used to be error checking code here; I'm pretty sure any and all mishaps should already
// get caught and folded into CastResult by evaluate.
val result = next.evaluate(continuation.next, world, this)
val image2 = next.evaluate(continuation.next, world, this)
// Then write all pertinent data back to the harness for the next iteration.
if (result.newData != null) {
this.applyFunctionalData(result.newData)
if (image2.newData != null) {
this.applyFunctionalData(image2.newData)
}
continuation = result.continuation
lastResolutionType = result.resolutionType
performSideEffects(info, result.sideEffects)
info.earlyExit = info.earlyExit || !lastResolutionType.success
sound = if (result.sound == HexEvalSounds.MISHAP) {
HexEvalSounds.MISHAP
} else {
sound.greaterOf(result.sound)
}
}
this.env.postExecution(image2)
sound.sound?.let {
this.ctx.world.playSound(
null, this.ctx.position.x, this.ctx.position.y, this.ctx.position.z, it,
SoundSource.PLAYERS, 1f, 1f
)
// TODO: is it worth mixing in to the immut map and making our own game event with blackjack and hookers
this.ctx.world.gameEvent(this.ctx.caster, GameEvent.ITEM_INTERACT_FINISH, this.ctx.position)
continuation = image2.continuation
lastResolutionType = image2.resolutionType
performSideEffects(info, image2.sideEffects)
info.earlyExit = info.earlyExit || !lastResolutionType.success
}
if (continuation is SpellContinuation.NotDone) {
@ -118,29 +66,23 @@ class CastingHarness private constructor(
if (lastResolutionType.success) ResolvedPatternType.EVALUATED else ResolvedPatternType.ERRORED
}
val (stackDescs, parenDescs, ravenmind) = generateDescs()
val (stackDescs, ravenmind) = generateDescs()
return ControllerInfo(
this.stack.isEmpty() && this.parenCount == 0 && !this.escapeNext,
lastResolutionType,
stackDescs,
parenDescs,
ravenmind,
this.parenCount
)
val isStackClear = image.stack.isEmpty() && image.parenCount == 0 && !image.escapeNext
return ExecutionClientView(isStackClear, lastResolutionType, stackDescs, ravenmind)
}
/**
* this DOES NOT THROW THINGS
*/
@Throws()
fun getUpdate(iota: Iota, world: ServerLevel, continuation: SpellContinuation): CastResult {
fun executeInner(iota: Iota, world: ServerLevel, continuation: SpellContinuation): CastResult {
try {
// TODO we can have a special intro/retro sound
// ALSO TODO need to add reader macro-style things
try {
this.handleParentheses(iota)?.let { (data, resolutionType) ->
return@getUpdate CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.OPERATOR)
return@executeInner CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.OPERATOR)
}
} catch (e: MishapTooManyCloseParens) {
// This is ridiculous and needs to be fixed
@ -162,7 +104,7 @@ class CastingHarness private constructor(
}
if (iota is PatternIota) {
return updateWithPattern(iota.pattern, world, continuation)
return executePattern(iota.pattern, world, continuation)
} else {
return CastResult(
continuation,
@ -202,11 +144,13 @@ class CastingHarness private constructor(
* When the server gets a packet from the client with a new pattern,
* handle it functionally.
*/
private fun updateWithPattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult {
private fun executePattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult {
var castedName: Component? = null
try {
val lookup = PatternRegistryManifest.matchPattern(newPat, world, false)
val lookupResult: Either<Action, List<OperatorSideEffect>> = if (lookup is Normal || lookup is PerWorld) {
this.env.precheckAction(lookup)
val action = if (lookup is Normal || lookup is PerWorld) {
val key = when (lookup) {
is Normal -> lookup.key
is PerWorld -> lookup.key
@ -214,63 +158,33 @@ class CastingHarness private constructor(
}
val reqsEnlightenment = isOfTag(IXplatAbstractions.INSTANCE.actionRegistry, key, HexTags.Actions.REQUIRES_ENLIGHTENMENT)
val canEnlighten = isOfTag(IXplatAbstractions.INSTANCE.actionRegistry, key, HexTags.Actions.CAN_START_ENLIGHTEN)
castedName = HexAPI.instance().getActionI18n(key, reqsEnlightenment)
if (!ctx.isCasterEnlightened && reqsEnlightenment) {
Either.right(listOf(OperatorSideEffect.RequiredEnlightenment(canEnlighten)))
} else {
val regiEntry = IXplatAbstractions.INSTANCE.actionRegistry.get(key)!!
Either.left(regiEntry.action)
}
IXplatAbstractions.INSTANCE.actionRegistry.get(key)!!.action
} else if (lookup is Special) {
castedName = lookup.handler.name
Either.left(lookup.handler.act())
lookup.handler.act()
} else if (lookup is PatternShapeMatch.Nothing) {
throw MishapInvalidPattern()
} else {
throw IllegalStateException()
}
// TODO: the config denylist should be handled per VM type.
// I just removed it for now, should re-add it...
} else throw IllegalStateException()
val sideEffects = mutableListOf<OperatorSideEffect>()
var stack2: List<Iota>? = null
var cont2 = continuation
var ravenmind2: Iota? = null
if (lookupResult.left().isPresent) {
val action = lookupResult.left().get()
displayPatternDebug(false, 0, castedName)
val result = action.operate(
continuation,
this.stack.toMutableList(),
this.ravenmind,
this.ctx
)
cont2 = result.newContinuation
stack2 = result.newStack
ravenmind2 = result.newRavenmind
// TODO parens also break prescience
sideEffects.addAll(result.sideEffects)
} else {
val problems = lookupResult.right().get()
sideEffects.addAll(problems)
}
// Stick a poofy particle effect at the caster position
// TODO again this should be on the VM lalala
if (this.ctx.spellCircle == null)
sideEffects.add(
OperatorSideEffect.Particles(
ParticleSpray(
this.ctx.position,
Vec3(0.0, 1.0, 0.0),
0.5, 1.0
)
)
)
val result = action.operate(
continuation,
this.stack.toMutableList(),
this.ravenmind,
this.ctx
)
cont2 = result.newContinuation
stack2 = result.newStack
ravenmind2 = result.newRavenmind
// TODO parens also break prescience
sideEffects.addAll(result.sideEffects)
val hereFd = this.getFunctionalData()
val fd = if (stack2 != null) {
@ -282,25 +196,6 @@ class CastingHarness private constructor(
hereFd
}
// TODO again this should be per VM
var soundType = if (this.ctx.source == CastingEnvironment.CastSource.STAFF) {
HexEvalSounds.OPERATOR
} else {
HexEvalSounds.NOTHING
}
for (se in sideEffects) {
if (se is OperatorSideEffect.AttemptSpell) {
soundType = if (se.hasCastingSound) {
soundType.greaterOf(HexEvalSounds.SPELL)
} else {
// WITH CATLIKE TREAD
// UPON OUR PREY WE STEAL
HexEvalSounds.NOTHING
}
} else if (se is OperatorSideEffect.DoMishap) {
soundType = HexEvalSounds.MISHAP
}
}
return CastResult(
cont2,
fd,
@ -333,11 +228,14 @@ class CastingHarness private constructor(
}
}
fun generateDescs() = Triple(
stack.map(HexIotaTypes::serialize),
parenthesized.map(HexIotaTypes::serialize),
ravenmind?.let(HexIotaTypes::serialize)
)
fun generateDescs(): Pair<List<Component>, Component?> {
val stackDescs = this.image.stack.map { it.display() }
val ravenmind = if (this.image.userData.contains(HexAPI.RAVENMIND_USERDATA.toString())) {
val tag = this.image.userData.getCompound(HexAPI.RAVENMIND_USERDATA.toString())
IotaType.getDisplay(tag)
} else null
return Pair(stackDescs, ravenmind)
}
/**
* Return the functional update represented by the current state (for use with `copy`)
@ -478,92 +376,6 @@ class CastingHarness private constructor(
return out
}
fun getColorizer(): FrozenColorizer {
if (this.prepackagedColorizer != null)
return this.prepackagedColorizer
return IXplatAbstractions.INSTANCE.getColorizer(this.ctx.caster)
}
fun serializeToNBT() = NBTBuilder {
TAG_STACK %= stack.serializeToNBT()
if (ravenmind != null)
TAG_LOCAL %= HexIotaTypes.serialize(ravenmind!!)
TAG_PAREN_COUNT %= parenCount
TAG_ESCAPE_NEXT %= escapeNext
TAG_PARENTHESIZED %= parenthesized.serializeToNBT()
if (prepackagedColorizer != null)
TAG_PREPACKAGED_COLORIZER %= prepackagedColorizer.serializeToNBT()
}
companion object {
const val TAG_STACK = "stack"
const val TAG_LOCAL = "local"
const val TAG_PAREN_COUNT = "open_parens"
const val TAG_PARENTHESIZED = "parenthesized"
const val TAG_ESCAPE_NEXT = "escape_next"
const val TAG_PREPACKAGED_COLORIZER = "prepackaged_colorizer"
init {
DiscoveryHandlers.addMediaHolderDiscoverer {
it.ctx.caster.inventory.items
.filter(::isMediaItem)
.mapNotNull(IXplatAbstractions.INSTANCE::findMediaHolder)
}
DiscoveryHandlers.addMediaHolderDiscoverer {
it.ctx.caster.inventory.armor
.filter(::isMediaItem)
.mapNotNull(IXplatAbstractions.INSTANCE::findMediaHolder)
}
DiscoveryHandlers.addMediaHolderDiscoverer {
it.ctx.caster.inventory.offhand
.filter(::isMediaItem)
.mapNotNull(IXplatAbstractions.INSTANCE::findMediaHolder)
}
}
@JvmStatic
fun fromNBT(nbt: CompoundTag, ctx: CastingEnvironment): CastingHarness {
return try {
val stack = mutableListOf<Iota>()
val stackTag = nbt.getList(TAG_STACK, Tag.TAG_COMPOUND)
for (subtag in stackTag) {
val datum = HexIotaTypes.deserialize(subtag.asCompound, ctx.world)
stack.add(datum)
}
val ravenmind = if (nbt.contains(TAG_LOCAL))
HexIotaTypes.deserialize(nbt.getCompound(TAG_LOCAL), ctx.world)
else
null
val parenthesized = mutableListOf<Iota>()
val parenTag = nbt.getList(TAG_PARENTHESIZED, Tag.TAG_COMPOUND)
for (subtag in parenTag) {
parenthesized.add(HexIotaTypes.deserialize(subtag.downcast(CompoundTag.TYPE), ctx.world))
}
val parenCount = nbt.getInt(TAG_PAREN_COUNT)
val escapeNext = nbt.getBoolean(TAG_ESCAPE_NEXT)
val colorizer = if (nbt.contains(TAG_PREPACKAGED_COLORIZER)) {
FrozenColorizer.fromNBT(nbt.getCompound(TAG_PREPACKAGED_COLORIZER))
} else {
null
}
CastingHarness(stack, ravenmind, parenCount, parenthesized, escapeNext, ctx, colorizer)
} catch (exn: Exception) {
CastingHarness(ctx)
}
}
}
data class TempControllerInfo(
var earlyExit: Boolean,
)

View file

@ -1,7 +1,6 @@
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.utils.getList
@ -31,7 +30,7 @@ sealed interface ContinuationFrame {
* For Evaluate, this consumes one pattern; for ForEach this queues the next iteration of the outer loop.
* @return the result of this pattern step
*/
fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingHarness): CastResult
fun evaluate(continuation: SpellContinuation, level: ServerLevel, harness: CastingVM): CastResult
/**
* The OpHalt instruction wants us to "jump to" the END of the nearest meta-eval.

View file

@ -2,7 +2,6 @@ package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.utils.NBTBuilder
@ -23,7 +22,7 @@ data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : Cont
override fun evaluate(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
harness: CastingVM
): CastResult {
// If there are patterns left...
return if (list.nonEmpty) {
@ -32,7 +31,7 @@ data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : Cont
continuation.pushFrame(FrameEvaluate(list.cdr, this.isMetacasting))
} else continuation
// ...before evaluating the first one in the list.
val update = harness.getUpdate(list.car, level, newCont)
val update = harness.executeInner(list.car, level, newCont)
if (this.isMetacasting && update.sound != HexEvalSounds.MISHAP) {
update.copy(sound = HexEvalSounds.HERMES)
} else {

View file

@ -1,7 +1,6 @@
package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.utils.NBTBuilder
@ -20,7 +19,7 @@ object FrameFinishEval : ContinuationFrame {
override fun evaluate(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
harness: CastingVM
): CastResult {
return CastResult(
continuation,

View file

@ -2,7 +2,6 @@ package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.CastResult
import at.petrak.hexcasting.api.casting.eval.CastingHarness
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.ListIota
@ -39,7 +38,7 @@ data class FrameForEach(
override fun evaluate(
continuation: SpellContinuation,
level: ServerLevel,
harness: CastingHarness
harness: CastingVM
): CastResult {
// If this isn't the very first Thoth step (i.e. no Thoth computations run yet)...
val stack = if (baseStack == null) {

View file

@ -30,7 +30,7 @@ public abstract class Iota {
/**
* Serialize this under the {@code data} tag.
* <p>
* You probably don't want to call this directly; use {@link HexIotaTypes#serialize}.
* You probably don't want to call this directly; use {@link IotaType#serialize}.
*/
abstract public @NotNull Tag serialize();

View file

@ -1,15 +1,27 @@
package at.petrak.hexcasting.api.casting.iota;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import com.mojang.datafixers.util.Pair;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.Font;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextColor;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.FormattedCharSequence;
import javax.annotation.Nullable;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Objects;
// Take notes from ForgeRegistryEntry
public abstract class IotaType<T extends Iota> {
/**
* Spell datums are stored as such: {@code { "type": "modid:type", "datum": a_tag }}.
* <p>
@ -41,4 +53,149 @@ public abstract class IotaType<T extends Iota> {
return Component.translatable("hexcasting.iota." + key)
.withStyle(style -> style.withColor(TextColor.fromRgb(color())));
}
public static CompoundTag serialize(Iota iota) {
var type = iota.getType();
var typeId = HexIotaTypes.REGISTRY.getKey(type);
if (typeId == null) {
throw new IllegalStateException(
"Tried to serialize an unregistered iota type. Iota: " + iota
+ " ; Type" + type.getClass().getTypeName());
}
// We check if it's too big on serialization; if it is we just return a garbage.
if (iota instanceof ListIota listIota && isTooLargeToSerialize(listIota.getList())) {
// Garbage will never be too large so we just recurse
return serialize(new GarbageIota());
}
var dataTag = iota.serialize();
var out = new CompoundTag();
out.putString(HexIotaTypes.KEY_TYPE, typeId.toString());
out.put(HexIotaTypes.KEY_DATA, dataTag);
return out;
}
public static boolean isTooLargeToSerialize(Iterable<Iota> examinee) {
// We don't recurse here, just a work queue (or work stack, if we liked.)
// Each element is a found sub-iota, and how deep it is.
//
// TODO: is it worth trying to cache the depth and size statically on a SpellList.
var listsToExamine = new ArrayDeque<>(Collections.singleton(new Pair<>(examinee, 0)));
int totalEltsFound = 1; // count the first list
while (!listsToExamine.isEmpty()) {
var iotaPair = listsToExamine.removeFirst();
var sublist = iotaPair.getFirst();
int depth = iotaPair.getSecond();
for (var iota : sublist) {
totalEltsFound++;
if (totalEltsFound >= HexIotaTypes.MAX_SERIALIZATION_TOTAL) {
return true; // too bad
}
if (iota instanceof ListIota subsublist) {
if (depth + 1 >= HexIotaTypes.MAX_SERIALIZATION_DEPTH) {
return true;
}
listsToExamine.addLast(new Pair<>(subsublist.getList(), depth + 1));
}
}
}
// we made it!
return false;
}
/**
* This method attempts to find the type from the {@code type} key.
* See {@link HexIotaTypes#serialize(Iota)} for the storage format.
*
* @return {@code null} if it cannot get the type.
*/
@org.jetbrains.annotations.Nullable
public static IotaType<?> getTypeFromTag(CompoundTag tag) {
if (!tag.contains(HexIotaTypes.KEY_TYPE, Tag.TAG_STRING)) {
return null;
}
var typeKey = tag.getString(HexIotaTypes.KEY_TYPE);
if (!ResourceLocation.isValidResourceLocation(typeKey)) {
return null;
}
var typeLoc = new ResourceLocation(typeKey);
return HexIotaTypes.REGISTRY.get(typeLoc);
}
/**
* Attempt to deserialize an iota from a tag.
* <br>
* Iotas are saved as such:
* <code>
* {
* "type": "hexcasting:atype",
* "data": {...}
* }
* </code>
*/
public static Iota deserialize(CompoundTag tag, ServerLevel world) {
var type = getTypeFromTag(tag);
if (type == null) {
return new GarbageIota();
}
var data = tag.get(HexIotaTypes.KEY_DATA);
if (data == null) {
return new GarbageIota();
}
Iota deserialized;
try {
deserialized = Objects.requireNonNullElse(type.deserialize(data, world), new NullIota());
} catch (IllegalArgumentException exn) {
HexAPI.LOGGER.warn("Caught an exception deserializing an iota", exn);
deserialized = new GarbageIota();
}
return deserialized;
}
private static Component brokenIota() {
return Component.translatable("hexcasting.spelldata.unknown")
.withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC);
}
public static Component getDisplay(CompoundTag tag) {
var type = getTypeFromTag(tag);
if (type == null) {
return brokenIota();
}
var data = tag.get(HexIotaTypes.KEY_DATA);
if (data == null) {
return brokenIota();
}
return type.display(data);
}
public static FormattedCharSequence getDisplayWithMaxWidth(CompoundTag tag, int maxWidth, Font font) {
var type = getTypeFromTag(tag);
if (type == null) {
return brokenIota().getVisualOrderText();
}
var data = tag.get(HexIotaTypes.KEY_DATA);
if (data == null) {
return brokenIota().getVisualOrderText();
}
var display = type.display(data);
var splitted = font.split(display, maxWidth - font.width("..."));
if (splitted.isEmpty())
return FormattedCharSequence.EMPTY;
else if (splitted.size() == 1)
return splitted.get(0);
else {
var first = splitted.get(0);
return FormattedCharSequence.fromPair(first,
Component.literal("...").withStyle(ChatFormatting.GRAY).getVisualOrderText());
}
}
public static int getColor(CompoundTag tag) {
var type = getTypeFromTag(tag);
if (type == null) {
return HexUtils.ERROR_COLOR;
}
return type.color();
}
}

View file

@ -68,7 +68,7 @@ public class ListIota extends Iota {
public @NotNull Tag serialize() {
var out = new ListTag();
for (var subdatum : this.getList()) {
out.add(HexIotaTypes.serialize(subdatum));
out.add(IotaType.serialize(subdatum));
}
return out;
}
@ -82,7 +82,7 @@ public class ListIota extends Iota {
for (var sub : listTag) {
var csub = HexUtils.downcast(sub, CompoundTag.TYPE);
var subiota = HexIotaTypes.deserialize(csub, world);
var subiota = IotaType.deserialize(csub, world);
if (subiota == null) {
return null;
}
@ -100,7 +100,7 @@ public class ListIota extends Iota {
Tag sub = list.get(i);
var csub = HexUtils.downcast(sub, CompoundTag.TYPE);
out.append(HexIotaTypes.getDisplay(csub));
out.append(IotaType.getDisplay(csub));
if (i < list.size() - 1) {
out.append(", ");

View file

@ -1,6 +1,7 @@
package at.petrak.hexcasting.api.item;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.client.ClientTickCounter;
@ -45,7 +46,7 @@ public interface IotaHolderItem {
var tag = dh.readIotaTag(stack);
if (tag != null) {
return HexIotaTypes.deserialize(tag, world);
return IotaType.deserialize(tag, world);
} else {
return null;
}
@ -83,7 +84,7 @@ public interface IotaHolderItem {
return HexUtils.ERROR_COLOR;
}
return HexIotaTypes.getColor(tag);
return IotaType.getColor(tag);
}
/**
@ -100,7 +101,7 @@ public interface IotaHolderItem {
TooltipFlag flag) {
var datumTag = self.readIotaTag(stack);
if (datumTag != null) {
var cmp = HexIotaTypes.getDisplay(datumTag);
var cmp = IotaType.getDisplay(datumTag);
components.add(Component.translatable("hexcasting.spelldata.onitem", cmp));
if (flag.isAdvanced()) {

View file

@ -2,7 +2,7 @@ package at.petrak.hexcasting.api.misc;
import at.petrak.hexcasting.api.addldata.ADMediaHolder;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
@ -15,10 +15,11 @@ import java.util.function.Predicate;
public class DiscoveryHandlers {
private static final List<Predicate<Player>> HAS_LENS_PREDICATE = new ArrayList<>();
private static final List<Function<CastingHarness, List<ADMediaHolder>>> MEDIA_HOLDER_DISCOVERY = new ArrayList<>();
private static final List<Function<CastingVM, List<ADMediaHolder>>> MEDIA_HOLDER_DISCOVERY = new ArrayList<>();
private static final List<FunctionToFloat<Player>> GRID_SCALE_MODIFIERS = new ArrayList<>();
private static final List<Function<CastingEnvironment, List<ItemStack>>> ITEM_SLOT_DISCOVERER = new ArrayList<>();
private static final List<Function<CastingEnvironment, List<ItemStack>>> OPERATIVE_SLOT_DISCOVERER = new ArrayList<>();
private static final List<Function<CastingEnvironment, List<ItemStack>>> OPERATIVE_SLOT_DISCOVERER =
new ArrayList<>();
private static final List<BiFunction<Player, String, ItemStack>> DEBUG_DISCOVERER = new ArrayList<>();
public static boolean hasLens(Player player) {
@ -30,7 +31,7 @@ public class DiscoveryHandlers {
return false;
}
public static List<ADMediaHolder> collectMediaHolders(CastingHarness harness) {
public static List<ADMediaHolder> collectMediaHolders(CastingVM harness) {
List<ADMediaHolder> holders = Lists.newArrayList();
for (var discoverer : MEDIA_HOLDER_DISCOVERY) {
holders.addAll(discoverer.apply(harness));
@ -76,7 +77,7 @@ public class DiscoveryHandlers {
HAS_LENS_PREDICATE.add(predicate);
}
public static void addMediaHolderDiscoverer(Function<CastingHarness, List<ADMediaHolder>> discoverer) {
public static void addMediaHolderDiscoverer(Function<CastingVM, List<ADMediaHolder>> discoverer) {
MEDIA_HOLDER_DISCOVERY.add(discoverer);
}

View file

@ -3,9 +3,9 @@
package at.petrak.hexcasting.api.utils
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.iota.ListIota
import at.petrak.hexcasting.api.casting.math.HexCoord
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
import net.minecraft.ChatFormatting
import net.minecraft.core.Registry
import net.minecraft.nbt.*
@ -251,7 +251,7 @@ inline operator fun <T> WeakValue<T>.setValue(thisRef: Any?, property: KProperty
* Returns an empty list if it's too complicated.
*/
fun Iterable<Iota>.serializeToNBT() =
if (HexIotaTypes.isTooLargeToSerialize(this))
if (IotaType.isTooLargeToSerialize(this))
ListTag()
else
ListIota(this.toList()).serialize()

View file

@ -2,6 +2,7 @@ package at.petrak.hexcasting.client;
import at.petrak.hexcasting.api.block.circle.BlockAbstractImpetus;
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.client.ScryingLensOverlayRegistry;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.item.MediaHolderItem;
@ -19,7 +20,6 @@ import at.petrak.hexcasting.common.items.magic.ItemPackagedHex;
import at.petrak.hexcasting.common.lib.HexBlockEntities;
import at.petrak.hexcasting.common.lib.HexBlocks;
import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import at.petrak.hexcasting.xplat.IClientXplatAbstractions;
import com.mojang.datafixers.util.Pair;
import net.minecraft.ChatFormatting;
@ -138,7 +138,7 @@ public class RegisterClientStuff {
if (iotaTag == null) {
return 0xff_ffffff;
}
return HexIotaTypes.getColor(iotaTag);
return IotaType.getColor(iotaTag);
}, HexBlocks.AKASHIC_BOOKSHELF);
}
@ -192,7 +192,7 @@ public class RegisterClientStuff {
if (world.getBlockEntity(pos) instanceof BlockEntityAkashicBookshelf tile) {
var iotaTag = tile.getIotaTag();
if (iotaTag != null) {
var display = HexIotaTypes.getDisplay(iotaTag);
var display = IotaType.getDisplay(iotaTag);
lines.add(new Pair<>(new ItemStack(Items.BOOK), display));
}
}

View file

@ -1,21 +1,21 @@
package at.petrak.hexcasting.client.gui
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.mod.HexTags
import at.petrak.hexcasting.api.casting.eval.ControllerInfo
import at.petrak.hexcasting.api.casting.eval.ExecutionClientView
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.math.HexAngle
import at.petrak.hexcasting.api.casting.math.HexCoord
import at.petrak.hexcasting.api.casting.math.HexDir
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.mod.HexTags
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.client.*
import at.petrak.hexcasting.client.ktxt.accumulatedScroll
import at.petrak.hexcasting.client.sound.GridSoundInstance
import at.petrak.hexcasting.common.lib.HexSounds
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
import at.petrak.hexcasting.common.network.MsgNewSpellPatternSyn
import at.petrak.hexcasting.xplat.IClientXplatAbstractions
import com.mojang.blaze3d.systems.RenderSystem
@ -59,7 +59,7 @@ class GuiSpellcasting constructor(
this.calculateIotaDisplays()
}
fun recvServerUpdate(info: ControllerInfo, index: Int) {
fun recvServerUpdate(info: ExecutionClientView, index: Int) {
this.patterns.getOrNull(index)?.let {
it.type = info.resolutionType
}
@ -75,7 +75,7 @@ class GuiSpellcasting constructor(
val mc = Minecraft.getInstance()
val width = (this.width * LHS_IOTAS_ALLOCATION).toInt()
this.stackDescs =
this.cachedStack.map { HexIotaTypes.getDisplayWithMaxWidth(it, width, mc.font) }
this.cachedStack.map { IotaType.getDisplayWithMaxWidth(it, width, mc.font) }
.asReversed()
// this.parenDescs = if (this.cachedParens.isNotEmpty())
// this.cachedParens.flatMap { HexIotaTypes.getDisplayWithMaxWidth(it, width, mc.font) }
@ -86,7 +86,7 @@ class GuiSpellcasting constructor(
this.parenDescs = emptyList()
this.ravenmind =
this.cachedRavenmind?.let {
HexIotaTypes.getDisplayWithMaxWidth(
IotaType.getDisplayWithMaxWidth(
it,
(this.width * RHS_IOTAS_ALLOCATION).toInt(),
mc.font

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.common.blocks.akashic;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
@ -57,7 +57,7 @@ public class BlockAkashicRecord extends Block {
var tile = (BlockEntityAkashicBookshelf) slevel.getBlockEntity(foundPos);
var tag = tile.getIotaTag();
return tag == null ? null : HexIotaTypes.deserialize(tag, slevel);
return tag == null ? null : IotaType.deserialize(tag, slevel);
}
// TODO get comparators working again and also cache the number of iotas somehow?

View file

@ -2,9 +2,9 @@ package at.petrak.hexcasting.common.blocks.akashic;
import at.petrak.hexcasting.api.block.HexBlockEntity;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.casting.math.HexPattern;
import at.petrak.hexcasting.common.lib.HexBlockEntities;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.state.BlockState;
@ -38,7 +38,7 @@ public class BlockEntityAkashicBookshelf extends HexBlockEntity {
public void setNewMapping(HexPattern pattern, Iota iota) {
var previouslyEmpty = this.pattern == null;
this.pattern = pattern;
this.iotaTag = HexIotaTypes.serialize(iota);
this.iotaTag = IotaType.serialize(iota);
if (previouslyEmpty) {
var oldBs = this.getBlockState();

View file

@ -2,7 +2,7 @@ package at.petrak.hexcasting.common.casting.env;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.api.casting.eval.CastResult;
import at.petrak.hexcasting.api.casting.eval.ControllerInfo;
import at.petrak.hexcasting.api.casting.eval.ExecutionClientView;
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern;
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType;
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect;
@ -74,13 +74,13 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
var harness = IXplatAbstractions.INSTANCE.getStaffHarness(sender, msg.handUsed());
ControllerInfo clientInfo;
ExecutionClientView clientInfo;
if (autoFail) {
var descs = harness.generateDescs();
clientInfo = new ControllerInfo(harness.getStack().isEmpty(), ResolvedPatternType.INVALID,
clientInfo = new ExecutionClientView(harness.getStack().isEmpty(), ResolvedPatternType.INVALID,
descs.getFirst(), descs.getSecond(), descs.getThird(), harness.getParenCount());
} else {
clientInfo = harness.executeIota(new PatternIota(msg.pattern()), sender.getLevel());
clientInfo = harness.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
}
if (clientInfo.isStackClear()) {

View file

@ -1,10 +1,10 @@
package at.petrak.hexcasting.common.items;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.casting.iota.DoubleIota;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import at.petrak.hexcasting.common.lib.HexSounds;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
@ -30,7 +30,7 @@ public class ItemAbacus extends Item implements IotaHolderItem {
public @Nullable
CompoundTag readIotaTag(ItemStack stack) {
var datum = new DoubleIota(NBTHelper.getDouble(stack, TAG_VALUE));
return HexIotaTypes.serialize(datum);
return IotaType.serialize(datum);
}
@Override
@ -66,7 +66,7 @@ public class ItemAbacus extends Item implements IotaHolderItem {
@Override
public void appendHoverText(ItemStack pStack, @Nullable Level pLevel, List<Component> pTooltipComponents,
TooltipFlag pIsAdvanced) {
TooltipFlag pIsAdvanced) {
IotaHolderItem.appendHoverText(this, pStack, pTooltipComponents, pIsAdvanced);
}
}

View file

@ -1,10 +1,10 @@
package at.petrak.hexcasting.common.items;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.casting.iota.NullIota;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
@ -57,7 +57,7 @@ public class ItemFocus extends Item implements IotaHolderItem {
stack.removeTagKey(TAG_DATA);
stack.removeTagKey(TAG_SEALED);
} else if (!isSealed(stack)) {
NBTHelper.put(stack, TAG_DATA, HexIotaTypes.serialize(datum));
NBTHelper.put(stack, TAG_DATA, IotaType.serialize(datum));
}
}

View file

@ -1,10 +1,10 @@
package at.petrak.hexcasting.common.items;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.casting.iota.NullIota;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
@ -42,7 +42,7 @@ public class ItemSpellbook extends Item implements IotaHolderItem {
@Override
public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip,
TooltipFlag isAdvanced) {
TooltipFlag isAdvanced) {
boolean sealed = isSealed(stack);
boolean empty = false;
if (NBTHelper.hasNumber(stack, TAG_SELECTED_PAGE)) {
@ -148,14 +148,14 @@ public class ItemSpellbook extends Item implements IotaHolderItem {
pages.remove(key);
NBTHelper.remove(NBTHelper.getCompound(stack, TAG_SEALED), key);
} else {
pages.put(key, HexIotaTypes.serialize(datum));
pages.put(key, IotaType.serialize(datum));
}
if (pages.isEmpty()) {
NBTHelper.remove(stack, TAG_PAGES);
}
} else if (datum != null) {
NBTHelper.getOrCreateCompound(stack, TAG_PAGES).put(key, HexIotaTypes.serialize(datum));
NBTHelper.getOrCreateCompound(stack, TAG_PAGES).put(key, IotaType.serialize(datum));
} else {
NBTHelper.remove(NBTHelper.getCompound(stack, TAG_SEALED), key);
}

View file

@ -1,11 +1,11 @@
package at.petrak.hexcasting.common.items.magic;
import at.petrak.hexcasting.api.item.HexHolderItem;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.item.HexHolderItem;
import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
@ -66,7 +66,7 @@ public abstract class ItemPackagedHex extends ItemMediaHolder implements HexHold
var out = new ArrayList<Iota>();
for (var patTag : patsTag) {
CompoundTag tag = NBTHelper.getAsCompound(patTag);
out.add(HexIotaTypes.deserialize(tag, level));
out.add(IotaType.deserialize(tag, level));
}
return out;
}
@ -75,7 +75,7 @@ public abstract class ItemPackagedHex extends ItemMediaHolder implements HexHold
public void writeHex(ItemStack stack, List<Iota> program, int media) {
ListTag patsTag = new ListTag();
for (Iota pat : program) {
patsTag.add(HexIotaTypes.serialize(pat));
patsTag.add(IotaType.serialize(pat));
}
NBTHelper.putList(stack, TAG_PROGRAM, patsTag);
@ -107,8 +107,8 @@ public abstract class ItemPackagedHex extends ItemMediaHolder implements HexHold
}
var sPlayer = (ServerPlayer) player;
var ctx = new CastingEnvironment(sPlayer, usedHand, CastingEnvironment.CastSource.PACKAGED_HEX);
var harness = new CastingHarness(ctx);
var info = harness.executeIotas(instrs, sPlayer.getLevel());
var harness = new CastingVM(ctx);
var info = harness.queueAndExecuteIotas(instrs, sPlayer.getLevel());
boolean broken = breakAfterDepletion() && getMedia(stack) == 0;

View file

@ -2,22 +2,13 @@ package at.petrak.hexcasting.common.lib.hex;
import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.api.casting.iota.*;
import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import com.mojang.datafixers.util.Pair;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.Font;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.FormattedCharSequence;
import org.jetbrains.annotations.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.BiConsumer;
import static at.petrak.hexcasting.api.HexAPI.modLoc;
@ -34,151 +25,6 @@ public class HexIotaTypes {
public static final int MAX_SERIALIZATION_DEPTH = 256;
public static final int MAX_SERIALIZATION_TOTAL = 1024;
public static CompoundTag serialize(Iota iota) {
var type = iota.getType();
var typeId = REGISTRY.getKey(type);
if (typeId == null) {
throw new IllegalStateException(
"Tried to serialize an unregistered iota type. Iota: " + iota
+ " ; Type" + type.getClass().getTypeName());
}
// We check if it's too big on serialization; if it is we just return a garbage.
if (iota instanceof ListIota listIota && isTooLargeToSerialize(listIota.getList())) {
// Garbage will never be too large so we just recurse
return serialize(new GarbageIota());
}
var dataTag = iota.serialize();
var out = new CompoundTag();
out.putString(KEY_TYPE, typeId.toString());
out.put(KEY_DATA, dataTag);
return out;
}
public static boolean isTooLargeToSerialize(Iterable<Iota> examinee) {
// We don't recurse here, just a work queue (or work stack, if we liked.)
// Each element is a found sub-iota, and how deep it is.
//
// TODO: is it worth trying to cache the depth and size statically on a SpellList.
var listsToExamine = new ArrayDeque<>(Collections.singleton(new Pair<>(examinee, 0)));
int totalEltsFound = 1; // count the first list
while (!listsToExamine.isEmpty()) {
var iotaPair = listsToExamine.removeFirst();
var sublist = iotaPair.getFirst();
int depth = iotaPair.getSecond();
for (var iota : sublist) {
totalEltsFound++;
if (totalEltsFound >= MAX_SERIALIZATION_TOTAL) {
return true; // too bad
}
if (iota instanceof ListIota subsublist) {
if (depth + 1 >= MAX_SERIALIZATION_DEPTH) {
return true;
}
listsToExamine.addLast(new Pair<>(subsublist.getList(), depth + 1));
}
}
}
// we made it!
return false;
}
/**
* This method attempts to find the type from the {@code type} key.
* See {@link HexIotaTypes#serialize(Iota)} for the storage format.
*
* @return {@code null} if it cannot get the type.
*/
@Nullable
public static IotaType<?> getTypeFromTag(CompoundTag tag) {
if (!tag.contains(KEY_TYPE, Tag.TAG_STRING)) {
return null;
}
var typeKey = tag.getString(KEY_TYPE);
if (!ResourceLocation.isValidResourceLocation(typeKey)) {
return null;
}
var typeLoc = new ResourceLocation(typeKey);
return REGISTRY.get(typeLoc);
}
/**
* Attempt to deserialize an iota from a tag.
* <br>
* Iotas are saved as such:
* <code>
* {
* "type": "hexcasting:atype",
* "data": {...}
* }
* </code>
*/
public static Iota deserialize(CompoundTag tag, ServerLevel world) {
var type = getTypeFromTag(tag);
if (type == null) {
return new GarbageIota();
}
var data = tag.get(KEY_DATA);
if (data == null) {
return new GarbageIota();
}
Iota deserialized;
try {
deserialized = Objects.requireNonNullElse(type.deserialize(data, world), new NullIota());
} catch (IllegalArgumentException exn) {
HexAPI.LOGGER.warn("Caught an exception deserializing an iota", exn);
deserialized = new GarbageIota();
}
return deserialized;
}
private static Component brokenIota() {
return Component.translatable("hexcasting.spelldata.unknown")
.withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC);
}
public static Component getDisplay(CompoundTag tag) {
var type = getTypeFromTag(tag);
if (type == null) {
return brokenIota();
}
var data = tag.get(KEY_DATA);
if (data == null) {
return brokenIota();
}
return type.display(data);
}
public static FormattedCharSequence getDisplayWithMaxWidth(CompoundTag tag, int maxWidth, Font font) {
var type = getTypeFromTag(tag);
if (type == null) {
return brokenIota().getVisualOrderText();
}
var data = tag.get(KEY_DATA);
if (data == null) {
return brokenIota().getVisualOrderText();
}
var display = type.display(data);
var splitted = font.split(display, maxWidth - font.width("..."));
if (splitted.isEmpty())
return FormattedCharSequence.EMPTY;
else if (splitted.size() == 1)
return splitted.get(0);
else {
var first = splitted.get(0);
return FormattedCharSequence.fromPair(first,
Component.literal("...").withStyle(ChatFormatting.GRAY).getVisualOrderText());
}
}
public static int getColor(CompoundTag tag) {
var type = getTypeFromTag(tag);
if (type == null) {
return HexUtils.ERROR_COLOR;
}
return type.color();
}
public static void registerTypes(BiConsumer<IotaType<?>, ResourceLocation> r) {
for (var e : TYPES.entrySet()) {
r.accept(e.getValue(), e.getKey());

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.common.network;
import at.petrak.hexcasting.api.casting.eval.ControllerInfo;
import at.petrak.hexcasting.api.casting.eval.ExecutionClientView;
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType;
import at.petrak.hexcasting.client.gui.GuiSpellcasting;
import at.petrak.hexcasting.common.lib.HexSounds;
@ -16,7 +16,7 @@ import static at.petrak.hexcasting.api.HexAPI.modLoc;
/**
* Sent server->client when the player finishes casting a spell.
*/
public record MsgNewSpellPatternAck(ControllerInfo info, int index) implements IMessage {
public record MsgNewSpellPatternAck(ExecutionClientView info, int index) implements IMessage {
public static final ResourceLocation ID = modLoc("pat_sc");
@Override
@ -38,7 +38,7 @@ public record MsgNewSpellPatternAck(ControllerInfo info, int index) implements I
var parenCount = buf.readVarInt();
return new MsgNewSpellPatternAck(
new ControllerInfo(isStackEmpty, resolutionType, stack, parens, raven, parenCount), index
new ExecutionClientView(isStackEmpty, resolutionType, stack, parens, raven, parenCount), index
);
}

View file

@ -1,9 +1,9 @@
package at.petrak.hexcasting.common.network;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.utils.NBTHelper;
import at.petrak.hexcasting.common.items.ItemAbacus;
import at.petrak.hexcasting.common.items.ItemSpellbook;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import at.petrak.hexcasting.common.lib.HexItems;
import at.petrak.hexcasting.common.lib.HexSounds;
import io.netty.buffer.ByteBuf;
@ -144,7 +144,7 @@ public record MsgShiftScrollSyn(double mainHandDelta, double offHandDelta, boole
var datumTag = HexItems.ABACUS.readIotaTag(stack);
if (datumTag != null) {
var popup = HexIotaTypes.getDisplay(datumTag);
var popup = IotaType.getDisplay(datumTag);
sender.displayClientMessage(
Component.translatable("hexcasting.tooltip.abacus", popup).withStyle(ChatFormatting.GREEN), true);
}

View file

@ -6,9 +6,9 @@ import at.petrak.hexcasting.api.addldata.ADIotaHolder;
import at.petrak.hexcasting.api.addldata.ADMediaHolder;
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern;
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.player.FlightAbility;
@ -79,7 +79,7 @@ public interface IXplatAbstractions {
void setFlight(ServerPlayer target, FlightAbility flight);
void setHarness(ServerPlayer target, @Nullable CastingHarness harness);
void setHarness(ServerPlayer target, @Nullable CastingVM harness);
void setPatterns(ServerPlayer target, List<ResolvedPattern> patterns);
@ -91,7 +91,7 @@ public interface IXplatAbstractions {
Sentinel getSentinel(Player player);
CastingHarness getStaffHarness(ServerPlayer player, InteractionHand hand);
CastingVM getStaffHarness(ServerPlayer player, InteractionHand hand);
List<ResolvedPattern> getPatternsSavedInUi(ServerPlayer player);

View file

@ -1,7 +1,7 @@
package at.petrak.hexcasting.fabric.cc;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import dev.onyxstudios.cca.api.v3.component.Component;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
@ -18,16 +18,16 @@ public class CCHarness implements Component {
this.owner = owner;
}
public CastingHarness getHarness(InteractionHand hand) {
public CastingVM getHarness(InteractionHand hand) {
var ctx = new CastingEnvironment(this.owner, hand, CastingEnvironment.CastSource.STAFF);
if (this.lazyLoadedTag.isEmpty()) {
return new CastingHarness(ctx);
return new CastingVM(ctx);
} else {
return CastingHarness.fromNBT(this.lazyLoadedTag, ctx);
return CastingVM.fromNBT(this.lazyLoadedTag, ctx);
}
}
public void setHarness(@Nullable CastingHarness harness) {
public void setHarness(@Nullable CastingVM harness) {
this.lazyLoadedTag = harness == null ? new CompoundTag() : harness.serializeToNBT();
}

View file

@ -1,8 +1,8 @@
package at.petrak.hexcasting.fabric.cc.adimpl;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.item.IotaHolderItem;
import at.petrak.hexcasting.fabric.cc.HexCardinalComponents;
import dev.onyxstudios.cca.api.v3.item.ItemComponent;
import net.minecraft.nbt.CompoundTag;
@ -56,7 +56,7 @@ public abstract class CCItemIotaHolder extends ItemComponent implements CCIotaHo
@Override
public @Nullable CompoundTag readIotaTag() {
var iota = this.provider.apply(this.stack);
return iota == null ? null : HexIotaTypes.serialize(iota);
return iota == null ? null : IotaType.serialize(iota);
}
@Override

View file

@ -6,9 +6,9 @@ import at.petrak.hexcasting.api.addldata.ADIotaHolder;
import at.petrak.hexcasting.api.addldata.ADMediaHolder;
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern;
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexConfig;
@ -165,7 +165,7 @@ public class FabricXplatImpl implements IXplatAbstractions {
}
@Override
public void setHarness(ServerPlayer target, CastingHarness harness) {
public void setHarness(ServerPlayer target, CastingVM harness) {
var cc = HexCardinalComponents.HARNESS.get(target);
cc.setHarness(harness);
}
@ -201,7 +201,7 @@ public class FabricXplatImpl implements IXplatAbstractions {
}
@Override
public CastingHarness getStaffHarness(ServerPlayer player, InteractionHand hand) {
public CastingVM getStaffHarness(ServerPlayer player, InteractionHand hand) {
var cc = HexCardinalComponents.HARNESS.get(player);
return cc.getHarness(hand);
}

View file

@ -2,7 +2,7 @@ package at.petrak.hexcasting.forge.cap.adimpl;
import at.petrak.hexcasting.api.addldata.ADIotaHolder;
import at.petrak.hexcasting.api.casting.iota.Iota;
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
@ -17,7 +17,7 @@ public record CapStaticIotaHolder(Function<ItemStack, Iota> provider,
public @Nullable
CompoundTag readIotaTag() {
var iota = provider.apply(stack);
return iota == null ? null : HexIotaTypes.serialize(iota);
return iota == null ? null : IotaType.serialize(iota);
}
@Override

View file

@ -8,9 +8,9 @@ import at.petrak.hexcasting.api.addldata.ADMediaHolder;
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.CastingHarness;
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern;
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM;
import at.petrak.hexcasting.api.casting.iota.IotaType;
import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexTags;
@ -183,7 +183,7 @@ public class ForgeXplatImpl implements IXplatAbstractions {
}
@Override
public void setHarness(ServerPlayer player, CastingHarness harness) {
public void setHarness(ServerPlayer player, CastingVM harness) {
player.getPersistentData().put(TAG_HARNESS, harness == null ? new CompoundTag() : harness.serializeToNBT());
}
@ -237,10 +237,10 @@ public class ForgeXplatImpl implements IXplatAbstractions {
}
@Override
public CastingHarness getStaffHarness(ServerPlayer player, InteractionHand hand) {
public CastingVM getStaffHarness(ServerPlayer player, InteractionHand hand) {
// This is always from a staff because we don't need to load the harness when casting from item
var ctx = new CastingEnvironment(player, hand, CastingEnvironment.CastSource.STAFF);
return CastingHarness.fromNBT(player.getPersistentData().getCompound(TAG_HARNESS), ctx);
return CastingVM.fromNBT(player.getPersistentData().getCompound(TAG_HARNESS), ctx);
}
@Override