diff --git a/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java b/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java
index 378069e94..9b19a75b2 100644
--- a/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java
+++ b/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java
@@ -40,7 +40,7 @@ public class GeneralConfig extends DummyConfig {
@ConfigurableProperty(category = "machine", comment = "The maximum number of recipes that will be read from a list inside an enumerated crafting interface. Set to 0 for no limit.", minimalValue = 0, isCommandable = true, configLocation = ModConfig.Type.SERVER)
public static int maxCraftingInterfaceEnumeratedRecipes = 4096;
- @ConfigurableProperty(category = "machine", comment = "The minimal update frequency in ticks to use for enumerated crafting interfaces. Reading a list of recipes is more expensive than reading a single recipe, so this defaults higher than the regular crafting interface.", minimalValue = 1, configLocation = ModConfig.Type.SERVER)
+ @ConfigurableProperty(category = "machine", comment = "The minimal number of ticks between two recipe list reloads in enumerated crafting interfaces, which happen when the list variable changes. Reading a list of recipes is more expensive than reading a single recipe, so this defaults higher than the regular crafting interface update frequency.", minimalValue = 1, configLocation = ModConfig.Type.SERVER)
public static int minCraftingInterfaceEnumeratedUpdateFreq = 20;
@ConfigurableProperty(category = "machine", comment = "The maximum number of recipes that a crafting interface remembers crafting durations for, which are used to estimate the duration of crafting jobs. Set to 0 to disable recipe-specific estimations.", minimalValue = 0, isCommandable = true, configLocation = ModConfig.Type.SERVER)
diff --git a/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingVariableBase.java b/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingVariableBase.java
index 974981647..c80d6110d 100644
--- a/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingVariableBase.java
+++ b/src/main/java/org/cyclops/integratedcrafting/core/part/PartTypeInterfaceCraftingVariableBase.java
@@ -156,7 +156,9 @@ public void update(INetwork network, IPartNetwork partNetwork, PartTarget target
// Reload recipes if needed
IntSet slots = state.getDelayedRecipeReloads();
- if (!slots.isEmpty()) {
+ long gameTime = target.getCenter().getPos().getLevel(true).getGameTime();
+ if (!slots.isEmpty() && state.canReloadDelayedRecipes(gameTime)) {
+ state.lastDelayedRecipeReloadTick = gameTime;
ICraftingNetwork craftingNetwork = network.getCapability(getNetworkCapability()).orElse(null);
if (craftingNetwork != null) {
IntSet slotsCopy = new IntOpenHashSet(slots); // Create a copy, to allow insertion into slots during this loop
@@ -219,6 +221,7 @@ public static abstract class State
{
protected int ticksAfterReload = 0;
+ protected long lastDelayedRecipeReloadTick = Integer.MIN_VALUE;
private final SimpleInventory inventoryVariables;
private final List> variableEvaluators;
@@ -463,6 +466,19 @@ private void setSlotRecipes(int slot, List recipes) {
}
}
+ /**
+ * @return The minimal number of ticks between two reloads of invalidated recipe variables.
+ */
+ protected int getMinDelayedRecipeReloadInterval() {
+ return 0;
+ }
+
+ protected boolean canReloadDelayedRecipes(long gameTime) {
+ // Never throttle during initialization, as dependency variables may still be loading.
+ return ticksAfterReload <= 1
+ || gameTime - lastDelayedRecipeReloadTick >= getMinDelayedRecipeReloadInterval();
+ }
+
protected void delayedReloadRecipe(int slot) {
this.delayedRecipeReloads.add(slot);
}
diff --git a/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsItemsCraftEnumerated.java b/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsItemsCraftEnumerated.java
index 6da336a84..7887ed2f9 100644
--- a/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsItemsCraftEnumerated.java
+++ b/src/main/java/org/cyclops/integratedcrafting/gametest/GameTestsItemsCraftEnumerated.java
@@ -15,6 +15,7 @@
import net.neoforged.neoforge.gametest.GameTestHolder;
import net.neoforged.neoforge.gametest.PrefixGameTestTemplate;
import org.apache.commons.lang3.tuple.Pair;
+import org.cyclops.integratedcrafting.GeneralConfig;
import org.cyclops.integratedcrafting.Reference;
import org.cyclops.integratedcrafting.part.PartTypeInterfaceCraftingEnumerated;
import org.cyclops.integratedcrafting.part.PartTypes;
@@ -99,6 +100,37 @@ public void testItemsCraftEnumeratedCraftingTable(GameTestHelper helper) {
});
}
+ /**
+ * The enumerated interface can process jobs as fast as the regular interface,
+ * as only reloads of its list are throttled.
+ */
+ @GameTest(template = TEMPLATE_EMPTY, timeoutTicks = TIMEOUT)
+ public void testItemsCraftEnumeratedMinUpdateInterval(GameTestHelper helper) {
+ GameTestHelpersIntegratedCrafting.INetworkPositions positions =
+ createBasicNetwork(helper, POS, PartTypes.INTERFACE_CRAFTING_ENUMERATED, Blocks.CRAFTING_TABLE);
+ PartTypeInterfaceCraftingEnumerated.State state = positions.interfaceStates().get(0);
+
+ helper.assertValueEqual(PartTypes.INTERFACE_CRAFTING_ENUMERATED.getMinimumUpdateInterval(state),
+ GeneralConfig.minCraftingInterfaceUpdateFreq, "Minimum update interval is incorrect");
+ GameTestHelpersIntegratedCrafting.setCraftingInterfaceUpdateInterval(positions.interfaces().get(0),
+ GeneralConfig.minCraftingInterfaceUpdateFreq);
+
+ ChestBlockEntity chestIn = helper.getBlockEntity(POS.east());
+ chestIn.setItem(0, new ItemStack(Items.OAK_PLANKS, 64));
+
+ state.getInventoryVariables().setItem(0, createVariableForRecipeList(helper.getLevel(), List.of(
+ Pair.of(RecipeType.CRAFTING, ResourceLocation.fromNamespaceAndPath("minecraft", "chest"))
+ )));
+
+ enableRecipeInWriter(helper, positions.writer(), new ItemStack(Items.CHEST));
+
+ helper.succeedWhen(() -> {
+ helper.assertValueEqual(state.getUpdateInterval(), GeneralConfig.minCraftingInterfaceUpdateFreq,
+ "Update interval is incorrect");
+ helper.assertValueEqual(chestIn.getItem(1).getItem(), Items.CHEST, "Slot 1 item is incorrect");
+ });
+ }
+
/**
* Replacing the list variable re-indexes the interface with the new recipes.
*/
diff --git a/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java b/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java
index 1bcaf23ad..cfcd9ba8f 100644
--- a/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java
+++ b/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java
@@ -62,9 +62,10 @@ protected PartTypeInterfaceCraftingEnumerated getPartTypeInstance() {
}
@Override
- protected int getDefaultUpdateInterval() {
+ protected int getMinDelayedRecipeReloadInterval() {
// Reading a whole list of recipes is more expensive than reading a single recipe,
// and reader-backed list variables are invalidated on every reader tick.
+ // Only reloads are throttled, so static lists can process jobs at the regular rate.
return GeneralConfig.minCraftingInterfaceEnumeratedUpdateFreq;
}