diff --git a/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java b/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java
index 378069e94..4ad5373e0 100644
--- a/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java
+++ b/src/main/java/org/cyclops/integratedcrafting/GeneralConfig.java
@@ -22,6 +22,9 @@ public class GeneralConfig extends DummyConfig {
@ConfigurableProperty(category = "machine", comment = "The minimal update frequency in ticks to use for crafting interfaces.", minimalValue = 1, configLocation = ModConfig.Type.SERVER)
public static int minCraftingInterfaceUpdateFreq = 5;
+ @ConfigurableProperty(category = "machine", comment = "The minimal update frequency in ticks to use for attuned crafting interfaces.", minimalValue = 1, configLocation = ModConfig.Type.SERVER)
+ public static int minCraftingInterfaceAttunedUpdateFreq = 5;
+
@ConfigurableProperty(category = "machine", comment = "If the crafting interface should validate recipes on insertion.", isCommandable = true, configLocation = ModConfig.Type.SERVER)
public static boolean validateRecipesCraftingInterface = true;
@@ -40,8 +43,11 @@ 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)
- public static int minCraftingInterfaceEnumeratedUpdateFreq = 20;
+ @ConfigurableProperty(category = "machine", comment = "The minimal update frequency in ticks to use for enumerated crafting interfaces.", minimalValue = 1, configLocation = ModConfig.Type.SERVER)
+ public static int minCraftingInterfaceEnumeratedUpdateFreq = 5;
+
+ @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 update frequency.", minimalValue = 1, configLocation = ModConfig.Type.SERVER)
+ public static int minCraftingInterfaceEnumeratedRecipeReloadFreq = 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)
public static int craftingInterfaceRecipeDurationEntries = 32;
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..6b5e67ce7 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 uses its own minimum update interval,
+ * 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.minCraftingInterfaceEnumeratedUpdateFreq, "Minimum update interval is incorrect");
+ GameTestHelpersIntegratedCrafting.setCraftingInterfaceUpdateInterval(positions.interfaces().get(0),
+ GeneralConfig.minCraftingInterfaceEnumeratedUpdateFreq);
+
+ 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.minCraftingInterfaceEnumeratedUpdateFreq,
+ "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/PartTypeInterfaceCraftingAttuned.java b/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingAttuned.java
index 1e8087de1..f4eddb698 100644
--- a/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingAttuned.java
+++ b/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingAttuned.java
@@ -224,6 +224,11 @@ public static class State extends PartTypeInterfaceCraftingBase.State disabledRecipes = Sets.newLinkedHashSet();
private int recipesVersion = 0;
+ @Override
+ protected int getDefaultUpdateInterval() {
+ return GeneralConfig.minCraftingInterfaceAttunedUpdateFreq;
+ }
+
protected Optional getTargetRecipeHandler() {
PartPos target = getTarget().getTarget();
return IModHelpersNeoForge.get().getCapabilityHelpers().getCapability(target.getPos(), target.getSide(), Capabilities.RecipeHandler.BLOCK);
diff --git a/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java b/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java
index 1bcaf23ad..b060ea1ad 100644
--- a/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java
+++ b/src/main/java/org/cyclops/integratedcrafting/part/PartTypeInterfaceCraftingEnumerated.java
@@ -63,9 +63,15 @@ protected PartTypeInterfaceCraftingEnumerated getPartTypeInstance() {
@Override
protected int getDefaultUpdateInterval() {
+ return GeneralConfig.minCraftingInterfaceEnumeratedUpdateFreq;
+ }
+
+ @Override
+ 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.
- return GeneralConfig.minCraftingInterfaceEnumeratedUpdateFreq;
+ // Only reloads are throttled, so static lists can process jobs at the full update rate.
+ return GeneralConfig.minCraftingInterfaceEnumeratedRecipeReloadFreq;
}
@Override