finish sound cleanup and also other things cleanup
This commit is contained in:
parent
7699a5e468
commit
76006d72dc
34 changed files with 397 additions and 304 deletions
|
@ -2,7 +2,7 @@ package at.petrak.hexcasting.api.spell
|
|||
|
||||
import at.petrak.hexcasting.api.PatternRegistry
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import at.petrak.hexcasting.api.utils.lightPurple
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.api.spell
|
||||
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package at.petrak.hexcasting.api.spell
|
||||
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package at.petrak.hexcasting.api.spell
|
||||
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -12,6 +12,11 @@ import at.petrak.hexcasting.api.mod.HexStatistics
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.ParticleSpray
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.ContinuationFrame
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.FrameEvaluate
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.FunctionalData
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.EvalSound
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.iota.ListIota
|
||||
|
@ -20,6 +25,7 @@ import at.petrak.hexcasting.api.spell.math.HexDir
|
|||
import at.petrak.hexcasting.api.spell.math.HexPattern
|
||||
import at.petrak.hexcasting.api.spell.mishaps.*
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
|
||||
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.ChatFormatting
|
||||
|
@ -76,13 +82,13 @@ class CastingHarness private constructor(
|
|||
}
|
||||
|
||||
private fun getPatternForFrame(frame: ContinuationFrame): HexPattern? {
|
||||
if (frame !is ContinuationFrame.Evaluate) return null
|
||||
if (frame !is FrameEvaluate) return null
|
||||
|
||||
return (frame.list.car as? PatternIota)?.pattern
|
||||
}
|
||||
|
||||
private fun getOperatorForFrame(frame: ContinuationFrame, world: ServerLevel): Action? {
|
||||
if (frame !is ContinuationFrame.Evaluate) return null
|
||||
if (frame !is FrameEvaluate) return null
|
||||
|
||||
return getOperatorForPattern(frame.list.car, world)
|
||||
}
|
||||
|
@ -92,10 +98,11 @@ class CastingHarness private constructor(
|
|||
*/
|
||||
fun executeIotas(iotas: List<Iota>, world: ServerLevel): ControllerInfo {
|
||||
// Initialize the continuation stack to a single top-level eval for all iotas.
|
||||
var continuation = SpellContinuation.Done.pushFrame(ContinuationFrame.Evaluate(SpellList.LList(0, 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
|
||||
|
@ -115,7 +122,7 @@ class CastingHarness private constructor(
|
|||
Mishap.Context(pattern ?: HexPattern(HexDir.WEST), operator)
|
||||
)
|
||||
),
|
||||
EvalSound.MISHAP,
|
||||
HexEvalSounds.MISHAP,
|
||||
)
|
||||
}
|
||||
// Then write all pertinent data back to the harness for the next iteration.
|
||||
|
@ -124,8 +131,22 @@ class CastingHarness private constructor(
|
|||
}
|
||||
continuation = result.continuation
|
||||
lastResolutionType = result.resolutionType
|
||||
performSideEffects(info, result.sideEffects, result.sound)
|
||||
performSideEffects(info, result.sideEffects)
|
||||
info.earlyExit = info.earlyExit || !lastResolutionType.success
|
||||
sound = if (result.sound == HexEvalSounds.MISHAP) {
|
||||
HexEvalSounds.MISHAP
|
||||
} else {
|
||||
sound.greaterOf(result.sound)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
if (continuation is SpellContinuation.NotDone) {
|
||||
|
@ -147,14 +168,15 @@ class CastingHarness private constructor(
|
|||
|
||||
fun getUpdate(iota: Iota, world: ServerLevel, continuation: SpellContinuation): CastResult {
|
||||
try {
|
||||
// TODO we can have a special intro/retro sound
|
||||
this.handleParentheses(iota)?.let { (data, resolutionType) ->
|
||||
return@getUpdate CastResult(continuation, data, resolutionType, listOf(), EvalSound.GENERIC)
|
||||
return@getUpdate CastResult(continuation, data, resolutionType, listOf(), HexEvalSounds.OPERATOR)
|
||||
}
|
||||
|
||||
return if (iota is PatternIota) {
|
||||
updateWithPattern(iota.pattern, world, continuation)
|
||||
if (iota is PatternIota) {
|
||||
return updateWithPattern(iota.pattern, world, continuation)
|
||||
} else {
|
||||
CastResult(
|
||||
return CastResult(
|
||||
continuation,
|
||||
null,
|
||||
ResolvedPatternType.INVALID, // Should never matter
|
||||
|
@ -164,7 +186,7 @@ class CastingHarness private constructor(
|
|||
Mishap.Context(HexPattern(HexDir.WEST), null)
|
||||
)
|
||||
),
|
||||
EvalSound.MISHAP
|
||||
HexEvalSounds.MISHAP
|
||||
)
|
||||
}
|
||||
} catch (mishap: Mishap) {
|
||||
|
@ -181,7 +203,7 @@ class CastingHarness private constructor(
|
|||
)
|
||||
)
|
||||
),
|
||||
EvalSound.MISHAP
|
||||
HexEvalSounds.MISHAP
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
// This means something very bad has happened
|
||||
|
@ -199,7 +221,7 @@ class CastingHarness private constructor(
|
|||
)
|
||||
)
|
||||
),
|
||||
EvalSound.MISHAP
|
||||
HexEvalSounds.MISHAP
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -273,20 +295,22 @@ class CastingHarness private constructor(
|
|||
hereFd
|
||||
}
|
||||
|
||||
var soundType =
|
||||
if (this.ctx.source == CastingContext.CastSource.STAFF) EvalSound.GENERIC else EvalSound.NONE;
|
||||
var soundType = if (this.ctx.source == CastingContext.CastSource.STAFF) {
|
||||
HexEvalSounds.OPERATOR
|
||||
} else {
|
||||
HexEvalSounds.NOTHING
|
||||
}
|
||||
for (se in sideEffects) {
|
||||
if (se is OperatorSideEffect.AttemptSpell) {
|
||||
if (se.hasCastingSound) {
|
||||
soundType = soundType.greaterOf(EvalSound.SPELL_BOINK)
|
||||
soundType = if (se.hasCastingSound) {
|
||||
soundType.greaterOf(HexEvalSounds.SPELL)
|
||||
} else {
|
||||
// WITH CATLIKE TREAD
|
||||
// UPON OUR PREY WE STEAL
|
||||
soundType = EvalSound.NONE
|
||||
break
|
||||
HexEvalSounds.NOTHING
|
||||
}
|
||||
} else if (se is OperatorSideEffect.DoMishap) {
|
||||
soundType = EvalSound.MISHAP
|
||||
soundType = HexEvalSounds.MISHAP
|
||||
}
|
||||
}
|
||||
return CastResult(
|
||||
|
@ -303,7 +327,7 @@ class CastingHarness private constructor(
|
|||
null,
|
||||
mishap.resolutionType(ctx),
|
||||
listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, actionIdPair?.first))),
|
||||
EvalSound.MISHAP
|
||||
HexEvalSounds.MISHAP
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -311,7 +335,7 @@ class CastingHarness private constructor(
|
|||
/**
|
||||
* Execute the side effects of a pattern, updating our aggregated info.
|
||||
*/
|
||||
fun performSideEffects(info: TempControllerInfo, sideEffects: List<OperatorSideEffect>, sound: EvalSound) {
|
||||
fun performSideEffects(info: TempControllerInfo, sideEffects: List<OperatorSideEffect>) {
|
||||
for (haskellProgrammersShakingandCryingRN in sideEffects) {
|
||||
val mustStop = haskellProgrammersShakingandCryingRN.performEffect(this)
|
||||
if (mustStop) {
|
||||
|
@ -319,14 +343,6 @@ class CastingHarness private constructor(
|
|||
break
|
||||
}
|
||||
}
|
||||
sound.soundEvent()?.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)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateDescs() = Triple(
|
||||
|
|
|
@ -1,216 +0,0 @@
|
|||
package at.petrak.hexcasting.api.spell.casting
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness.CastResult
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.iota.ListIota
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import at.petrak.hexcasting.api.utils.getList
|
||||
import at.petrak.hexcasting.api.utils.hasList
|
||||
import at.petrak.hexcasting.api.utils.serializeToNBT
|
||||
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
// TODO this should probably be a registry too
|
||||
/**
|
||||
* A single frame of evaluation during the execution of a spell.
|
||||
*
|
||||
* Specifically, an evaluation will keep a stack of these frames.
|
||||
* An evaluation with no meta-eval will consist of a single [Evaluate(rest of the pats)] at all times.
|
||||
* When an Eval is invoked, we push Evaluate(pats) to the top of the stack.
|
||||
*
|
||||
* Evaluation is performed by repeatedly popping the top-most (i.e. innermost) frame from the stack,
|
||||
* then evaluating that frame (and possibly allowing it to push other frames (e.g. if it's a Hermes)).
|
||||
*
|
||||
* Once the stack of frames is empty, there are no more computations to run, so we're done.
|
||||
*/
|
||||
sealed interface ContinuationFrame {
|
||||
/**
|
||||
* Step the evaluation forward once.
|
||||
* 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
|
||||
|
||||
/**
|
||||
* The OpHalt instruction wants us to "jump to" the END of the nearest meta-eval.
|
||||
* In other words, we should consume Evaluate frames until we hit a FinishEval or Thoth frame.
|
||||
* @return whether the break should stop here, alongside the new stack state (e.g. for finalizing a Thoth)
|
||||
*/
|
||||
fun breakDownwards(stack: List<Iota>): Pair<Boolean, List<Iota>>
|
||||
|
||||
/**
|
||||
* Serializes this frame. Used for things like delays, where we pause execution.
|
||||
*/
|
||||
fun serializeToNBT(): CompoundTag
|
||||
|
||||
/**
|
||||
* A list of patterns to be evaluated in sequence.
|
||||
* @property list the *remaining* list of patterns to be evaluated
|
||||
*/
|
||||
data class Evaluate(val list: SpellList) : ContinuationFrame {
|
||||
// Discard this frame and keep discarding frames.
|
||||
override fun breakDownwards(stack: List<Iota>) = false to stack
|
||||
|
||||
// Step the list of patterns, evaluating a single one.
|
||||
override fun evaluate(
|
||||
continuation: SpellContinuation,
|
||||
level: ServerLevel,
|
||||
harness: CastingHarness
|
||||
): CastResult {
|
||||
// If there are patterns left...
|
||||
return if (list.nonEmpty) {
|
||||
val newCont = if (list.cdr.nonEmpty) { // yay TCO
|
||||
// ...enqueue the evaluation of the rest of the patterns...
|
||||
continuation.pushFrame(Evaluate(list.cdr))
|
||||
} else continuation
|
||||
// ...before evaluating the first one in the list.
|
||||
harness.getUpdate(list.car, level, newCont)
|
||||
} else {
|
||||
// If there are no patterns (e.g. empty Hermes), just return OK.
|
||||
CastResult(continuation, null, ResolvedPatternType.EVALUATED, listOf(), EvalSound.NONE)
|
||||
}
|
||||
}
|
||||
|
||||
override fun serializeToNBT() = NBTBuilder {
|
||||
"type" %= "evaluate"
|
||||
"patterns" %= list.serializeToNBT()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A stack marker representing the end of a Hermes evaluation,
|
||||
* so that we know when to stop removing frames during a Halt.
|
||||
*/
|
||||
object FinishEval : ContinuationFrame {
|
||||
// Don't do anything else to the stack, just finish the halt statement.
|
||||
override fun breakDownwards(stack: List<Iota>) = true to stack
|
||||
|
||||
// Evaluating it does nothing; it's only a boundary condition.
|
||||
override fun evaluate(
|
||||
continuation: SpellContinuation,
|
||||
level: ServerLevel,
|
||||
harness: CastingHarness
|
||||
): CastResult {
|
||||
return CastResult(
|
||||
continuation,
|
||||
FunctionalData(harness.stack.toList(), 0, listOf(), false, harness.ravenmind),
|
||||
ResolvedPatternType.EVALUATED,
|
||||
listOf(),
|
||||
EvalSound.NONE,
|
||||
)
|
||||
}
|
||||
|
||||
override fun serializeToNBT() = NBTBuilder {
|
||||
"type" %= "end"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A frame representing all the state for a Thoth evaluation.
|
||||
* Pushed by an OpForEach.
|
||||
* @property first whether the input stack state is the first one (since we don't want to save the base-stack before any changes are made)
|
||||
* @property data list of *remaining* datums to ForEach over
|
||||
* @property code code to run per datum
|
||||
* @property baseStack the stack state at Thoth entry
|
||||
* @property acc concatenated list of final stack states after Thoth exit
|
||||
*/
|
||||
data class ForEach(
|
||||
val data: SpellList,
|
||||
val code: SpellList,
|
||||
val baseStack: List<Iota>?,
|
||||
val acc: MutableList<Iota>
|
||||
) : ContinuationFrame {
|
||||
|
||||
/** When halting, we add the stack state at halt to the stack accumulator, then return the original pre-Thoth stack, plus the accumulator. */
|
||||
override fun breakDownwards(stack: List<Iota>): Pair<Boolean, List<Iota>> {
|
||||
val newStack = baseStack?.toMutableList() ?: mutableListOf()
|
||||
acc.addAll(stack)
|
||||
newStack.add(ListIota(acc))
|
||||
return true to newStack
|
||||
}
|
||||
|
||||
/** Step the Thoth computation, enqueueing one code evaluation. */
|
||||
override fun evaluate(
|
||||
continuation: SpellContinuation,
|
||||
level: ServerLevel,
|
||||
harness: CastingHarness
|
||||
): CastResult {
|
||||
// If this isn't the very first Thoth step (i.e. no Thoth computations run yet)...
|
||||
val stack = if (baseStack == null) {
|
||||
// init stack to the harness stack...
|
||||
harness.stack.toList()
|
||||
} else {
|
||||
// else save the stack to the accumulator and reuse the saved base stack.
|
||||
acc.addAll(harness.stack)
|
||||
baseStack
|
||||
}
|
||||
|
||||
// If we still have data to process...
|
||||
val (stackTop, newCont) = if (data.nonEmpty) {
|
||||
// Increment the evaluation depth,
|
||||
harness.ctx.incDepth()
|
||||
// push the next datum to the top of the stack,
|
||||
data.car to continuation
|
||||
// put the next Thoth object back on the stack for the next Thoth cycle,
|
||||
.pushFrame(ForEach(data.cdr, code, stack, acc))
|
||||
// and prep the Thoth'd code block for evaluation.
|
||||
.pushFrame(Evaluate(code))
|
||||
} else {
|
||||
// Else, dump our final list onto the stack.
|
||||
ListIota(acc) to continuation
|
||||
}
|
||||
val tStack = stack.toMutableList()
|
||||
tStack.add(stackTop)
|
||||
// TODO: this means we could have Thoth casting do a different sound
|
||||
return CastResult(
|
||||
newCont,
|
||||
FunctionalData(tStack, 0, listOf(), false, harness.ravenmind),
|
||||
ResolvedPatternType.EVALUATED,
|
||||
listOf(),
|
||||
EvalSound.NONE,
|
||||
)
|
||||
}
|
||||
|
||||
override fun serializeToNBT() = NBTBuilder {
|
||||
"type" %= "foreach"
|
||||
"data" %= data.serializeToNBT()
|
||||
"code" %= code.serializeToNBT()
|
||||
if (baseStack != null)
|
||||
"base" %= baseStack.serializeToNBT()
|
||||
"accumulator" %= acc.serializeToNBT()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromNBT(tag: CompoundTag, world: ServerLevel): ContinuationFrame {
|
||||
return when (tag.getString("type")) {
|
||||
"eval" -> Evaluate(
|
||||
HexIotaTypes.LIST.deserialize(
|
||||
tag.getList("patterns", Tag.TAG_COMPOUND),
|
||||
world
|
||||
)!!.list
|
||||
)
|
||||
|
||||
"end" -> FinishEval
|
||||
"foreach" -> ForEach(
|
||||
HexIotaTypes.LIST.deserialize(tag.getList("data", Tag.TAG_COMPOUND), world)!!.list,
|
||||
HexIotaTypes.LIST.deserialize(tag.getList("code", Tag.TAG_COMPOUND), world)!!.list,
|
||||
if (tag.hasList("base", Tag.TAG_COMPOUND))
|
||||
HexIotaTypes.LIST.deserialize(tag.getList("base", Tag.TAG_COMPOUND), world)!!.list.toList()
|
||||
else
|
||||
null,
|
||||
HexIotaTypes.LIST.deserialize(
|
||||
tag.getList("accumulator", Tag.TAG_COMPOUND),
|
||||
world
|
||||
)!!.list.toMutableList()
|
||||
)
|
||||
|
||||
else -> Evaluate(SpellList.LList(0, listOf()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package at.petrak.hexcasting.api.spell.casting.eval
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness.CastResult
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.utils.getList
|
||||
import at.petrak.hexcasting.api.utils.hasList
|
||||
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
// TODO this should probably be a registry too
|
||||
/**
|
||||
* A single frame of evaluation during the execution of a spell.
|
||||
*
|
||||
* Specifically, an evaluation will keep a stack of these frames.
|
||||
* An evaluation with no meta-eval will consist of a single [Evaluate(rest of the pats)] at all times.
|
||||
* When an Eval is invoked, we push Evaluate(pats) to the top of the stack.
|
||||
*
|
||||
* Evaluation is performed by repeatedly popping the top-most (i.e. innermost) frame from the stack,
|
||||
* then evaluating that frame (and possibly allowing it to push other frames (e.g. if it's a Hermes)).
|
||||
*
|
||||
* Once the stack of frames is empty, there are no more computations to run, so we're done.
|
||||
*
|
||||
*/
|
||||
sealed interface ContinuationFrame {
|
||||
/**
|
||||
* Step the evaluation forward once.
|
||||
* 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
|
||||
|
||||
/**
|
||||
* The OpHalt instruction wants us to "jump to" the END of the nearest meta-eval.
|
||||
* In other words, we should consume Evaluate frames until we hit a FinishEval or Thoth frame.
|
||||
* @return whether the break should stop here, alongside the new stack state (e.g. for finalizing a Thoth)
|
||||
*/
|
||||
fun breakDownwards(stack: List<Iota>): Pair<Boolean, List<Iota>>
|
||||
|
||||
/**
|
||||
* Serializes this frame. Used for things like delays, where we pause execution.
|
||||
*/
|
||||
fun serializeToNBT(): CompoundTag
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromNBT(tag: CompoundTag, world: ServerLevel): ContinuationFrame {
|
||||
return when (tag.getString("type")) {
|
||||
"eval" -> FrameEvaluate(
|
||||
HexIotaTypes.LIST.deserialize(
|
||||
tag.getList("patterns", Tag.TAG_COMPOUND),
|
||||
world
|
||||
)!!.list,
|
||||
tag.getBoolean("isMetacasting")
|
||||
)
|
||||
|
||||
"end" -> FrameFinishEval
|
||||
"foreach" -> FrameForEach(
|
||||
HexIotaTypes.LIST.deserialize(tag.getList("data", Tag.TAG_COMPOUND), world)!!.list,
|
||||
HexIotaTypes.LIST.deserialize(tag.getList("code", Tag.TAG_COMPOUND), world)!!.list,
|
||||
if (tag.hasList("base", Tag.TAG_COMPOUND))
|
||||
HexIotaTypes.LIST.deserialize(tag.getList("base", Tag.TAG_COMPOUND), world)!!.list.toList()
|
||||
else
|
||||
null,
|
||||
HexIotaTypes.LIST.deserialize(
|
||||
tag.getList("accumulator", Tag.TAG_COMPOUND),
|
||||
world
|
||||
)!!.list.toMutableList()
|
||||
)
|
||||
|
||||
else -> FrameEvaluate(SpellList.LList(0, listOf()), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package at.petrak.hexcasting.api.spell.casting.eval
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness
|
||||
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import at.petrak.hexcasting.api.utils.serializeToNBT
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
/**
|
||||
* A list of patterns to be evaluated in sequence.
|
||||
* @property list the *remaining* list of patterns to be evaluated
|
||||
* @property isMetacasting only for sound effects, if this is being cast from a hermes / iris
|
||||
*/
|
||||
data class FrameEvaluate(val list: SpellList, val isMetacasting: Boolean) : ContinuationFrame {
|
||||
// Discard this frame and keep discarding frames.
|
||||
override fun breakDownwards(stack: List<Iota>) = false to stack
|
||||
|
||||
// Step the list of patterns, evaluating a single one.
|
||||
override fun evaluate(
|
||||
continuation: SpellContinuation,
|
||||
level: ServerLevel,
|
||||
harness: CastingHarness
|
||||
): CastingHarness.CastResult {
|
||||
// If there are patterns left...
|
||||
return if (list.nonEmpty) {
|
||||
val newCont = if (list.cdr.nonEmpty) { // yay TCO
|
||||
// ...enqueue the evaluation of the rest of the patterns...
|
||||
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)
|
||||
if (this.isMetacasting && update.sound != HexEvalSounds.MISHAP) {
|
||||
update.copy(sound = HexEvalSounds.HERMES)
|
||||
} else {
|
||||
update
|
||||
}
|
||||
} else {
|
||||
// If there are no patterns (e.g. empty Hermes), just return OK.
|
||||
CastingHarness.CastResult(continuation, null, ResolvedPatternType.EVALUATED, listOf(), HexEvalSounds.HERMES)
|
||||
}
|
||||
}
|
||||
|
||||
override fun serializeToNBT() = NBTBuilder {
|
||||
"type" %= "evaluate"
|
||||
"patterns" %= list.serializeToNBT()
|
||||
"isMetacasting" %= isMetacasting
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package at.petrak.hexcasting.api.spell.casting.eval
|
||||
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness
|
||||
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
/**
|
||||
* A stack marker representing the end of a Hermes evaluation,
|
||||
* so that we know when to stop removing frames during a Halt.
|
||||
*/
|
||||
object FrameFinishEval : ContinuationFrame {
|
||||
// Don't do anything else to the stack, just finish the halt statement.
|
||||
override fun breakDownwards(stack: List<Iota>) = true to stack
|
||||
|
||||
// Evaluating it does nothing; it's only a boundary condition.
|
||||
override fun evaluate(
|
||||
continuation: SpellContinuation,
|
||||
level: ServerLevel,
|
||||
harness: CastingHarness
|
||||
): CastingHarness.CastResult {
|
||||
return CastingHarness.CastResult(
|
||||
continuation,
|
||||
FunctionalData(harness.stack.toList(), 0, listOf(), false, harness.ravenmind),
|
||||
ResolvedPatternType.EVALUATED,
|
||||
listOf(),
|
||||
HexEvalSounds.NOTHING,
|
||||
)
|
||||
}
|
||||
|
||||
override fun serializeToNBT() = NBTBuilder {
|
||||
"type" %= "end"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package at.petrak.hexcasting.api.spell.casting.eval
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness
|
||||
import at.petrak.hexcasting.api.spell.casting.ResolvedPatternType
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.iota.ListIota
|
||||
import at.petrak.hexcasting.api.utils.NBTBuilder
|
||||
import at.petrak.hexcasting.api.utils.serializeToNBT
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
|
||||
/**
|
||||
* A frame representing all the state for a Thoth evaluation.
|
||||
* Pushed by an OpForEach.
|
||||
* @property first whether the input stack state is the first one (since we don't want to save the base-stack before any changes are made)
|
||||
* @property data list of *remaining* datums to ForEach over
|
||||
* @property code code to run per datum
|
||||
* @property baseStack the stack state at Thoth entry
|
||||
* @property acc concatenated list of final stack states after Thoth exit
|
||||
*/
|
||||
data class FrameForEach(
|
||||
val data: SpellList,
|
||||
val code: SpellList,
|
||||
val baseStack: List<Iota>?,
|
||||
val acc: MutableList<Iota>
|
||||
) : ContinuationFrame {
|
||||
|
||||
/** When halting, we add the stack state at halt to the stack accumulator, then return the original pre-Thoth stack, plus the accumulator. */
|
||||
override fun breakDownwards(stack: List<Iota>): Pair<Boolean, List<Iota>> {
|
||||
val newStack = baseStack?.toMutableList() ?: mutableListOf()
|
||||
acc.addAll(stack)
|
||||
newStack.add(ListIota(acc))
|
||||
return true to newStack
|
||||
}
|
||||
|
||||
/** Step the Thoth computation, enqueueing one code evaluation. */
|
||||
override fun evaluate(
|
||||
continuation: SpellContinuation,
|
||||
level: ServerLevel,
|
||||
harness: CastingHarness
|
||||
): CastingHarness.CastResult {
|
||||
// If this isn't the very first Thoth step (i.e. no Thoth computations run yet)...
|
||||
val stack = if (baseStack == null) {
|
||||
// init stack to the harness stack...
|
||||
harness.stack.toList()
|
||||
} else {
|
||||
// else save the stack to the accumulator and reuse the saved base stack.
|
||||
acc.addAll(harness.stack)
|
||||
baseStack
|
||||
}
|
||||
|
||||
// If we still have data to process...
|
||||
val (stackTop, newCont) = if (data.nonEmpty) {
|
||||
// Increment the evaluation depth,
|
||||
harness.ctx.incDepth()
|
||||
// push the next datum to the top of the stack,
|
||||
data.car to continuation
|
||||
// put the next Thoth object back on the stack for the next Thoth cycle,
|
||||
.pushFrame(FrameForEach(data.cdr, code, stack, acc))
|
||||
// and prep the Thoth'd code block for evaluation.
|
||||
.pushFrame(FrameEvaluate(code, true))
|
||||
} else {
|
||||
// Else, dump our final list onto the stack.
|
||||
ListIota(acc) to continuation
|
||||
}
|
||||
val tStack = stack.toMutableList()
|
||||
tStack.add(stackTop)
|
||||
// TODO: this means we could have Thoth casting do a different sound
|
||||
return CastingHarness.CastResult(
|
||||
newCont,
|
||||
FunctionalData(tStack, 0, listOf(), false, harness.ravenmind),
|
||||
ResolvedPatternType.EVALUATED,
|
||||
listOf(),
|
||||
HexEvalSounds.THOTH,
|
||||
)
|
||||
}
|
||||
|
||||
override fun serializeToNBT() = NBTBuilder {
|
||||
"type" %= "foreach"
|
||||
"data" %= data.serializeToNBT()
|
||||
"code" %= code.serializeToNBT()
|
||||
if (baseStack != null)
|
||||
"base" %= baseStack.serializeToNBT()
|
||||
"accumulator" %= acc.serializeToNBT()
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package at.petrak.hexcasting.api.spell.casting
|
||||
package at.petrak.hexcasting.api.spell.casting.eval
|
||||
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package at.petrak.hexcasting.api.spell.casting
|
||||
package at.petrak.hexcasting.api.spell.casting.eval
|
||||
|
||||
/**
|
||||
* A continuation during the execution of a spell.
|
|
@ -12,4 +12,7 @@ import org.jetbrains.annotations.Nullable;
|
|||
* shortcutMetacasting takes precedence over this.
|
||||
*/
|
||||
public record EvalSound(@Nullable SoundEvent sound, int priority) {
|
||||
public EvalSound greaterOf(EvalSound that) {
|
||||
return (this.priority > that.priority) ? this : that;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package at.petrak.hexcasting.api.spell.casting.sideeffects
|
||||
|
||||
/**
|
||||
* Package for all the side effects that happen during one cast.
|
||||
*
|
||||
* This lives outside of nested evaluations so we don't get giant sound spam
|
||||
*/
|
||||
class SideEffectsTracker private constructor(private val ops: MutableList<OperatorSideEffect>, private var sound: EvalSound) {
|
||||
public constructor() : this(mutableListOf(), EvalSound.NONE)
|
||||
}
|
|
@ -4,8 +4,9 @@ import at.petrak.hexcasting.api.spell.Action
|
|||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.SpellList
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.ContinuationFrame
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.FrameEvaluate
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.FrameFinishEval
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.evaluatable
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.iota.PatternIota
|
||||
|
@ -27,14 +28,14 @@ object OpEval : Action {
|
|||
// if not installed already...
|
||||
// also, never make a break boundary when evaluating just one pattern
|
||||
val newCont =
|
||||
if (instrs.left().isPresent || (continuation is SpellContinuation.NotDone && continuation.frame is ContinuationFrame.FinishEval)) {
|
||||
if (instrs.left().isPresent || (continuation is SpellContinuation.NotDone && continuation.frame is FrameFinishEval)) {
|
||||
continuation
|
||||
} else {
|
||||
continuation.pushFrame(ContinuationFrame.FinishEval) // install a break-boundary after eval
|
||||
continuation.pushFrame(FrameFinishEval) // install a break-boundary after eval
|
||||
}
|
||||
|
||||
val instrsList = instrs.map({ SpellList.LList(0, listOf(PatternIota(it))) }, { it })
|
||||
val frame = ContinuationFrame.Evaluate(instrsList)
|
||||
val frame = FrameEvaluate(instrsList, true)
|
||||
return OperationResult(newCont.pushFrame(frame), stack, ravenmind, listOf())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.eval
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
|
||||
object OpEvalDelay : Action {
|
||||
|
|
|
@ -3,8 +3,8 @@ package at.petrak.hexcasting.common.casting.operators.eval
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.ContinuationFrame
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.FrameForEach
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getList
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
@ -24,7 +24,7 @@ object OpForEach : Action {
|
|||
stack.removeLastOrNull()
|
||||
stack.removeLastOrNull()
|
||||
|
||||
val frame = ContinuationFrame.ForEach(datums, instrs, null, mutableListOf())
|
||||
val frame = FrameForEach(datums, instrs, null, mutableListOf())
|
||||
|
||||
return OperationResult(
|
||||
continuation.pushFrame(frame),
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.eval
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
|
||||
object OpHalt : Action {
|
||||
|
|
|
@ -4,7 +4,7 @@ import at.petrak.hexcasting.api.spell.Action
|
|||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.asActionResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getPositiveIntUnderInclusive
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.local
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.orNull
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.local
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import at.petrak.hexcasting.api.spell.Action
|
|||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.RenderedSpell
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.OperatorSideEffect
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.stack
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getPositiveInt
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.stack
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getPositiveInt
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.stack
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getPositiveIntUnderInclusive
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.stack
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.getPositiveIntUnderInclusive
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
import at.petrak.hexcasting.api.spell.mishaps.MishapNotEnoughArgs
|
||||
|
|
|
@ -3,7 +3,7 @@ package at.petrak.hexcasting.common.casting.operators.stack
|
|||
import at.petrak.hexcasting.api.spell.Action
|
||||
import at.petrak.hexcasting.api.spell.OperationResult
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingContext
|
||||
import at.petrak.hexcasting.api.spell.casting.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.casting.eval.SpellContinuation
|
||||
import at.petrak.hexcasting.api.spell.iota.DoubleIota
|
||||
import at.petrak.hexcasting.api.spell.iota.Iota
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ public class HexSounds {
|
|||
public static final SoundEvent FAIL_PATTERN = sound("casting.fail_pattern");
|
||||
public static final SoundEvent CASTING_AMBIANCE = sound("casting.ambiance");
|
||||
public static final SoundEvent ACTUALLY_CAST = sound("casting.cast");
|
||||
public static final SoundEvent CAST_HERMES = sound("casting.hermes");
|
||||
public static final SoundEvent CAST_THOTH = sound("casting.thoth");
|
||||
|
||||
public static final SoundEvent ABACUS = sound("abacus");
|
||||
public static final SoundEvent ABACUS_SHAKE = sound("abacus.shake");
|
||||
|
|
|
@ -8,13 +8,14 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
||||
public class HexEvalSounds {
|
||||
public static final Registry<EvalSound> REGISTRY = IXplatAbstractions.INSTANCE.getEvalSoundRegistry();
|
||||
|
||||
private static final Map<ResourceLocation, EvalSound> TYPES = new LinkedHashMap<>();
|
||||
private static final Map<ResourceLocation, EvalSound> SOUNDS = new LinkedHashMap<>();
|
||||
|
||||
public static final EvalSound NOTHING = make("nothing",
|
||||
new EvalSound(null, Integer.MIN_VALUE));
|
||||
|
@ -24,12 +25,23 @@ public class HexEvalSounds {
|
|||
new EvalSound(HexSounds.ACTUALLY_CAST, 1000));
|
||||
public static final EvalSound MISHAP = make("mishap",
|
||||
new EvalSound(HexSounds.FAIL_PATTERN, Integer.MAX_VALUE));
|
||||
public static final EvalSound HERMES = make("hermes",
|
||||
new EvalSound(HexSounds.CAST_HERMES, Integer.MAX_VALUE));
|
||||
public static final EvalSound THOTH = make("thoth",
|
||||
new EvalSound(HexSounds.CAST_THOTH, Integer.MAX_VALUE));
|
||||
|
||||
private static EvalSound make(String name, EvalSound sound) {
|
||||
var old = TYPES.put(modLoc(name), sound);
|
||||
var old = SOUNDS.put(modLoc(name), sound);
|
||||
if (old != null) {
|
||||
throw new IllegalArgumentException("Typo? Duplicate id " + name);
|
||||
}
|
||||
return sound;
|
||||
}
|
||||
|
||||
public static void registerTypes() {
|
||||
BiConsumer<EvalSound, ResourceLocation> r = (type, id) -> Registry.register(REGISTRY, id, type);
|
||||
for (var e : SOUNDS.entrySet()) {
|
||||
r.accept(e.getValue(), e.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,18 @@
|
|||
"hexcasting:cast_hex"
|
||||
]
|
||||
},
|
||||
|
||||
"casting.hermes": {
|
||||
"subtitle": "hexcasting.subtitles.cast",
|
||||
"sounds": [
|
||||
"hexcasting:hermes"
|
||||
]
|
||||
},
|
||||
"casting.thoth": {
|
||||
"subtitle": "hexcasting.subtitles.cast",
|
||||
"sounds": [
|
||||
"hexcasting:thoth"
|
||||
]
|
||||
},
|
||||
"abacus": {
|
||||
"subtitle": "hexcasting.subtitles.abacus",
|
||||
"sounds": [
|
||||
|
@ -58,7 +69,6 @@
|
|||
"hexcasting:abacus_shake"
|
||||
]
|
||||
},
|
||||
|
||||
"spellcircle.find_block": {
|
||||
"sounds": [
|
||||
{
|
||||
|
@ -83,7 +93,6 @@
|
|||
],
|
||||
"subtitle": "hexcasting.subtitles.spellcircle.cast"
|
||||
},
|
||||
|
||||
"scroll.dust": {
|
||||
"sounds": [
|
||||
"minecraft:dig/sand1",
|
||||
|
@ -101,7 +110,6 @@
|
|||
],
|
||||
"subtitle": "hexcasting.subtitles.scroll.scribble"
|
||||
},
|
||||
|
||||
"impetus.fletcher.tick": {
|
||||
"sounds": [
|
||||
"minecraft:note/hat"
|
||||
|
@ -114,7 +122,6 @@
|
|||
],
|
||||
"subtitle": "hexcasting.subtitles.impetus.cleric.register"
|
||||
},
|
||||
|
||||
"lore_fragment.read": {
|
||||
"sounds": [
|
||||
"block/enchantment_table/enchant1",
|
||||
|
|
BIN
Common/src/main/resources/assets/hexcasting/sounds/hermes.ogg
Normal file
BIN
Common/src/main/resources/assets/hexcasting/sounds/hermes.ogg
Normal file
Binary file not shown.
BIN
Common/src/main/resources/assets/hexcasting/sounds/thoth.ogg
Normal file
BIN
Common/src/main/resources/assets/hexcasting/sounds/thoth.ogg
Normal file
Binary file not shown.
|
@ -11,6 +11,7 @@ import at.petrak.hexcasting.api.player.FlightAbility;
|
|||
import at.petrak.hexcasting.api.player.Sentinel;
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness;
|
||||
import at.petrak.hexcasting.api.spell.casting.ResolvedPattern;
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.EvalSound;
|
||||
import at.petrak.hexcasting.api.spell.iota.IotaType;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import at.petrak.hexcasting.common.network.IMessage;
|
||||
|
@ -24,6 +25,7 @@ import at.petrak.hexcasting.mixin.accessor.AccessorVillager;
|
|||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import at.petrak.hexcasting.xplat.IXplatTags;
|
||||
import at.petrak.hexcasting.xplat.Platform;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.jamieswhiteshirt.reachentityattributes.ReachEntityAttributes;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import net.fabricmc.api.EnvType;
|
||||
|
@ -79,6 +81,7 @@ import virtuoel.pehkui.api.ScaleTypes;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
@ -258,7 +261,7 @@ public class FabricXplatImpl implements IXplatAbstractions {
|
|||
|
||||
@Override
|
||||
public <T extends BlockEntity> BlockEntityType<T> createBlockEntityType(BiFunction<BlockPos, BlockState, T> func,
|
||||
Block... blocks) {
|
||||
Block... blocks) {
|
||||
return FabricBlockEntityTypeBuilder.create(func::apply, blocks).build();
|
||||
}
|
||||
|
||||
|
@ -409,17 +412,27 @@ public class FabricXplatImpl implements IXplatAbstractions {
|
|||
return namespace;
|
||||
}
|
||||
|
||||
private static Registry<IotaType<?>> IOTA_TYPE_REGISTRY = null;
|
||||
private static final Supplier<Registry<IotaType<?>>> IOTA_TYPE_REGISTRY = Suppliers.memoize(() ->
|
||||
FabricRegistryBuilder.from(new DefaultedRegistry<IotaType<?>>(
|
||||
HexAPI.MOD_ID + ":null", ResourceKey.createRegistryKey(modLoc("iota_type")),
|
||||
Lifecycle.stable(), null))
|
||||
.buildAndRegister()
|
||||
);
|
||||
private static final Supplier<Registry<EvalSound>> EVAL_SOUNDS_REGISTRY = Suppliers.memoize(() ->
|
||||
FabricRegistryBuilder.from(new DefaultedRegistry<EvalSound>(
|
||||
HexAPI.MOD_ID + ":nothing", ResourceKey.createRegistryKey(modLoc("eval_sound")),
|
||||
Lifecycle.stable(), null))
|
||||
.buildAndRegister()
|
||||
);
|
||||
|
||||
@Override
|
||||
public Registry<IotaType<?>> getIotaTypeRegistry() {
|
||||
if (IOTA_TYPE_REGISTRY == null) {
|
||||
IOTA_TYPE_REGISTRY = FabricRegistryBuilder.from(new DefaultedRegistry<IotaType<?>>(
|
||||
HexAPI.MOD_ID + ":null", ResourceKey.createRegistryKey(modLoc("iota_type")),
|
||||
Lifecycle.stable(), null))
|
||||
.buildAndRegister();
|
||||
}
|
||||
return IOTA_TYPE_REGISTRY;
|
||||
return IOTA_TYPE_REGISTRY.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registry<EvalSound> getEvalSoundRegistry() {
|
||||
return EVAL_SOUNDS_REGISTRY.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,10 +12,12 @@ import at.petrak.hexcasting.api.player.Sentinel;
|
|||
import at.petrak.hexcasting.api.spell.casting.CastingContext;
|
||||
import at.petrak.hexcasting.api.spell.casting.CastingHarness;
|
||||
import at.petrak.hexcasting.api.spell.casting.ResolvedPattern;
|
||||
import at.petrak.hexcasting.api.spell.casting.sideeffects.EvalSound;
|
||||
import at.petrak.hexcasting.api.spell.iota.IotaType;
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
|
||||
import at.petrak.hexcasting.common.lib.HexItems;
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds;
|
||||
import at.petrak.hexcasting.common.lib.hex.HexIotaTypes;
|
||||
import at.petrak.hexcasting.common.network.IMessage;
|
||||
import at.petrak.hexcasting.forge.cap.CapSyncers;
|
||||
import at.petrak.hexcasting.forge.cap.HexCapabilities;
|
||||
|
@ -30,6 +32,7 @@ import at.petrak.hexcasting.mixin.accessor.AccessorVillager;
|
|||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import at.petrak.hexcasting.xplat.IXplatTags;
|
||||
import at.petrak.hexcasting.xplat.Platform;
|
||||
import com.google.common.base.Suppliers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
|
@ -83,6 +86,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
import static net.minecraftforge.fluids.capability.IFluidHandler.FluidAction.EXECUTE;
|
||||
|
@ -414,16 +418,25 @@ public class ForgeXplatImpl implements IXplatAbstractions {
|
|||
return namespace;
|
||||
}
|
||||
|
||||
private static Registry<IotaType<?>> IOTA_TYPE_REGISTRY = null;
|
||||
private static final Supplier<Registry<IotaType<?>>> IOTA_TYPE_REGISTRY = Suppliers.memoize(() ->
|
||||
ForgeAccessorRegistry.hex$registerDefaulted(
|
||||
ResourceKey.createRegistryKey(modLoc("iota_type")),
|
||||
HexAPI.MOD_ID + ":null", registry -> HexIotaTypes.NULL)
|
||||
);
|
||||
private static final Supplier<Registry<EvalSound>> EVAL_SOUND_REGISTRY = Suppliers.memoize(() ->
|
||||
ForgeAccessorRegistry.hex$registerDefaulted(
|
||||
ResourceKey.createRegistryKey(modLoc("eval_sound")),
|
||||
HexAPI.MOD_ID + ":nothing", registry -> HexEvalSounds.NOTHING)
|
||||
);
|
||||
|
||||
@Override
|
||||
public Registry<IotaType<?>> getIotaTypeRegistry() {
|
||||
if (IOTA_TYPE_REGISTRY == null) {
|
||||
IOTA_TYPE_REGISTRY = ForgeAccessorRegistry.hex$registerDefaulted(
|
||||
ResourceKey.createRegistryKey(modLoc("iota_type")),
|
||||
HexAPI.MOD_ID + ":null", registry -> HexIotaTypes.NULL);
|
||||
}
|
||||
return IOTA_TYPE_REGISTRY;
|
||||
return IOTA_TYPE_REGISTRY.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Registry<EvalSound> getEvalSoundRegistry() {
|
||||
return EVAL_SOUND_REGISTRY.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue