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
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -219,6 +221,7 @@ public static abstract class State<P extends PartTypeInterfaceCraftingVariableBa
extends PartTypeInterfaceCraftingBase.State<P, S> {

protected int ticksAfterReload = 0;
protected long lastDelayedRecipeReloadTick = Integer.MIN_VALUE;

private final SimpleInventory inventoryVariables;
private final List<InventoryVariableEvaluator<IValue>> variableEvaluators;
Expand Down Expand Up @@ -463,6 +466,19 @@ private void setSlotRecipes(int slot, List<IRecipeDefinition> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<PartTypeInterfaceCraftingEnumerated.State> 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.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Loading