Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

- Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @slava110

### Changed

- Changed the argument order for Thoth's Gambit to take data first ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid
- Changed Thoth's Gambit to accept single iotas as the loop body ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid
- Changed Thoth's Gambit to be a special handler with a new shape ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid
- Changed Thoth's Gambit to use a context stack for iterations, and restore stashed iotas at the end ([#1106](https://github.com/FallingColors/HexMod/pull/1106)) @IridescentVoid

### Fixed

- Fixed Entity Iota comparison to use `equals` on entity IDs instead of reference equality ([#1101](https://github.com/FallingColors/HexMod/pull/1101)) @IridescentVoid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,27 @@ import net.minecraft.network.RegistryFriendlyByteBuf
import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec
import net.minecraft.server.level.ServerLevel
import java.util.*
import kotlin.jvm.optionals.getOrNull

/**
* 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
* @property contextStack the stack state used for each iteration
* @property stashedStack the stack state to restore after all iterations finish
* @property acc concatenated list of final stack states after each iteration
*/
data class FrameForEach(
val data: SpellList,
val code: SpellList,
val baseStack: List<Iota>?,
val contextStack: List<Iota>,
val stashedStack: List<Iota>,
val acc: TreeList<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. */
/** When halting, we add the stack state at halt to the stack accumulator, then return the stashed stack, plus the accumulator. */
override fun breakDownwards(stack: List<Iota>): Pair<Boolean, List<Iota>> {
val newStack = baseStack?.toMutableList() ?: mutableListOf()
val newStack = stashedStack.toMutableList()
newStack.add(ListIota(acc.appendedAll(stack)))
return true to newStack
}
Expand All @@ -46,42 +45,40 @@ data class FrameForEach(
level: ServerLevel,
harness: CastingVM
): CastResult {
// If this is the very first Thoth step (i.e. no Thoth computations run yet)...
val (stack, newAcc) = if (baseStack == null) {
// init stack to the harness stack...
harness.image.stack.toList() to acc
} else {
// else save the stack to the accumulator and reuse the saved base stack.
baseStack to acc.appendedAll(harness.image.stack)
}
// Save the stack to the accumulator. On the first iteration, the stack will be empty.
val newAcc = acc.appendedAll(harness.image.stack)

// If we still have data to process...
val (stackTop, newImage, newCont) = if (data.nonEmpty) {
val (newStack, newImage, newCont) = if (data.nonEmpty) {
// Restore the context stack,
val stack = contextStack.toMutableList()
// push the next datum to the top of the stack,
stack.add(data.car)
val cont2 = continuation
// put the next Thoth object back on the stack for the next Thoth cycle,
.pushFrame(FrameForEach(data.cdr, code, stack, newAcc))
.pushFrame(FrameForEach(data.cdr, code, contextStack, stashedStack, newAcc))
// and prep the Thoth'd code block for evaluation.
.pushFrame(FrameEvaluate(code, true))
Triple(data.car, harness.image.withUsedOp(), cont2)
Triple(stack, harness.image.withUsedOp(), cont2)
} else {
// Else, dump our final list onto the stack.
Triple(ListIota(newAcc), harness.image, continuation)
// Else, restore the stashed stack,
val stack = stashedStack.toMutableList()
// and dump our final list onto the stack.
stack.add(ListIota(newAcc))
Triple(stack, harness.image, continuation)
}
val tStack = stack.toMutableList()
tStack.add(stackTop)
return CastResult(
ListIota(code),
newCont,
// reset escapes so they don't carry over to other iterations or out of thoth
newImage.withResetEscape().copy(stack = tStack),
newImage.withResetEscape().copy(stack = newStack),
listOf(),
ResolvedPatternType.EVALUATED,
HexEvalSounds.THOTH,
)
}

override fun size() = data.size() + code.size() + acc.size + (baseStack?.size ?: 0)
override fun size() = data.size() + code.size() + acc.size + contextStack.size + stashedStack.size

override val type: ContinuationFrame.Type<*> = TYPE

Expand All @@ -92,21 +89,24 @@ data class FrameForEach(
inst.group(
SpellList.CODEC.fieldOf("data").forGetter { it.data },
SpellList.CODEC.fieldOf("code").forGetter { it.code },
IotaType.TYPED_CODEC.listOf().optionalFieldOf("base").forGetter { Optional.ofNullable(it.baseStack) },
IotaType.TYPED_CODEC.listOf().fieldOf("context").forGetter { it.contextStack },
IotaType.TYPED_CODEC.listOf().fieldOf("stashed").forGetter { it.stashedStack },
IotaType.TYPED_CODEC.listOf().fieldOf("accumulator").forGetter { it.acc }
).apply(inst) { a, b, c, d ->
FrameForEach(a, b, c.getOrNull(), TreeList.from(d))
).apply(inst) { a, b, c, d, e ->
FrameForEach(a, b, c, d, TreeList.from(e))
}
}
val STREAM_CODEC = StreamCodec.composite(
SpellList.STREAM_CODEC, FrameForEach::data,
SpellList.STREAM_CODEC, FrameForEach::code,
ByteBufCodecs.optional(IotaType.TYPED_STREAM_CODEC
.apply(ByteBufCodecs.list())), { Optional.ofNullable(it.baseStack) },
IotaType.TYPED_STREAM_CODEC
.apply(ByteBufCodecs.list()), FrameForEach::contextStack,
IotaType.TYPED_STREAM_CODEC
.apply(ByteBufCodecs.list()), FrameForEach::stashedStack,
IotaType.TYPED_STREAM_CODEC
.apply(ByteBufCodecs.list()), FrameForEach::acc
) { a, b, c, d ->
FrameForEach(a, b, c.getOrNull(), TreeList.from(d))
) { a, b, c, d, e ->
FrameForEach(a, b, c, d, TreeList.from(e))
}


Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package at.petrak.hexcasting.common.casting.actions.eval

import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.castables.Action
import at.petrak.hexcasting.api.casting.castables.SpecialHandler
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.OperationResult
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage
import at.petrak.hexcasting.api.casting.eval.vm.FrameForEach
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
import at.petrak.hexcasting.api.casting.evaluatable
import at.petrak.hexcasting.api.casting.getList
import at.petrak.hexcasting.api.casting.math.HexPattern
import at.petrak.hexcasting.api.casting.mishaps.MishapNotEnoughArgs
import at.petrak.hexcasting.api.utils.TreeList
import at.petrak.hexcasting.api.utils.asTranslatedComponent
import at.petrak.hexcasting.api.utils.lightPurple
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds
import at.petrak.hexcasting.common.lib.hex.HexSpecialHandlers
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.network.chat.Component

class SpecialHandlerForEach(val n: Int) : SpecialHandler {
override fun act(): Action {
return InnerAction(n)
}

override fun getName(): Component {
val key = IXplatAbstractions.INSTANCE.specialHandlerRegistry.getResourceKey(HexSpecialHandlers.FOR_EACH).get()
return HexAPI.instance().getSpecialHandlerI18nKey(key)
.asTranslatedComponent(n.toString()).lightPurple
}

class InnerAction(val n: Int) : Action {
override fun operate(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation): OperationResult {
val stack = image.stack.toMutableList()

if (stack.size < 2 + n)
throw MishapNotEnoughArgs(2 + n, stack.size)

val datums = stack.getList(stack.lastIndex - 1, stack.size)
val instrs = evaluatable(stack[stack.lastIndex], 0)
stack.removeLastOrNull()
stack.removeLastOrNull()

val instrList = instrs.map({ SpellList.LList(0, listOf(it)) }, { it })

val contextStack = stack.takeLast(n)
val stashedStack = stack.dropLast(n)

val frame = FrameForEach(datums, instrList, contextStack, stashedStack, TreeList.empty())
val image2 = image.withUsedOp().copy(stack = listOf())

return OperationResult(image2, listOf(), continuation.pushFrame(frame), HexEvalSounds.THOTH)
}
}

class Factory : SpecialHandler.Factory<SpecialHandlerForEach> {
override fun tryMatch(pat: HexPattern, env: CastingEnvironment): SpecialHandlerForEach? {
val sig = pat.anglesSignature()
if (!sig.startsWith("waaddw")) return null

val tail = sig.substring(6)
if (tail.length % 2 != 0) return null

for ((index, segment) in tail.chunked(2).withIndex()) {
when (index % 2) {
0 -> if (segment != "da") return null
1 -> if (segment != "ad") return null
}
}

return SpecialHandlerForEach(tail.length / 2)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,6 @@ public class HexActions {
// new ActionRegistryEntry(HexPattern.fromAngles("qaeaq", HexDir.NORTH_WEST), OpConcat.INSTANCE));
public static final ActionRegistryEntry INDEX = make("index",
new OperationAction(HexPattern.fromAngles("deeed", HexDir.NORTH_WEST)));
public static final ActionRegistryEntry FOR_EACH = make("for_each",
new ActionRegistryEntry(HexPattern.fromAngles("dadad", HexDir.NORTH_EAST), OpForEach.INSTANCE));
// public static final ActionRegistryEntry LIST_SIZE = make("list_size",
// new ActionRegistryEntry(HexPattern.fromAngles("aqaeaq", HexDir.EAST), OpListSize.INSTANCE));
public static final ActionRegistryEntry SINGLETON = make("singleton",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package at.petrak.hexcasting.common.lib.hex;

import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
import at.petrak.hexcasting.common.casting.actions.eval.SpecialHandlerForEach;
import at.petrak.hexcasting.common.casting.actions.math.SpecialHandlerNumberLiteral;
import at.petrak.hexcasting.common.casting.actions.stack.SpecialHandlerMask;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -18,6 +19,8 @@ public class HexSpecialHandlers {
new SpecialHandlerNumberLiteral.Factory());
public static final SpecialHandler.Factory<SpecialHandlerMask> MASK = make("mask",
new SpecialHandlerMask.Factory());
public static final SpecialHandler.Factory<SpecialHandlerForEach> FOR_EACH = make("for_each",
new SpecialHandlerForEach.Factory());

private static <T extends SpecialHandler> SpecialHandler.Factory<T> make(String name,
SpecialHandler.Factory<T> handler) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@ public LootItemFunctionType<? extends LootItemConditionalFunction> getType() {
new Pair<>("hexcasting.loot_hex.ascend", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaae","WEST qqqqqawwawawd"}),
new Pair<>("hexcasting.loot_hex.blink", new String[] {"NORTH_EAST qaq","EAST aadaa","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST wqaawdd","NORTH_EAST qaq","EAST aa","NORTH_WEST wddw","NORTH_EAST wqaqw","SOUTH_EAST aqaaw","NORTH_WEST wddw","SOUTH_WEST awqqqwaq"}),
new Pair<>("hexcasting.loot_hex.blastoff", new String[] {"NORTH_EAST qaq","NORTH_WEST qqqqqew","SOUTH_EAST aqaawaa","SOUTH_EAST waqaw","SOUTH_WEST awqqqwaqw"}),
new Pair<>("hexcasting.loot_hex.radar", new String[] {"WEST qqq","EAST aadaa","EAST aa","SOUTH_EAST aqaawa","SOUTH_WEST ewdqdwe","NORTH_EAST de","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaeaqq","SOUTH_EAST qqqqqwdeddwd","NORTH_EAST dadad"}),
new Pair<>("hexcasting.loot_hex.radar", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaeaqq","SOUTH_EAST qqqqqwdeddwd","WEST qqq","EAST aadaa","EAST aa","SOUTH_EAST aqaawa","SOUTH_WEST ewdqdwe","NORTH_EAST de","EAST eee","EAST waaddw"}),
new Pair<>("hexcasting.loot_hex.beckon", new String[] {"NORTH_EAST qaq","EAST aa","NORTH_EAST qaq","NORTH_EAST wa","EAST weaqa","EAST aadaa","EAST dd","NORTH_EAST qaq","EAST aa","EAST aawdd","NORTH_WEST wddw","EAST aadaa","NORTH_EAST wqaqw","NORTH_EAST wdedw","SOUTH_EAST aqaawa","SOUTH_EAST waqaw","SOUTH_WEST awqqqwaqw"}),
new Pair<>("hexcasting.loot_hex.detonate", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaaedwd","EAST ddwddwdd"}),
new Pair<>("hexcasting.loot_hex.shockwave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaawaa","EAST aadaadaa","SOUTH_EAST aqawqadaq","SOUTH_EAST aqaaedwd","EAST aawaawaa","NORTH_EAST qqa","EAST qaqqqqq"}),
new Pair<>("hexcasting.loot_hex.heat_wave", new String[] {"WEST qqq","SOUTH_EAST aaqawawa","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwded","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadad"}),
new Pair<>("hexcasting.loot_hex.wither_wave", new String[] {"WEST qqq","SOUTH_EAST aqaae","SOUTH_EAST aqaaw","SOUTH_WEST qqqqqaewawawe","EAST eee","NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwdeddwd","SOUTH_WEST aaqwqaa","SOUTH_EAST a","NORTH_EAST dadad"}),
new Pair<>("hexcasting.loot_hex.flight_zone", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaaq","SOUTH_WEST awawaawq"})
new Pair<>("hexcasting.loot_hex.heat_wave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwded","SOUTH_WEST aaqwqaa","SOUTH_EAST a","WEST qqq","SOUTH_EAST aaqawawa","EAST eee","EAST waaddw"}),
new Pair<>("hexcasting.loot_hex.wither_wave", new String[] {"NORTH_EAST qaq","EAST aa","SOUTH_EAST aqaae","SOUTH_EAST qqqqqwdeddwd","SOUTH_WEST aaqwqaa","SOUTH_EAST a","WEST qqq","SOUTH_EAST aqaae","SOUTH_EAST aqaaw","SOUTH_WEST qqqqqaewawawe","EAST eee","EAST waaddw"}),
new Pair<>("hexcasting.loot_hex.flight_zone", new String[] {"NORTH_EAST qaq","SOUTH_EAST aqaaq","SOUTH_WEST awawaawq"}),
new Pair<>("hexcasting.loot_hex.magnet", new String[] {"NORTH_EAST qaq","EAST aa","EAST aadaa","SOUTH_EAST aqaaeq","SOUTH_EAST qqqqqwdeddww","WEST qqq","EAST ddqaa","EAST aa","NORTH_WEST wddw","EAST aadaa","NORTH_EAST wqaqw","NORTH_EAST wdedw","SOUTH_WEST awqqqwaqw","EAST eee","EAST waaddwda"})
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@ public void render(GuiGraphics graphics, IComponentRenderContext context, float
: PatternColors.READABLE_GRID_SCROLL_COLORS;
}

int colsInLastRow = (patterns.size() - 1) % cols + 1;
double lastRowOffset = (cols - colsInLastRow) * cellW / 2;
for(int p = 0; p < patterns.size(); p++){

int r = p / cols;
int c = p % cols;
double offset = r < rows - 1 ? 0 : lastRowOffset;
HexPattern pattern = patterns.get(p);

ps.pushPose();
ps.translate(cellW * c, cellH * r + 16, 100);
ps.translate(offset + cellW * c, cellH * r + 16, 100);

PatternRenderer.renderPattern(pattern, graphics.pose(), patSets, patCols, 0, 4);
ps.popPose();
Expand Down
Loading
Loading