Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added

- Updated to Minecraft 1.21.1 ([#985](https://github.com/FallingColors/HexMod/pull/985)) @SuperKnux @slava110
- Added Simulate, which causes the next pattern drawn to be simulated (to check for mishaps) rather than executed ([#1194](https://github.com/FallingColors/HexMod/pull/1194)) @Robotgiggle
- Added the `hex_unbreakable` tag for blocks that should be immune to Break Block regardless of the configured mining tier ([#1186](https://github.com/FallingColors/HexMod/pull/1186)) @Robotgiggle @slava110

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ enum class ResolvedPatternType(val color: Int, val fadeColor: Int, val success:
UNRESOLVED(0x7f7f7f, 0xcccccc, false),
EVALUATED(0x7385de, 0xfecbe6, true),
ESCAPED(0xddcc73, 0xfffae5, true),
SIMULATED(0xed9d64, 0xffecde, true),
UNDONE(0xb26b6b, 0xcca88e, true), // TODO: Pick better colours
ERRORED(0xde6262, 0xffc7a0, false),
INVALID(0xb26b6b, 0xcca88e, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.utils.getOrCreateCompound
import at.petrak.hexcasting.api.utils.putCompound
import at.petrak.hexcasting.api.utils.compositeCodecSeven
import com.mojang.serialization.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.nbt.CompoundTag
Expand All @@ -22,10 +23,11 @@ data class CastingImage(
val parenCount: Int,
val parenthesized: List<ParenthesizedIota>,
val escapeNext: Boolean,
val simulateNext: Boolean,
val opsConsumed: Long,
val userData: CompoundTag
) {
constructor() : this(listOf(), 0, listOf(), false, 0, CompoundTag())
constructor() : this(listOf(), 0, listOf(), false, false, 0, CompoundTag())

/**
* `escaped` is used by [OpUndo][at.petrak.hexcasting.common.casting.actions.escaping.OpUndo] to determine whether the paren count
Expand Down Expand Up @@ -95,22 +97,24 @@ data class CastingImage(
Codec.INT.fieldOf("open_parens").forGetter { it.parenCount },
ParenthesizedIota.CODEC.listOf().fieldOf("parenthesized").forGetter { it.parenthesized },
Codec.BOOL.fieldOf("escape_next").forGetter { it.escapeNext },
Codec.BOOL.fieldOf("simulate_next").forGetter { it.simulateNext },
Codec.LONG.fieldOf("ops_consumed").forGetter { it.opsConsumed },
CompoundTag.CODEC.fieldOf("userData").forGetter { it.userData }
).apply(inst) { a, b, c, d, e, f ->
CastingImage(a, b, c, d, e, f)
).apply(inst) { a, b, c, d, e, f, g ->
CastingImage(a, b, c, d, e, f, g)
}
}.orElseGet(::CastingImage)
@JvmStatic
val STREAM_CODEC = StreamCodec.composite(
val STREAM_CODEC = compositeCodecSeven(
IotaType.TYPED_STREAM_CODEC.apply(ByteBufCodecs.list()), CastingImage::stack,
ByteBufCodecs.VAR_INT, CastingImage::parenCount,
ParenthesizedIota.STREAM_CODEC.apply(ByteBufCodecs.list()), CastingImage::parenthesized,
ByteBufCodecs.BOOL, CastingImage::escapeNext,
ByteBufCodecs.BOOL, CastingImage::simulateNext,
ByteBufCodecs.VAR_LONG, CastingImage::opsConsumed,
ByteBufCodecs.COMPOUND_TAG, { it.userData },
{ a, b, c, d, e, f ->
CastingImage(a, b, c, d, e, f)
{ a, b, c, d, e, f, g ->
CastingImage(a, b, c, d, e, f, g)
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.eval.*
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage.ParenthesizedIota
import at.petrak.hexcasting.api.casting.iota.BooleanIota
import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.iota.ListIota
Expand Down Expand Up @@ -111,7 +112,11 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
ravenmind = IotaType.TYPED_CODEC.encodeStart<Tag?>(NbtOps.INSTANCE, newIota).getOrThrow() as CompoundTag?
}

val isStackClear = image.stack.isEmpty() && image.parenCount == 0 && !image.escapeNext && ravenmind == null
val isStackClear = image.stack.isEmpty()
&& image.parenCount == 0
&& !image.escapeNext
&& !image.simulateNext
&& ravenmind == null

this.env.postCast(image)
return ExecutionClientView(isStackClear, lastResolutionType, image.stack, ravenmind)
Expand Down Expand Up @@ -150,13 +155,28 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.ESCAPED, HexEvalSounds.NORMAL_EXECUTE)
}

if (this.image.parenCount > 0) {
val result = if (this.image.parenCount > 0) {
// Handle parens escaping
return iota.executeInParens(this, world, continuation)
iota.executeInParens(this, world, continuation)
} else {
// Handle normal execution behavior
return iota.execute(this, world, continuation)
iota.execute(this, world, continuation)
}

// if simulating, push a bool for whether the cast would have succeeded; do not perform any side effects
if (this.image.simulateNext) {
val tooBig = result.newData != null && IotaType.isTooLargeToSerialize(result.newData.stack)
val newStack = this.image.stack.toMutableList()
newStack.add(BooleanIota(result.resolutionType.success && !tooBig))
val newImage = this.image.copy(
stack = newStack,
simulateNext = false
)
return CastResult(iota, continuation, newImage, listOf(), ResolvedPatternType.SIMULATED, HexEvalSounds.NORMAL_EXECUTE)
}

// otherwise, return the original CastResult to perform all the side effects, stack manip, etc
return result
} catch (exception: Exception) {
// This means something very bad has happened
exception.printStackTrace()
Expand Down
38 changes: 38 additions & 0 deletions Common/src/main/java/at/petrak/hexcasting/api/utils/HexUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import at.petrak.hexcasting.api.casting.iota.NullIota
import at.petrak.hexcasting.api.casting.math.HexCoord
import at.petrak.hexcasting.api.casting.validateSubIotas
import at.petrak.hexcasting.api.mod.HexTags
import com.mojang.datafixers.util.Function6
import net.minecraft.ChatFormatting
import net.minecraft.core.HolderLookup
import net.minecraft.core.Registry
import net.minecraft.nbt.*
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.Style
import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
Expand All @@ -28,6 +30,7 @@ import net.minecraft.world.phys.Vec2
import net.minecraft.world.phys.Vec3
import java.lang.ref.WeakReference
import java.util.*
import java.util.function.Function
import kotlin.math.absoluteValue
import kotlin.math.max
import kotlin.math.min
Expand Down Expand Up @@ -330,3 +333,38 @@ fun <T : Iota> validateIotaList(iotaList: List<T>, serverLevel: ServerLevel): Li
return iotaList.map { validateIota(it, serverLevel) }
}


// vanilla's StreamCodec.composite() only supports up to six fields in 1.21
fun <B, C, T1, T2, T3, T4, T5, T6, T7> compositeCodecSeven(
streamCodec1: StreamCodec<in B, T1>, function1: Function<C, T1>,
streamCodec2: StreamCodec<in B, T2>, function2: Function<C, T2>,
streamCodec3: StreamCodec<in B, T3>, function3: Function<C, T3>,
streamCodec4: StreamCodec<in B, T4>, function4: Function<C, T4>,
streamCodec5: StreamCodec<in B, T5>, function5: Function<C, T5>,
streamCodec6: StreamCodec<in B, T6>, function6: Function<C, T6>,
streamCodec7: StreamCodec<in B, T7>, function7: Function<C, T7>,
createFunction: Function7<T1, T2, T3, T4, T5, T6, T7, C>
): StreamCodec<B, C> {
return object : StreamCodec<B, C> {
override fun decode(stream: B): C {
val field1 = streamCodec1.decode(stream)
val field2 = streamCodec2.decode(stream)
val field3 = streamCodec3.decode(stream)
val field4 = streamCodec4.decode(stream)
val field5 = streamCodec5.decode(stream)
val field6 = streamCodec6.decode(stream)
val field7 = streamCodec7.decode(stream)
return createFunction.invoke(field1, field2, field3, field4, field5, field6, field7)
}

override fun encode(stream: B, obj: C) {
streamCodec1.encode(stream, function1.apply(obj))
streamCodec2.encode(stream, function2.apply(obj))
streamCodec3.encode(stream, function3.apply(obj))
streamCodec4.encode(stream, function4.apply(obj))
streamCodec5.encode(stream, function5.apply(obj))
streamCodec6.encode(stream, function6.apply(obj))
streamCodec7.encode(stream, function7.apply(obj))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public ControlFlow acceptControlFlow(CastingImage imageIn, CircleCastEnv env, Di
? bs.getValue(FACING).getOpposite()
: bs.getValue(FACING);
var imageOut = imageIn.copy(stack, imageIn.getParenCount(), imageIn.getParenthesized(),
imageIn.getEscapeNext(), imageIn.getOpsConsumed(), imageIn.getUserData());
imageIn.getEscapeNext(), imageIn.getSimulateNext(), imageIn.getOpsConsumed(), imageIn.getUserData());

return new ControlFlow.Continue(imageOut, List.of(this.exitPositionFromDirection(pos, outputDir)));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package at.petrak.hexcasting.common.casting.actions.escaping

import at.petrak.hexcasting.api.casting.castables.Action
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.SpellContinuation
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds

object OpSimulate : Action {
override fun operate(env: CastingEnvironment, image: CastingImage, continuation: SpellContinuation): OperationResult {
val image2 = image.copy(
simulateNext = true
)
return OperationResult(image2, listOf(), continuation, HexEvalSounds.NORMAL_EXECUTE)
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,9 @@ public class HexActions {
public static final ActionRegistryEntry UNDO = make("undo",
new ActionRegistryEntry(HexPattern.fromAngles("eeedw", HexDir.EAST), OpUndo.INSTANCE));

public static final ActionRegistryEntry SIMULATE = make("simulate",
new ActionRegistryEntry(HexPattern.fromAngles("deaq", HexDir.EAST), OpSimulate.INSTANCE));

// http://www.toroidalsnark.net/mkss3-pix/CalderheadJMM2014.pdf
// eval being a space filling curve feels apt doesn't it
public static final ActionRegistryEntry EVAL = make("eval",
Expand All @@ -414,14 +417,6 @@ public class HexActions {
new ActionRegistryEntry(HexPattern.fromAngles("deeeee", HexDir.EAST), OpWrite.INSTANCE));
public static final ActionRegistryEntry WRITE$ENTITY = make("write/entity",
new ActionRegistryEntry(HexPattern.fromAngles("wdwewewewewew", HexDir.EAST), OpTheCoolerWrite.INSTANCE));
public static final ActionRegistryEntry READABLE = make("readable",
new ActionRegistryEntry(HexPattern.fromAngles("aqqqqqe", HexDir.EAST), OpReadable.INSTANCE));
public static final ActionRegistryEntry READABLE$ENTITY = make("readable/entity",
new ActionRegistryEntry(HexPattern.fromAngles("wawqwqwqwqwqwew", HexDir.EAST), OpTheCoolerReadable.INSTANCE));
public static final ActionRegistryEntry WRITABLE = make("writable",
new ActionRegistryEntry(HexPattern.fromAngles("deeeeeq", HexDir.EAST), OpWritable.INSTANCE));
public static final ActionRegistryEntry WRITABLE$ENTITY = make("writable/entity",
new ActionRegistryEntry(HexPattern.fromAngles("wdwewewewewewqw", HexDir.EAST), OpTheCoolerWritable.INSTANCE));

public static final ActionRegistryEntry READ$LOCAL = make("read/local",
new ActionRegistryEntry(HexPattern.fromAngles("qeewdweddw", HexDir.NORTH_EAST), OpPeekLocal.INSTANCE));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -845,11 +845,7 @@
write: "Scribe's Gambit",
"write/entity": "Chronicler's Gambit",
"write/local": "Huginn's Gambit",

readable: "Auditor's Reflection",
"readable/entity": "Auditor's Purification",
writable: "Assessor's Reflection",
"writable/entity": "Assessor's Purification",

"akashic/read": "Akasha's Distillation",
"akashic/write": "Akasha's Gambit",

Expand Down Expand Up @@ -918,6 +914,8 @@
open_paren: "Introspection",
close_paren: "Retrospection",
undo: "Evanition",

simulate: "Simulate",

eval: "Hermes' Gambit",
"eval/cc": "Iris' Gambit",
Expand Down Expand Up @@ -1311,6 +1309,7 @@
patterns_as_iotas: "Escaping Patterns",
readwrite: "Reading and Writing",
meta: "Meta-Evaluation",
mishap_avoidance: "Mishap Avoidance",
circle_patterns: "Spell Circle Patterns",
akashic_patterns: "Akashic Patterns",

Expand Down Expand Up @@ -2012,10 +2011,15 @@

"thanatos.1": "Adds the number of patterns a _Hex is still capable of evaluating to the stack. This is reduced by one for each pattern cast by the _Hex."
},

mishap_avoidance: {
"1": "$(l:casting/mishaps)$(thing)Mishaps/$ can be very annoying. Thankfully, I have found a way to mitigate them. The following pattern can be used to simulate any other pattern, allowing me to find out if it would have succeeded without actually executing it.$(br2)Note that simulating a pattern like $(l:patterns/meta)$(action)Hermes' Gambit/$ will not simulate the resulting meta-evaluation, only the pattern itself.",
simulate: "Causes the next pattern drawn to be simulated rather than actually executed. A simulated pattern does not change the stack, and has no effects apart from pushing a boolean value representing whether it $(o)would/$ have successfully resolved.",
},

circle_patterns: {
disclaimer: "These patterns must be cast from a $(l:greatwork/spellcircles)$(item)Spell Circle/$; trying to cast them through a $(l:items/staff)$(item)Staff/$ will fail rather spectacularly.",

"circle/impetus_pos": "Returns the position of the $(l:greatwork/impetus)$(item)Impetus/$ of this spell circle.",
"circle/impetus_dir": "Returns the direction the $(l:greatwork/impetus)$(item)Impetus/$ of this spell circle is facing as a unit vector.",
"circle/bounds/min": "Returns the position of the lower-north-west corner of the bounds of this spell circle.",
Expand Down
Loading
Loading