meta-eval limit is dead, long live op limit
This commit is contained in:
parent
9a231a634b
commit
e24e642432
9 changed files with 38 additions and 36 deletions
|
@ -113,9 +113,9 @@ public interface HexAPI {
|
|||
*/
|
||||
String RAVENMIND_USERDATA = modLoc("ravenmind").toString();
|
||||
/**
|
||||
* Location in the userdata of the evaluation depth
|
||||
* Location in the userdata of the number of ops executed
|
||||
*/
|
||||
String EVAL_DEPTH_USERDATA = modLoc("eval_depth").toString();
|
||||
String OP_COUNT_USERDATA = modLoc("op_count").toString();
|
||||
|
||||
String MARKED_MOVED_USERDATA = modLoc("impulsed").toString();
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ 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.casting.mishaps.MishapEvalTooDeep
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.Tag
|
||||
|
@ -79,21 +77,6 @@ data class CastingImage private constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if we get too deep.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun incDepth(userData: CompoundTag): CompoundTag {
|
||||
val maxAllowedDepth = HexConfig.server().maxRecurseDepth()
|
||||
val depth = userData.getInt(HexAPI.EVAL_DEPTH_USERDATA)
|
||||
if (depth + 1 > maxAllowedDepth) {
|
||||
throw MishapEvalTooDeep()
|
||||
}
|
||||
|
||||
userData.putInt(HexAPI.EVAL_DEPTH_USERDATA, depth + 1)
|
||||
return userData
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun checkAndMarkGivenMotion(userData: CompoundTag, entity: Entity): Boolean {
|
||||
val marked = userData.getOrCreateCompound(HexAPI.MARKED_MOVED_USERDATA)
|
||||
|
|
|
@ -13,6 +13,7 @@ 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.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.mod.HexTags
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import at.petrak.hexcasting.common.casting.PatternRegistryManifest
|
||||
|
@ -37,6 +38,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
|
|||
* needs to see.
|
||||
*/
|
||||
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
|
||||
|
@ -147,6 +149,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
|
|||
private fun executePattern(newPat: HexPattern, world: ServerLevel, continuation: SpellContinuation): CastResult {
|
||||
var castedName: Component? = null
|
||||
try {
|
||||
|
||||
val lookup = PatternRegistryManifest.matchPattern(newPat, world, false)
|
||||
this.env.precheckAction(lookup)
|
||||
|
||||
|
@ -169,6 +172,17 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
|
|||
throw MishapInvalidPattern()
|
||||
} else throw IllegalStateException()
|
||||
|
||||
val opCount = if (this.image.userData.contains(HexAPI.OP_COUNT_USERDATA)) {
|
||||
this.image.userData.getInt(HexAPI.OP_COUNT_USERDATA)
|
||||
} else {
|
||||
this.image.userData.putInt(HexAPI.OP_COUNT_USERDATA, 0)
|
||||
0
|
||||
}
|
||||
if (opCount + 1 > HexConfig.server().maxOpCount()) {
|
||||
throw MishapEvalTooMuch()
|
||||
}
|
||||
this.image.userData.putInt(HexAPI.OP_COUNT_USERDATA, opCount + 1)
|
||||
|
||||
val sideEffects = mutableListOf<OperatorSideEffect>()
|
||||
var stack2: List<Iota>? = null
|
||||
var cont2 = continuation
|
||||
|
|
|
@ -5,7 +5,7 @@ import at.petrak.hexcasting.api.casting.iota.Iota
|
|||
import at.petrak.hexcasting.api.misc.FrozenColorizer
|
||||
import net.minecraft.world.item.DyeColor
|
||||
|
||||
class MishapEvalTooDeep : Mishap() {
|
||||
class MishapEvalTooMuch : Mishap() {
|
||||
override fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer =
|
||||
dyeColor(DyeColor.BLUE)
|
||||
|
|
@ -56,7 +56,7 @@ public class HexConfig {
|
|||
public interface ServerConfigAccess {
|
||||
int opBreakHarvestLevelBecauseForgeThoughtItWasAGoodIdeaToImplementHarvestTiersUsingAnHonestToGodTopoSort();
|
||||
|
||||
int maxRecurseDepth();
|
||||
int maxOpCount();
|
||||
|
||||
int maxSpellCircleLength();
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class HexConfig {
|
|||
// fun fact, although dimension keys are a RegistryHolder, they aren't a registry, so i can't do tags
|
||||
boolean canTeleportInThisDimension(ResourceKey<Level> dimension);
|
||||
|
||||
int DEFAULT_MAX_RECURSE_DEPTH = 512;
|
||||
int DEFAULT_MAX_OP_COUNT = 1_000_000;
|
||||
int DEFAULT_MAX_SPELL_CIRCLE_LENGTH = 1024;
|
||||
int DEFAULT_OP_BREAK_HARVEST_LEVEL = 3;
|
||||
|
||||
|
|
|
@ -72,15 +72,19 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
|
|||
|
||||
sender.awardStat(HexStatistics.PATTERNS_DRAWN);
|
||||
|
||||
var harness = IXplatAbstractions.INSTANCE.getStaffcastVM(sender, msg.handUsed());
|
||||
var vm = IXplatAbstractions.INSTANCE.getStaffcastVM(sender, msg.handUsed());
|
||||
// every time we send a new pattern it'll be happening in a different tick, so reset here
|
||||
// i don't think we can do this in the casting vm itself because it doesn't know if `queueAndExecuteIotas`
|
||||
// is being called from the top level or not
|
||||
vm.getImage().getUserData().remove(HexAPI.OP_COUNT_USERDATA);
|
||||
|
||||
ExecutionClientView clientInfo = harness.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
|
||||
ExecutionClientView clientInfo = vm.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
|
||||
|
||||
if (clientInfo.isStackClear()) {
|
||||
IXplatAbstractions.INSTANCE.setStaffcastImage(sender, null);
|
||||
IXplatAbstractions.INSTANCE.setPatterns(sender, List.of());
|
||||
} else {
|
||||
IXplatAbstractions.INSTANCE.setStaffcastImage(sender, harness);
|
||||
IXplatAbstractions.INSTANCE.setStaffcastImage(sender, vm);
|
||||
if (!resolvedPatterns.isEmpty()) {
|
||||
resolvedPatterns.get(resolvedPatterns.size() - 1).setType(clientInfo.getResolutionType());
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@
|
|||
"text.autoconfig.hexcasting.option.client.gridSnapThreshold.@Tooltip": "When using a staff, the distance from one dot you have to go to snap to the next dot, where 0.5 means 50% of the way (0.5-1)",
|
||||
|
||||
"text.autoconfig.hexcasting.option.server.opBreakHarvestLevel": "Break Harvest Level",
|
||||
"text.autoconfig.hexcasting.option.server.maxRecurseDepth": "Max Recurse Depth",
|
||||
"text.autoconfig.hexcasting.option.server.maxOpCount": "Max Action Count",
|
||||
"text.autoconfig.hexcasting.option.server.maxSpellCircleLength": "Max Spell Circle Length",
|
||||
"text.autoconfig.hexcasting.option.server.actionDenyList": "Action Deny List",
|
||||
"text.autoconfig.hexcasting.option.server.circleActionDenyList": "Circle Action Deny List",
|
||||
|
@ -218,7 +218,7 @@
|
|||
"text.autoconfig.hexcasting.option.server.scrollInjectionsRaw": "Scroll Injection Weights",
|
||||
"text.autoconfig.hexcasting.option.server.amethystShardModification": "Amethyst Shard Drop Rate Change",
|
||||
"text.autoconfig.hexcasting.option.server.opBreakHarvestLevel.@Tooltip": "The harvest level of the Break Block spell.\n0 = wood, 1 = stone, 2 = iron, 3 = diamond, 4 = netherite.",
|
||||
"text.autoconfig.hexcasting.option.server.maxRecurseDepth.@Tooltip": "How many times an action can recursively cast other actions",
|
||||
"text.autoconfig.hexcasting.option.server.maxOpCount.@Tooltip": "The maximum number of actions that can be executed in one tick, to avoid hanging the server.",
|
||||
"text.autoconfig.hexcasting.option.server.maxSpellCircleLength.@Tooltip": "The maximum number of slates in a spell circle",
|
||||
"text.autoconfig.hexcasting.option.server.actionDenyList.@Tooltip": "Resource locations of disallowed actions. Trying to cast one of these will result in a mishap. For example, hexcasting:get_caster will prevent Mind's Reflection",
|
||||
"text.autoconfig.hexcasting.option.server.circleActionDenyList.@Tooltip": "Resource locations of disallowed actions within circles. Trying to cast one of these from a circle will result in a mishap.",
|
||||
|
|
|
@ -159,7 +159,7 @@ public class FabricHexConfig extends PartitioningSerializer.GlobalData {
|
|||
@ConfigEntry.Gui.Tooltip
|
||||
private int opBreakHarvestLevel = DEFAULT_OP_BREAK_HARVEST_LEVEL;
|
||||
@ConfigEntry.Gui.Tooltip
|
||||
private int maxRecurseDepth = DEFAULT_MAX_RECURSE_DEPTH;
|
||||
private int maxOpCount = DEFAULT_MAX_OP_COUNT;
|
||||
@ConfigEntry.Gui.Tooltip
|
||||
private int maxSpellCircleLength = DEFAULT_MAX_SPELL_CIRCLE_LENGTH;
|
||||
@ConfigEntry.Gui.Tooltip
|
||||
|
@ -189,7 +189,7 @@ public class FabricHexConfig extends PartitioningSerializer.GlobalData {
|
|||
|
||||
@Override
|
||||
public void validatePostLoad() throws ValidationException {
|
||||
this.maxRecurseDepth = Math.max(this.maxRecurseDepth, 0);
|
||||
this.maxOpCount = Math.max(this.maxOpCount, 0);
|
||||
this.maxSpellCircleLength = Math.max(this.maxSpellCircleLength, 4);
|
||||
|
||||
this.scrollInjections = new Object2IntOpenHashMap<>();
|
||||
|
@ -206,8 +206,8 @@ public class FabricHexConfig extends PartitioningSerializer.GlobalData {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int maxRecurseDepth() {
|
||||
return maxRecurseDepth;
|
||||
public int maxOpCount() {
|
||||
return maxOpCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -123,7 +123,7 @@ public class ForgeHexConfig implements HexConfig.CommonConfigAccess {
|
|||
|
||||
public static class Server implements HexConfig.ServerConfigAccess {
|
||||
private static ForgeConfigSpec.IntValue opBreakHarvestLevel;
|
||||
private static ForgeConfigSpec.IntValue maxRecurseDepth;
|
||||
private static ForgeConfigSpec.IntValue maxOpCount;
|
||||
|
||||
private static ForgeConfigSpec.IntValue maxSpellCircleLength;
|
||||
|
||||
|
@ -141,8 +141,9 @@ public class ForgeHexConfig implements HexConfig.CommonConfigAccess {
|
|||
|
||||
public Server(ForgeConfigSpec.Builder builder) {
|
||||
builder.push("Spells");
|
||||
maxRecurseDepth = builder.comment("How many times a spell can recursively cast other spells")
|
||||
.defineInRange("maxRecurseDepth", DEFAULT_MAX_RECURSE_DEPTH, 0, Integer.MAX_VALUE);
|
||||
maxOpCount = builder.comment("The maximum number of actions that can be executed in one tick, to avoid " +
|
||||
"hanging the server.")
|
||||
.defineInRange("maxOpCount", DEFAULT_MAX_OP_COUNT, 0, Integer.MAX_VALUE);
|
||||
opBreakHarvestLevel = builder.comment(
|
||||
"The harvest level of the Break Block spell.",
|
||||
"0 = wood, 1 = stone, 2 = iron, 3 = diamond, 4 = netherite."
|
||||
|
@ -177,8 +178,8 @@ public class ForgeHexConfig implements HexConfig.CommonConfigAccess {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int maxRecurseDepth() {
|
||||
return maxRecurseDepth.get();
|
||||
public int maxOpCount() {
|
||||
return maxOpCount.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue