Skip to content

Commit

Permalink
Merge pull request #784 from refinedmods/feat/GH-612/processing-balan…
Browse files Browse the repository at this point in the history
…cing

Processing pattern balancing
  • Loading branch information
raoulvdberge authored Jan 27, 2025
2 parents 1ae1b0f + 13bbc61 commit 1b11c24
Show file tree
Hide file tree
Showing 76 changed files with 1,510 additions and 981 deletions.
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
package com.refinedmods.refinedstorage.api.autocrafting;

import com.refinedmods.refinedstorage.api.core.CoreValidations;
import com.refinedmods.refinedstorage.api.resource.ResourceAmount;

import java.util.List;
import java.util.UUID;

import org.apiguardian.api.API;

/**
* Represents a unique pattern, with an ID.
*
* @param id the id
* @param layout the (non-unique) layout
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.6")
public record Pattern(UUID id, List<Ingredient> ingredients, List<ResourceAmount> outputs, PatternType type) {
public Pattern(final UUID id,
final List<Ingredient> ingredients,
final List<ResourceAmount> outputs,
final PatternType type) {
public record Pattern(UUID id, PatternLayout layout) {
public Pattern {
CoreValidations.validateNotNull(id, "ID cannot be null");
CoreValidations.validateNotEmpty(ingredients, "Ingredients cannot be empty");
CoreValidations.validateNotEmpty(outputs, "Outputs cannot be empty");
CoreValidations.validateNotNull(type, "Type cannot be null");
this.id = id;
this.ingredients = List.copyOf(ingredients);
this.outputs = List.copyOf(outputs);
this.type = type;
CoreValidations.validateNotNull(layout, "Layout cannot be null");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
public class PatternBuilder {
private final PatternType type;
private final UUID id;
private final List<Ingredient> ingredients = new ArrayList<>();
private final List<ResourceAmount> outputs = new ArrayList<>();

private PatternBuilder(final UUID id, final PatternType type) {
this.id = id;
private PatternBuilder(final PatternType type) {
this.type = type;
}

Expand All @@ -26,11 +24,7 @@ public static PatternBuilder pattern() {
}

public static PatternBuilder pattern(final PatternType type) {
return pattern(UUID.randomUUID(), type);
}

public static PatternBuilder pattern(final UUID id, final PatternType type) {
return new PatternBuilder(id, type);
return new PatternBuilder(type);
}

public IngredientBuilder ingredient(final long amount) {
Expand All @@ -47,8 +41,12 @@ public PatternBuilder output(final ResourceKey output, final long amount) {
return this;
}

public PatternLayout buildLayout() {
return new PatternLayout(ingredients, outputs, type);
}

public Pattern build() {
return new Pattern(id, ingredients, outputs, type);
return new Pattern(UUID.randomUUID(), buildLayout());
}

public class IngredientBuilder {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.refinedmods.refinedstorage.api.autocrafting;

import com.refinedmods.refinedstorage.api.core.CoreValidations;
import com.refinedmods.refinedstorage.api.resource.ResourceAmount;

import java.util.List;

import org.apiguardian.api.API;

/**
* Represents a pattern layout. Multiple {@link Pattern}s can share the same layout.
*
* @param ingredients the ingredients
* @param outputs the outputs
* @param type the type
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
public record PatternLayout(List<Ingredient> ingredients, List<ResourceAmount> outputs, PatternType type) {
public PatternLayout(final List<Ingredient> ingredients,
final List<ResourceAmount> outputs,
final PatternType type) {
CoreValidations.validateNotEmpty(ingredients, "Ingredients cannot be empty");
CoreValidations.validateNotEmpty(outputs, "Outputs cannot be empty");
CoreValidations.validateNotNull(type, "Type cannot be null");
this.ingredients = List.copyOf(ingredients);
this.outputs = List.copyOf(outputs);
this.type = type;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ public class PatternRepositoryImpl implements PatternRepository {
@Override
public void add(final Pattern pattern, final int priority) {
patterns.add(pattern);
pattern.outputs().forEach(output -> outputs.add(output.resource()));
for (final ResourceAmount output : pattern.outputs()) {
pattern.layout().outputs().forEach(output -> outputs.add(output.resource()));
for (final ResourceAmount output : pattern.layout().outputs()) {
patternsByOutput.computeIfAbsent(output.resource(), k -> new PriorityQueue<>(
Comparator.comparingInt(PatternHolder::priority).reversed()
)).add(new PatternHolder(pattern, priority));
Expand All @@ -32,7 +32,7 @@ public void add(final Pattern pattern, final int priority) {

@Override
public void update(final Pattern pattern, final int priority) {
for (final ResourceAmount output : pattern.outputs()) {
for (final ResourceAmount output : pattern.layout().outputs()) {
final PriorityQueue<PatternHolder> holders = patternsByOutput.get(output.resource());
if (holders == null) {
continue;
Expand All @@ -45,7 +45,7 @@ public void update(final Pattern pattern, final int priority) {
@Override
public void remove(final Pattern pattern) {
patterns.remove(pattern);
for (final ResourceAmount output : pattern.outputs()) {
for (final ResourceAmount output : pattern.layout().outputs()) {
final PriorityQueue<PatternHolder> holders = patternsByOutput.get(output.resource());
if (holders == null) {
continue;
Expand All @@ -55,7 +55,7 @@ public void remove(final Pattern pattern) {
patternsByOutput.remove(output.resource());
}
final boolean noOtherPatternHasThisOutput = patterns.stream()
.noneMatch(otherPattern -> otherPattern.outputs().stream()
.noneMatch(otherPattern -> otherPattern.layout().outputs().stream()
.anyMatch(o -> o.resource().equals(output.resource())));
if (noOtherPatternHasThisOutput) {
outputs.remove(output.resource());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public long getTotal() {
}

static Amount of(final Pattern pattern, final ResourceKey resource, final long requestedAmount) {
final long amountPerIteration = pattern.outputs()
final long amountPerIteration = pattern.layout().outputs()
.stream()
.filter(output -> output.resource().equals(resource))
.mapToLong(ResourceAmount::amount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void extractFromStorage(final ResourceKey resource, final long amount) {
}

void addOutputsToInternalStorage(final Pattern pattern, final Amount amount) {
pattern.outputs().forEach(output -> addOutputToInternalStorage(amount, output));
pattern.layout().outputs().forEach(output -> addOutputToInternalStorage(amount, output));
}

private void addOutputToInternalStorage(final Amount amount, final ResourceAmount output) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -65,8 +66,9 @@ CalculationResult calculate() {
throw new PatternCycleDetectedException(pattern);
}
CalculationResult result = CalculationResult.SUCCESS;
for (int ingredientIndex = 0; ingredientIndex < pattern.ingredients().size(); ++ingredientIndex) {
final Ingredient ingredient = pattern.ingredients().get(ingredientIndex);
final List<Ingredient> ingredients = pattern.layout().ingredients();
for (int ingredientIndex = 0; ingredientIndex < ingredients.size(); ++ingredientIndex) {
final Ingredient ingredient = ingredients.get(ingredientIndex);
final IngredientState ingredientState = new IngredientState(ingredient, craftingState);
final CalculationResult ingredientResult = calculateIngredient(ingredientIndex, ingredientState);
if (ingredientResult == CalculationResult.MISSING_RESOURCES) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private MutablePreviewItem get(final ResourceKey resource) {
}

public PreviewBuilder withPatternWithCycle(final Pattern pattern) {
this.outputsOfPatternWithCycle = pattern.outputs();
this.outputsOfPatternWithCycle = pattern.layout().outputs();
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static Preview calculatePreview(final CraftingCalculator calculator,
try {
calculator.calculate(resource, amount, listener);
} catch (final PatternCycleDetectedException e) {
return new Preview(PreviewType.CYCLE_DETECTED, Collections.emptyList(), e.getPattern().outputs());
return new Preview(PreviewType.CYCLE_DETECTED, Collections.emptyList(), e.getPattern().layout().outputs());
} catch (final NumberOverflowDuringCalculationException e) {
return new Preview(PreviewType.OVERFLOW, Collections.emptyList(), Collections.emptyList());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.refinedmods.refinedstorage.api.autocrafting.status;

import com.refinedmods.refinedstorage.api.autocrafting.task.ExternalPatternInputSinkKey;
import com.refinedmods.refinedstorage.api.autocrafting.task.ExternalPatternSinkKey;
import com.refinedmods.refinedstorage.api.autocrafting.task.TaskId;
import com.refinedmods.refinedstorage.api.resource.ResourceKey;

Expand All @@ -17,7 +17,7 @@ public record TaskInfo(TaskId id, ResourceKey resource, long amount, long startT
public record Item(
ResourceKey resource,
ItemType type,
@Nullable ExternalPatternInputSinkKey sinkKey,
@Nullable ExternalPatternSinkKey sinkKey,
long stored,
long processing,
long scheduled,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.refinedmods.refinedstorage.api.autocrafting.status;

import com.refinedmods.refinedstorage.api.autocrafting.task.ExternalPatternInputSinkKey;
import com.refinedmods.refinedstorage.api.autocrafting.task.ExternalPatternSinkKey;
import com.refinedmods.refinedstorage.api.autocrafting.task.TaskId;
import com.refinedmods.refinedstorage.api.core.CoreValidations;
import com.refinedmods.refinedstorage.api.resource.ResourceKey;
Expand All @@ -25,7 +25,7 @@ public TaskStatusBuilder stored(final ResourceKey resource, final long stored) {

public TaskStatusBuilder processing(final ResourceKey resource,
final long processing,
@Nullable final ExternalPatternInputSinkKey sinkKey) {
@Nullable final ExternalPatternSinkKey sinkKey) {
CoreValidations.validateLargerThanZero(processing, "Processing");
get(resource).processing += processing;
get(resource).sinkKey = sinkKey;
Expand Down Expand Up @@ -80,7 +80,7 @@ private static class MutableItem {
private long stored;
private long processing;
@Nullable
private ExternalPatternInputSinkKey sinkKey;
private ExternalPatternSinkKey sinkKey;
private long scheduled;
private long crafting;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected AbstractTaskPattern(final Pattern pattern, final TaskPlan.PatternPlan

abstract PatternStepResult step(MutableResourceList internalStorage,
RootStorage rootStorage,
ExternalPatternInputSink externalPatternInputSink);
ExternalPatternSinkProvider sinkProvider);

abstract RootStorageListener.InterceptResult interceptInsertion(ResourceKey resource, long amount);

Expand Down Expand Up @@ -79,7 +79,7 @@ private boolean calculateIterationInputs(final Map.Entry<Integer, Map<ResourceKe
final int ingredientIndex,
final MutableResourceList iterationInputs,
final Action action) {
long needed = pattern.ingredients().get(ingredientIndex).amount();
long needed = pattern.layout().ingredients().get(ingredientIndex).amount();
for (final Map.Entry<ResourceKey, Long> possibility : ingredient.getValue().entrySet()) {
final long available = Math.min(needed, possibility.getValue());
if (available == 0) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;

import com.refinedmods.refinedstorage.api.autocrafting.Pattern;
import com.refinedmods.refinedstorage.api.core.Action;
import com.refinedmods.refinedstorage.api.resource.ResourceAmount;

import java.util.Collection;
import javax.annotation.Nullable;

import org.apiguardian.api.API;

/**
* Gives the ability to a {@link Task} to dump inputs of an external {@link Pattern} into the external target.
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
public interface ExternalPatternSink {
/**
* Accepts the given resources into the external target.
* All resources MUST be able to be inserted for this method to return {@link Result#ACCEPTED},
* otherwise, it must return {@link Result#REJECTED}.
* If the sink is locked, it must return {@link Result#LOCKED}.
* If the resources are not applicable for this sink, it must return {@link Result#SKIPPED}.
*
* @param resources the resources
* @param action the action
* @return the result
*/
Result accept(Collection<ResourceAmount> resources, Action action);

/**
* @return the key for this sink
*/
@Nullable
default ExternalPatternSinkKey getKey() {
return null;
}

enum Result {
ACCEPTED,
REJECTED,
SKIPPED,
LOCKED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import org.apiguardian.api.API;

/**
* A unique identifier for a {@link ExternalPatternSink}.
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
public interface ExternalPatternInputSinkKey {
public interface ExternalPatternSinkKey {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.refinedmods.refinedstorage.api.autocrafting.task;

import com.refinedmods.refinedstorage.api.autocrafting.PatternLayout;

import java.util.List;

import org.apiguardian.api.API;

/**
* Provides access to the {@link ExternalPatternSink} for a {@link PatternLayout}.
* Used in autocrafting tasks.
*/
@API(status = API.Status.STABLE, since = "2.0.0-milestone.4.12")
@FunctionalInterface
public interface ExternalPatternSinkProvider {
/**
* @param patternLayout the pattern layout
* @return a list of sinks for a pattern
*/
List<ExternalPatternSink> getSinksByPatternLayout(PatternLayout patternLayout);
}
Loading

0 comments on commit 1b11c24

Please sign in to comment.