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
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ public interface ICraftingInterface {
* This may fall back to the average duration over all recipes of this interface,
* as recipe-specific durations are only remembered for a limited number of recipes,
* and are forgotten once they become outdated.
* This is never shorter than the interval at which this interface can start operations,
* so that recipes that produce their outputs instantly are not estimated as taking no time.
*/
public long getEstimatedRecipeDuration(IRecipeDefinition recipe);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ public <T, M> Iterator<CraftingJob> getCraftingJobs(int channel, IngredientCompo
* @param recipe A recipe.
* @return The estimated duration in ticks of a single crafting operation of the given recipe,
* based on the operations that the crafting interfaces performed before, or -1 if unknown.
* As with {@link ICraftingInterface#getEstimatedRecipeDuration(IRecipeDefinition)},
* this accounts for the interval at which those interfaces start operations.
*/
public long getEstimatedRecipeDuration(int channel, IRecipeDefinition recipe);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,14 +350,28 @@ public long getCraftingJobEntryStartTick(int craftingJobId) {
}

/**
* Only the time between starting a crafting operation and its outputs coming back in is measured.
* Recipes that produce their outputs within the tick they are started in, such as regular crafting
* recipes, therefore measure as taking no time at all, which would estimate whole crafting jobs away.
*
* In blocking mode, a single operation is started per update, so an operation occupies this handler
* for a full update interval, however quickly the recipe itself is done.
* In non-blocking mode, as many operations are started as the target accepts, so there is no such
* lower bound, and the given interval is ignored.
*
* @param recipe A recipe.
* @param updateInterval The number of ticks between two updates of this handler.
* @return The estimated duration in ticks of a single crafting operation of the given recipe,
* based on the operations that were performed by this handler before, or -1 if unknown.
* This falls back to the average duration over all recipes
* when the given recipe itself was not crafted recently.
*/
public long getEstimatedRecipeDuration(IRecipeDefinition recipe) {
return getRecipeDurationStatistics().getEstimatedDuration(recipe, getCurrentTick());
public long getEstimatedRecipeDuration(IRecipeDefinition recipe, long updateInterval) {
long recipeDuration = getRecipeDurationStatistics().getEstimatedDuration(recipe, getCurrentTick());
if (recipeDuration < 0) {
return -1;
}
return isBlockingJobsMode() ? Math.max(recipeDuration, updateInterval) : recipeDuration;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ public long getCraftingJobEntryStartTick(int craftingJobId) {

@Override
public long getEstimatedRecipeDuration(IRecipeDefinition recipe) {
return craftingJobHandler.getEstimatedRecipeDuration(recipe);
return craftingJobHandler.getEstimatedRecipeDuration(recipe, getUpdateInterval());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,12 @@ public void testItemsCraftChestOneRecipeDuration(GameTestHelper helper) {
// Check if items have been crafted
helper.assertValueEqual(chestIn.getItem(1).getItem(), Items.CHEST, "Slot 1 item is incorrect");

// Check if the duration of the crafted recipe was measured
// Check if the duration of the crafted recipe was measured.
// A chest is crafted within the tick it is started in, so its measured duration is zero,
// and the interval at which the interface starts operations is what is left of it.
PartTypeInterfaceCrafting.State interfaceState = positions.interfaceStates().get(0);
for (IRecipeDefinition recipe : interfaceState.getRecipes()) {
helper.assertTrue(interfaceState.getEstimatedRecipeDuration(recipe) >= 0,
helper.assertTrue(interfaceState.getEstimatedRecipeDuration(recipe) >= interfaceState.getUpdateInterval(),
"No crafting duration was measured for the crafted recipe");
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,28 +63,52 @@ protected CraftingJob newCraftingJob(int id, int amount) {

@Test
public void testRecipeDurationUnknown() {
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(-1L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(-1L));
}

@Test
public void testRecipeDurationSingle() {
handler.reportRecipeDuration(recipeA, 100);
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(100L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(100L));
}

@Test
public void testRecipeDurationSmoothed() {
handler.reportRecipeDuration(recipeA, 100);
handler.reportRecipeDuration(recipeA, 200);
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(125L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(125L));
handler.reportRecipeDuration(recipeA, 200);
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(144L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(144L));
}

@Test
public void testRecipeDurationIsAtLeastOneUpdate() {
handler.reportRecipeDuration(recipeA, 0);
assertThat(handler.getEstimatedRecipeDuration(recipeA, 5), equalTo(5L));
}

@Test
public void testRecipeDurationLongerThanOneUpdateIsKept() {
handler.reportRecipeDuration(recipeA, 100);
assertThat(handler.getEstimatedRecipeDuration(recipeA, 5), equalTo(100L));
}

@Test
public void testUnknownRecipeDurationStaysUnknownWithUpdateInterval() {
assertThat(handler.getEstimatedRecipeDuration(recipeA, 5), equalTo(-1L));
}

@Test
public void testRecipeDurationIsNotBoundedInNonBlockingMode() {
TickingCraftingJobHandler nonBlockingHandler = new TickingCraftingJobHandler(false);
nonBlockingHandler.reportRecipeDuration(recipeA, 0);
assertThat(nonBlockingHandler.getEstimatedRecipeDuration(recipeA, 5), equalTo(0L));
}

@Test
public void testRecipeDurationFallsBackToAverage() {
handler.reportRecipeDuration(recipeA, 100);
assertThat(handler.getEstimatedRecipeDuration(recipeB), equalTo(100L));
assertThat(handler.getEstimatedRecipeDuration(recipeB, 0), equalTo(100L));
}

@Test
Expand Down Expand Up @@ -130,7 +154,7 @@ public void testCraftingOperationIsMeasured() {

assertThat(craftingJob.getAmount(), equalTo(1));
assertThat(craftingJob.getAmountTotal(), equalTo(2));
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(60L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(60L));
assertThat(handler.getCraftingJobEntryStartTick(1), equalTo(-1L));
}

Expand All @@ -147,12 +171,12 @@ public void testParallelCraftingOperationsAreMeasured() {

handler.setCurrentTick(200);
handler.onCraftingJobEntryFinished(craftingNetwork, 1);
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(100L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(100L));
assertThat(handler.getCraftingJobEntryStartTick(1), equalTo(120L));

handler.setCurrentTick(220);
handler.onCraftingJobEntryFinished(craftingNetwork, 1);
assertThat(handler.getEstimatedRecipeDuration(recipeA), equalTo(100L));
assertThat(handler.getEstimatedRecipeDuration(recipeA, 0), equalTo(100L));
assertThat(handler.getCraftingJobEntryStartTick(1), equalTo(-1L));
}

Expand Down Expand Up @@ -210,7 +234,7 @@ public void testRecipeDurationsSurviveSerialization() {
TickingCraftingJobHandler deserialized = new TickingCraftingJobHandler();
deserialized.readFromNBT(null, tag);

assertThat(deserialized.getEstimatedRecipeDuration(recipeA), equalTo(100L));
assertThat(deserialized.getEstimatedRecipeDuration(recipeA, 0), equalTo(100L));
assertThat(deserialized.getRecipeDurationStatistics().getEntryCount(), equalTo(0));
}

Expand All @@ -219,7 +243,11 @@ protected static class TickingCraftingJobHandler extends CraftingJobHandler {
private long currentTick;

public TickingCraftingJobHandler() {
super(1, true, Collections.emptyList(), new ICraftingResultsSink() {
this(true);
}

public TickingCraftingJobHandler(boolean blockingJobsMode) {
super(1, blockingJobsMode, Collections.emptyList(), new ICraftingResultsSink() {
@Override
public <T, M> void addResult(IngredientComponent<T, M> ingredientComponent, T instance) {

Expand Down
Loading