From e7b6412c03af15b9e0a40b53a73297e4c0c6467a Mon Sep 17 00:00:00 2001 From: raoulvdberge Date: Mon, 30 Dec 2024 14:32:31 +0100 Subject: [PATCH] refactor: remove pattern interface It's not needed. Make it a record and validate the state properly. Add more validations for Ingredient. --- .../api/autocrafting/Ingredient.java | 14 +- .../api/autocrafting/Pattern.java | 18 +- .../api/autocrafting/PatternBuilder.java | 2 +- .../autocrafting/PatternRepositoryImpl.java | 27 +- .../api/autocrafting/calculation/Amount.java | 2 +- .../calculation/CraftingState.java | 4 +- .../calculation/CraftingTree.java | 5 +- .../autocrafting/preview/PreviewBuilder.java | 2 +- .../PreviewCraftingCalculatorListener.java | 2 +- .../api/autocrafting/IngredientTest.java | 79 +++++ .../api/autocrafting/PatternImpl.java | 49 --- .../PatternRepositoryImplTest.java | 105 +++---- .../api/autocrafting/PatternTest.java | 123 ++++++++ .../preview/PreviewBuilderTest.java | 6 +- .../api/autocrafting/preview/PreviewTest.java | 32 -- .../api/autocrafting/PatternProviderItem.java | 2 + .../common/autocrafting/CraftingPattern.java | 76 ----- ...CraftingPatternClientTooltipComponent.java | 25 +- .../common/autocrafting/PatternItem.java | 292 +++++++----------- .../common/autocrafting/PatternRendering.java | 18 +- .../common/autocrafting/PatternResolver.java | 220 +++++++++++++ .../autocrafting/PatternTooltipCache.java | 6 +- .../autocrafting/ProcessingPattern.java | 68 ---- ...ocessingPatternClientTooltipComponent.java | 36 +-- .../autocrafting/ProcessingPatternState.java | 2 +- .../autocrafting/SmithingTablePattern.java | 97 ------ ...ingTablePatternClientTooltipComponent.java | 14 +- .../autocrafting/StonecutterPattern.java | 77 ----- ...necutterPatternClientTooltipComponent.java | 13 +- .../AutocrafterManagerContainerMenu.java | 32 +- .../api/core/CoreValidations.java | 6 + .../api/core/CoreValidationsTest.java | 13 + .../relay/RelayOutputPatternProvider.java | 3 +- .../AutocraftingNetworkComponentImplTest.java | 14 +- .../impl/autocrafting/PatternImpl.java | 46 --- .../PatternProviderNetworkNodeTest.java | 41 ++- .../impl/node/relay/RelayNetworkNodeTest.java | 20 +- 37 files changed, 755 insertions(+), 836 deletions(-) rename refinedstorage-autocrafting-api/src/{test => main}/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java (95%) create mode 100644 refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/IngredientTest.java delete mode 100644 refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternImpl.java create mode 100644 refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternTest.java delete mode 100644 refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPattern.java create mode 100644 refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternResolver.java delete mode 100644 refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPattern.java delete mode 100644 refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePattern.java delete mode 100644 refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPattern.java delete mode 100644 refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/PatternImpl.java diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Ingredient.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Ingredient.java index 88c8c68fb..1f99175eb 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Ingredient.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Ingredient.java @@ -1,8 +1,8 @@ package com.refinedmods.refinedstorage.api.autocrafting; +import com.refinedmods.refinedstorage.api.core.CoreValidations; import com.refinedmods.refinedstorage.api.resource.ResourceKey; -import java.util.Collections; import java.util.List; public class Ingredient { @@ -10,12 +10,10 @@ public class Ingredient { private final List inputs; public Ingredient(final long amount, final List inputs) { + CoreValidations.validateLargerThanZero(amount, "Amount must be larger than zero"); + CoreValidations.validateNotEmpty(inputs, "Inputs cannot be empty"); this.amount = amount; - this.inputs = Collections.unmodifiableList(inputs); - } - - public boolean isEmpty() { - return inputs.isEmpty(); + this.inputs = List.copyOf(inputs); } public int size() { @@ -30,6 +28,10 @@ public ResourceKey get(final int index) { return inputs.get(index); } + public List getAll() { + return inputs; + } + @Override public String toString() { return "Ingredient{" diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Pattern.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Pattern.java index ec74da532..866c77f35 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Pattern.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/Pattern.java @@ -1,20 +1,18 @@ package com.refinedmods.refinedstorage.api.autocrafting; +import com.refinedmods.refinedstorage.api.core.CoreValidations; import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; import java.util.List; -import java.util.Set; import org.apiguardian.api.API; @API(status = API.Status.STABLE, since = "2.0.0-milestone.4.6") -public interface Pattern { - Set getInputResources(); - - Set getOutputResources(); - - List getIngredients(); - - List getOutputs(); +public record Pattern(List ingredients, List outputs) { + public Pattern(final List ingredients, final List outputs) { + CoreValidations.validateNotEmpty(ingredients, "Ingredients cannot be empty"); + CoreValidations.validateNotEmpty(outputs, "Outputs cannot be empty"); + this.ingredients = List.copyOf(ingredients); + this.outputs = List.copyOf(outputs); + } } diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java similarity index 95% rename from refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java rename to refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java index bc52a41e1..059561ea0 100644 --- a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternBuilder.java @@ -37,7 +37,7 @@ public PatternBuilder output(final ResourceKey output, final long amount) { } public Pattern build() { - return new PatternImpl(ingredients, outputs.toArray(new ResourceAmount[0])); + return new Pattern(ingredients, outputs); } public class IngredientBuilder { diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImpl.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImpl.java index dad2a4597..10de2a4b1 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImpl.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImpl.java @@ -1,5 +1,6 @@ package com.refinedmods.refinedstorage.api.autocrafting; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import java.util.Collections; @@ -13,16 +14,17 @@ public class PatternRepositoryImpl implements PatternRepository { private final Set patterns = new HashSet<>(); - private final Map> patternsByOutput = new HashMap<>(); private final Set patternsView = Collections.unmodifiableSet(patterns); + private final Map> patternsByOutput = new HashMap<>(); private final Set outputs = new HashSet<>(); + private final Set outputsView = Collections.unmodifiableSet(outputs); @Override public void add(final Pattern pattern, final int priority) { patterns.add(pattern); - outputs.addAll(pattern.getOutputResources()); - for (final ResourceKey output : pattern.getOutputResources()) { - patternsByOutput.computeIfAbsent(output, k -> new PriorityQueue<>( + pattern.outputs().forEach(output -> outputs.add(output.resource())); + for (final ResourceAmount output : pattern.outputs()) { + patternsByOutput.computeIfAbsent(output.resource(), k -> new PriorityQueue<>( Comparator.comparingInt(PatternHolder::priority).reversed() )).add(new PatternHolder(pattern, priority)); } @@ -30,8 +32,8 @@ public void add(final Pattern pattern, final int priority) { @Override public void update(final Pattern pattern, final int priority) { - for (final ResourceKey output : pattern.getOutputResources()) { - final PriorityQueue holders = patternsByOutput.get(output); + for (final ResourceAmount output : pattern.outputs()) { + final PriorityQueue holders = patternsByOutput.get(output.resource()); if (holders == null) { continue; } @@ -43,19 +45,20 @@ public void update(final Pattern pattern, final int priority) { @Override public void remove(final Pattern pattern) { patterns.remove(pattern); - for (final ResourceKey output : pattern.getOutputResources()) { - final PriorityQueue holders = patternsByOutput.get(output); + for (final ResourceAmount output : pattern.outputs()) { + final PriorityQueue holders = patternsByOutput.get(output.resource()); if (holders == null) { continue; } holders.removeIf(holder -> holder.pattern.equals(pattern)); if (holders.isEmpty()) { - patternsByOutput.remove(output); + patternsByOutput.remove(output.resource()); } final boolean noOtherPatternHasThisOutput = patterns.stream() - .noneMatch(otherPattern -> otherPattern.getOutputResources().contains(output)); + .noneMatch(otherPattern -> otherPattern.outputs().stream() + .anyMatch(o -> o.resource().equals(output.resource()))); if (noOtherPatternHasThisOutput) { - outputs.remove(output); + outputs.remove(output.resource()); } } } @@ -71,7 +74,7 @@ public List getByOutput(final ResourceKey output) { @Override public Set getOutputs() { - return outputs; + return outputsView; } @Override diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/Amount.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/Amount.java index 1522a35b6..7adfb528b 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/Amount.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/Amount.java @@ -10,7 +10,7 @@ public long getTotal() { } static Amount of(final Pattern pattern, final ResourceKey resource, final long requestedAmount) { - final long amountPerIteration = pattern.getOutputs() + final long amountPerIteration = pattern.outputs() .stream() .filter(output -> output.resource().equals(resource)) .mapToLong(ResourceAmount::amount) diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingState.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingState.java index cc4acc9c5..0e975c682 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingState.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingState.java @@ -28,9 +28,7 @@ void extractFromStorage(final ResourceKey resource, final long amount) { } void addOutputsToInternalStorage(final Pattern pattern, final Amount amount) { - pattern.getOutputs().forEach( - output -> addOutputToInternalStorage(amount, output) - ); + pattern.outputs().forEach(output -> addOutputToInternalStorage(amount, output)); } private void addOutputToInternalStorage(final Amount amount, final ResourceAmount output) { diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingTree.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingTree.java index 305bbe1a1..f2b919856 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingTree.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/calculation/CraftingTree.java @@ -58,10 +58,7 @@ CalculationResult calculate() { throw new PatternCycleDetectedException(pattern); } CalculationResult result = CalculationResult.SUCCESS; - for (final Ingredient ingredient : pattern.getIngredients()) { - if (ingredient.isEmpty()) { - continue; - } + for (final Ingredient ingredient : pattern.ingredients()) { final IngredientState ingredientState = new IngredientState(ingredient, craftingState); final CalculationResult ingredientResult = calculateIngredient(ingredientState); if (ingredientResult == CalculationResult.MISSING_RESOURCES) { diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilder.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilder.java index ce894747f..5acce122d 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilder.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilder.java @@ -29,7 +29,7 @@ private MutablePreviewItem get(final ResourceKey resource) { } public PreviewBuilder withPatternWithCycle(final Pattern pattern) { - this.outputsOfPatternWithCycle = pattern.getOutputs(); + this.outputsOfPatternWithCycle = pattern.outputs(); return this; } diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewCraftingCalculatorListener.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewCraftingCalculatorListener.java index 31b1a6791..9143c7cf4 100644 --- a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewCraftingCalculatorListener.java +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewCraftingCalculatorListener.java @@ -33,7 +33,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().getOutputs()); + return new Preview(PreviewType.CYCLE_DETECTED, Collections.emptyList(), e.getPattern().outputs()); } catch (final NumberOverflowDuringCalculationException e) { return new Preview(PreviewType.OVERFLOW, Collections.emptyList(), Collections.emptyList()); } diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/IngredientTest.java b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/IngredientTest.java new file mode 100644 index 000000000..aadbcb443 --- /dev/null +++ b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/IngredientTest.java @@ -0,0 +1,79 @@ +package com.refinedmods.refinedstorage.api.autocrafting; + +import com.refinedmods.refinedstorage.api.resource.ResourceKey; + +import java.util.ArrayList; +import java.util.List; + +import org.assertj.core.api.ThrowableAssert; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.A; +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.B; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class IngredientTest { + @Test + void testIngredient() { + // Act + final Ingredient sut = new Ingredient(1, List.of(A, B)); + + // Assert + assertThat(sut.size()).isEqualTo(2); + assertThat(sut.getAmount()).isEqualTo(1); + assertThat(sut.get(0)).isEqualTo(A); + assertThat(sut.get(1)).isEqualTo(B); + assertThat(sut.getAll()).containsExactly(A, B); + } + + @Test + void shouldCopyIngredients() { + // Arrange + final List outputs = new ArrayList<>(); + outputs.add(A); + + // Act + final Ingredient sut = new Ingredient(1, outputs); + outputs.add(B); + + // Assert + assertThat(sut.size()).isEqualTo(1); + assertThat(sut.get(0)).isEqualTo(A); + assertThat(sut.getAll()).containsExactly(A); + } + + @Test + void shouldNotBeAbleToModifyIngredients() { + // Arrange + final Ingredient sut = new Ingredient(1, List.of(A)); + final List items = sut.getAll(); + + // Act + final ThrowableAssert.ThrowingCallable action = () -> items.add(B); + + // Assert + assertThatThrownBy(action).isInstanceOf(UnsupportedOperationException.class); + } + + @ParameterizedTest + @ValueSource(longs = {0, -1}) + void shouldNotCreateIngredientWithInvalidAmount(final long amount) { + // Arrange + final ThrowableAssert.ThrowingCallable action = () -> new Ingredient(amount, List.of(A, B)); + + // Assert + assertThatThrownBy(action).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void shouldNotCreateIngredientWithEmptyInputs() { + // Act + final ThrowableAssert.ThrowingCallable action = () -> new Ingredient(1, List.of()); + + // Assert + assertThatThrownBy(action).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternImpl.java b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternImpl.java deleted file mode 100644 index 2bd80427f..000000000 --- a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.refinedmods.refinedstorage.api.autocrafting; - -import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -public class PatternImpl implements Pattern { - private final List ingredients; - private final List outputs; - - public PatternImpl(final ResourceKey... outputs) { - this(List.of(), - Arrays.stream(outputs).map(output -> new ResourceAmount(output, 1)).toArray(ResourceAmount[]::new)); - } - - public PatternImpl(final List ingredients, final ResourceAmount... outputs) { - this.ingredients = ingredients; - this.outputs = Arrays.asList(outputs); - } - - @Override - public Set getInputResources() { - throw new UnsupportedOperationException(); - } - - @Override - public Set getOutputResources() { - return outputs.stream().map(ResourceAmount::resource).collect(Collectors.toSet()); - } - - @Override - public List getIngredients() { - return ingredients; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public String toString() { - return ingredients + " -> " + outputs; - } -} diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImplTest.java b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImplTest.java index b4349737d..eeac5a9f3 100644 --- a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImplTest.java +++ b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternRepositoryImplTest.java @@ -3,12 +3,20 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static com.refinedmods.refinedstorage.api.autocrafting.PatternBuilder.pattern; import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.A; import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.B; import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.C; import static org.assertj.core.api.Assertions.assertThat; class PatternRepositoryImplTest { + private static final Pattern PATTERN_A = pattern().ingredient(C, 1).output(A, 1).build(); + private static final Pattern PATTERN_AB = pattern().ingredient(C, 1) + .output(A, 1) + .output(B, 1) + .build(); + private static final Pattern PATTERN_B = pattern().ingredient(C, 1).output(B, 1).build(); + private PatternRepositoryImpl sut; @BeforeEach @@ -26,23 +34,23 @@ void testDefaultState() { @Test void shouldAddPattern() { // Act - sut.add(new PatternImpl(A), 0); + sut.add(PATTERN_A, 0); // Assert assertThat(sut.getOutputs()).usingRecursiveFieldByFieldElementComparator().containsExactly(A); assertThat(sut.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(A) + PATTERN_A ); assertThat(sut.getByOutput(A)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(A) + PATTERN_A ); } @Test void shouldAddMultiplePatterns() { // Act - sut.add(new PatternImpl(A), 0); - sut.add(new PatternImpl(B), 0); + sut.add(PATTERN_A, 0); + sut.add(PATTERN_B, 0); // Assert assertThat(sut.getOutputs()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( @@ -50,27 +58,23 @@ void shouldAddMultiplePatterns() { B ); assertThat(sut.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new PatternImpl(A), - new PatternImpl(B) + PATTERN_A, + PATTERN_B ); assertThat(sut.getByOutput(A)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(A) + PATTERN_A ); assertThat(sut.getByOutput(B)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B) + PATTERN_B ); assertThat(sut.getByOutput(C)).isEmpty(); } @Test void shouldAddMultiplePatternsAndSomeWithTheSameOutput() { - // Arrange - final PatternImpl a = new PatternImpl(A); - final PatternImpl b = new PatternImpl(B, A); - // Act - sut.add(a, 0); - sut.add(b, 1); + sut.add(PATTERN_A, 0); + sut.add(PATTERN_AB, 1); // Assert assertThat(sut.getOutputs()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( @@ -78,15 +82,15 @@ void shouldAddMultiplePatternsAndSomeWithTheSameOutput() { B ); assertThat(sut.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( - new PatternImpl(A), - new PatternImpl(B, A) + PATTERN_A, + PATTERN_AB ); assertThat(sut.getByOutput(A)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B, A), - new PatternImpl(A) + PATTERN_AB, + PATTERN_A ); assertThat(sut.getByOutput(B)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B, A) + PATTERN_AB ); assertThat(sut.getByOutput(C)).isEmpty(); } @@ -94,65 +98,54 @@ void shouldAddMultiplePatternsAndSomeWithTheSameOutput() { @Test void shouldUpdatePriorityOfPattern() { // Arrange - final PatternImpl a = new PatternImpl(A); - final PatternImpl b = new PatternImpl(B, A); - sut.add(a, 0); - sut.add(b, 1); + sut.add(PATTERN_A, 0); + sut.add(PATTERN_AB, 1); // Act - sut.update(a, 2); + sut.update(PATTERN_A, 2); // Assert - assertThat(sut.getByOutput(A)).containsExactly(a, b); + assertThat(sut.getByOutput(A)).containsExactly(PATTERN_A, PATTERN_AB); } @Test void shouldNotUpdatePriorityOfPatternsIfThePatternHasNotBeenAddedYet() { - // Arrange - final PatternImpl pattern = new PatternImpl(C); - // Act - sut.update(pattern, 1); + sut.update(PATTERN_A, 1); // Assert - assertThat(sut.getByOutput(C)).isEmpty(); + assertThat(sut.getByOutput(A)).isEmpty(); } @Test void shouldRemovePattern() { // Arrange - final PatternImpl a = new PatternImpl(A); - final PatternImpl b = new PatternImpl(B); - - sut.add(a, 0); - sut.add(b, 0); + sut.add(PATTERN_A, 0); + sut.add(PATTERN_B, 0); // Act - sut.remove(a); + sut.remove(PATTERN_A); // Assert assertThat(sut.getOutputs()).usingRecursiveFieldByFieldElementComparator().containsExactly(B); assertThat(sut.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B) + PATTERN_B ); assertThat(sut.getByOutput(A)).isEmpty(); assertThat(sut.getByOutput(B)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B) + PATTERN_B ); } @Test void shouldRemoveMultiplePatterns() { // Arrange - final PatternImpl a = new PatternImpl(A); - final PatternImpl b = new PatternImpl(B); - - sut.add(a, 0); - sut.add(b, 0); + sut.add(PATTERN_A, 0); + sut.add(PATTERN_B, 0); // Act - sut.remove(a); - sut.remove(b); + sut.remove(PATTERN_A); + sut.remove(PATTERN_B); // Assert assertThat(sut.getOutputs()).isEmpty(); @@ -164,14 +157,11 @@ void shouldRemoveMultiplePatterns() { @Test void shouldRemovePatternButNotRemoveOutputIfAnotherPatternStillHasThatOutput() { // Arrange - final PatternImpl a = new PatternImpl(A); - final PatternImpl b = new PatternImpl(B, A); - - sut.add(a, 0); - sut.add(b, 0); + sut.add(PATTERN_A, 0); + sut.add(PATTERN_AB, 0); // Act - sut.remove(a); + sut.remove(PATTERN_A); // Assert assertThat(sut.getOutputs()).usingRecursiveFieldByFieldElementComparator().containsExactlyInAnyOrder( @@ -179,23 +169,20 @@ void shouldRemovePatternButNotRemoveOutputIfAnotherPatternStillHasThatOutput() { B ); assertThat(sut.getAll()).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B, A) + PATTERN_AB ); assertThat(sut.getByOutput(A)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B, A) + PATTERN_AB ); assertThat(sut.getByOutput(B)).usingRecursiveFieldByFieldElementComparator().containsExactly( - new PatternImpl(B, A) + PATTERN_AB ); } @Test void shouldRemovePatternThatWasNeverAddedInTheFirstPlace() { - // Arrange - final PatternImpl a = new PatternImpl(A); - // Act - sut.remove(a); + sut.remove(PATTERN_A); // Assert assertThat(sut.getOutputs()).isEmpty(); diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternTest.java b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternTest.java new file mode 100644 index 000000000..b58e6e1d8 --- /dev/null +++ b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/PatternTest.java @@ -0,0 +1,123 @@ +package com.refinedmods.refinedstorage.api.autocrafting; + +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; + +import java.util.ArrayList; +import java.util.List; + +import org.assertj.core.api.ThrowableAssert; +import org.junit.jupiter.api.Test; + +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.A; +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.B; +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.C; +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.OAK_LOG; +import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.OAK_PLANKS; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +class PatternTest { + @Test + void testPattern() { + // Act + final Pattern pattern = new Pattern( + List.of( + new Ingredient(1, List.of(A, B)), + new Ingredient(2, List.of(C)) + ), + List.of( + new ResourceAmount(OAK_LOG, 3), + new ResourceAmount(OAK_PLANKS, 4) + ) + ); + + // Assert + assertThat(pattern.ingredients().size()).isEqualTo(2); + final Ingredient firstIngredient = pattern.ingredients().getFirst(); + assertThat(firstIngredient.size()).isEqualTo(2); + assertThat(firstIngredient.getAmount()).isEqualTo(1); + assertThat(firstIngredient.get(0)).isEqualTo(A); + assertThat(firstIngredient.get(1)).isEqualTo(B); + assertThat(firstIngredient.getAll()).containsExactly(A, B); + final Ingredient secondIngredient = pattern.ingredients().get(1); + assertThat(secondIngredient.size()).isEqualTo(1); + assertThat(secondIngredient.getAmount()).isEqualTo(2); + assertThat(secondIngredient.get(0)).isEqualTo(C); + assertThat(secondIngredient.getAll()).containsExactly(C); + assertThat(pattern.outputs().size()).isEqualTo(2); + assertThat(pattern.outputs().get(0).resource()).isEqualTo(OAK_LOG); + assertThat(pattern.outputs().get(0).amount()).isEqualTo(3); + assertThat(pattern.outputs().get(1).resource()).isEqualTo(OAK_PLANKS); + assertThat(pattern.outputs().get(1).amount()).isEqualTo(4); + } + + @Test + void shouldNotCreatePatternWithoutIngredients() { + // Act + final ThrowableAssert.ThrowingCallable action = () -> new Pattern( + List.of(), + List.of( + new ResourceAmount(OAK_LOG, 3), + new ResourceAmount(OAK_PLANKS, 4) + ) + ); + + // Assert + assertThatThrownBy(action).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void shouldNotCreatePatternWithoutOutputs() { + // Act + final ThrowableAssert.ThrowingCallable action = () -> new Pattern( + List.of( + new Ingredient(1, List.of(A, B)), + new Ingredient(2, List.of(C)) + ), + List.of() + ); + + // Assert + assertThatThrownBy(action).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void shouldCopyIngredientsAndOutputs() { + // Arrange + final List ingredients = new ArrayList<>(); + ingredients.add(new Ingredient(1, List.of(A, B))); + final List outputs = new ArrayList<>(); + outputs.add(new ResourceAmount(OAK_LOG, 3)); + final Pattern sut = new Pattern(ingredients, outputs); + + // Act + ingredients.add(new Ingredient(2, List.of(C))); + outputs.add(new ResourceAmount(OAK_PLANKS, 4)); + + // Assert + assertThat(sut.ingredients().size()).isEqualTo(1); + assertThat(sut.outputs().size()).isEqualTo(1); + } + + @Test + void shouldNotBeAbleToModifyIngredientsAndOutputs() { + // Arrange + final Pattern sut = new Pattern( + List.of(new Ingredient(1, List.of(A))), + List.of(new ResourceAmount(OAK_LOG, 3)) + ); + final List ingredients = sut.ingredients(); + final List outputs = sut.outputs(); + + final Ingredient newIngredient = new Ingredient(2, List.of(B)); + final ResourceAmount newOutput = new ResourceAmount(OAK_PLANKS, 4); + + // Act + final ThrowableAssert.ThrowingCallable action = () -> ingredients.add(newIngredient); + final ThrowableAssert.ThrowingCallable action2 = () -> outputs.add(newOutput); + + // Assert + assertThatThrownBy(action).isInstanceOf(UnsupportedOperationException.class); + assertThatThrownBy(action2).isInstanceOf(UnsupportedOperationException.class); + } +} diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilderTest.java b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilderTest.java index 462f75c18..dfd115c8e 100644 --- a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilderTest.java +++ b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewBuilderTest.java @@ -1,7 +1,6 @@ package com.refinedmods.refinedstorage.api.autocrafting.preview; import com.refinedmods.refinedstorage.api.autocrafting.Pattern; -import com.refinedmods.refinedstorage.api.autocrafting.PatternImpl; import java.util.Collections; import java.util.List; @@ -12,6 +11,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import static com.refinedmods.refinedstorage.api.autocrafting.PatternBuilder.pattern; import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.OAK_LOG; import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.OAK_PLANKS; import static com.refinedmods.refinedstorage.api.autocrafting.ResourceFixtures.SPRUCE_LOG; @@ -36,7 +36,7 @@ void testDefaultState() { @Test void testWithPatternWithCycle() { // Arrange - final Pattern pattern = new PatternImpl(OAK_PLANKS); + final Pattern pattern = pattern().ingredient(OAK_LOG, 1).output(OAK_PLANKS, 4).build(); // Act final Preview preview = PreviewBuilder.ofType(PreviewType.CYCLE_DETECTED) @@ -45,7 +45,7 @@ void testWithPatternWithCycle() { // Assert assertThat(preview).usingRecursiveComparison() - .isEqualTo(new Preview(PreviewType.CYCLE_DETECTED, Collections.emptyList(), pattern.getOutputs())); + .isEqualTo(new Preview(PreviewType.CYCLE_DETECTED, Collections.emptyList(), pattern.outputs())); } @Test diff --git a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewTest.java b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewTest.java index 28889b6bd..2071c8bdf 100644 --- a/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewTest.java +++ b/refinedstorage-autocrafting-api/src/test/java/com/refinedmods/refinedstorage/api/autocrafting/preview/PreviewTest.java @@ -1,6 +1,5 @@ package com.refinedmods.refinedstorage.api.autocrafting.preview; -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; import com.refinedmods.refinedstorage.api.autocrafting.Pattern; import com.refinedmods.refinedstorage.api.autocrafting.PatternRepository; import com.refinedmods.refinedstorage.api.autocrafting.calculation.CraftingCalculator; @@ -8,7 +7,6 @@ import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.storage.root.RootStorage; -import java.util.Collections; import java.util.stream.Stream; import org.assertj.core.api.recursive.comparison.RecursiveComparisonConfiguration; @@ -676,34 +674,4 @@ void shouldDetectNumberOverflowWithOutputOfChildPattern() { // Assert assertThat(preview).usingRecursiveComparison().isEqualTo(PreviewBuilder.ofType(OVERFLOW).build()); } - - @Test - void shouldIgnoreEmptyIngredients() { - // Arrange - final RootStorage storage = storage( - new ResourceAmount(OAK_LOG, 1) - ); - final PatternRepository patterns = patterns( - pattern() - .ingredient(new Ingredient(10, Collections.emptyList())) - .ingredient(OAK_LOG, 1) - .output(OAK_PLANKS, 4) - .build(), - pattern() - .ingredient(OAK_PLANKS, 4) - .output(CRAFTING_TABLE, 1) - .build() - ); - - // Act - final CraftingCalculator sut = new CraftingCalculatorImpl(patterns, storage); - final Preview preview = calculatePreview(sut, CRAFTING_TABLE, 1); - - // Assert - assertThat(preview).usingRecursiveComparison(PREVIEW_CONFIG).isEqualTo(PreviewBuilder.ofType(SUCCESS) - .addToCraft(CRAFTING_TABLE, 1) - .addToCraft(OAK_PLANKS, 4) - .addAvailable(OAK_LOG, 1) - .build()); - } } diff --git a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/autocrafting/PatternProviderItem.java b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/autocrafting/PatternProviderItem.java index a9382e04f..cc3cc799a 100644 --- a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/autocrafting/PatternProviderItem.java +++ b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/autocrafting/PatternProviderItem.java @@ -21,4 +21,6 @@ static boolean isValid(final ItemStack stack, final Level level) { UUID getId(ItemStack stack); Optional getPattern(ItemStack stack, Level level); + + Optional getOutput(ItemStack stack, Level level); } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPattern.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPattern.java deleted file mode 100644 index d2da98a6d..000000000 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPattern.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.refinedmods.refinedstorage.common.autocrafting; - -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; -import com.refinedmods.refinedstorage.api.autocrafting.Pattern; -import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; -import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -class CraftingPattern implements Pattern { - private final UUID id; - private final List ingredients; - private final ResourceAmount output; - private final List outputs; - private final Set inputResources; - private final Set outputResources; - - CraftingPattern(final UUID id, - final List> inputs, - final ResourceAmount output, - final List byproducts) { - this.id = id; - this.output = output; - this.inputResources = inputs.stream().flatMap(List::stream).collect(Collectors.toSet()); - this.outputResources = Set.of(output.resource()); - this.ingredients = inputs.stream().map(i -> new Ingredient(i.isEmpty() ? 0 : 1, i)).toList(); - this.outputs = Stream.concat(Stream.of(output), byproducts.stream()).toList(); - } - - @Override - public Set getOutputResources() { - return outputResources; - } - - @Override - public Set getInputResources() { - return inputResources; - } - - @Override - public List getIngredients() { - return ingredients; - } - - @Override - public List getOutputs() { - return outputs; - } - - ResourceAmount getOutput() { - return output; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final CraftingPattern that = (CraftingPattern) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } -} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java index 4e28038bf..4222382af 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java @@ -1,10 +1,11 @@ package com.refinedmods.refinedstorage.common.autocrafting; -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.api.RefinedStorageClientApi; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; import com.refinedmods.refinedstorage.common.support.resource.ItemResource; +import java.util.List; import javax.annotation.Nullable; import net.minecraft.ChatFormatting; @@ -30,7 +31,7 @@ class CraftingPatternClientTooltipComponent implements ClientTooltipComponent { private final int width; private final int height; - private final CraftingPattern craftingPattern; + private final PatternResolver.ResolvedCraftingPattern pattern; @Nullable private final ItemStack outputStack; @@ -40,18 +41,20 @@ class CraftingPatternClientTooltipComponent implements ClientTooltipComponent { private long cycleStart = 0; private int currentCycle = 0; - CraftingPatternClientTooltipComponent(final int width, final int height, final CraftingPattern craftingPattern) { + CraftingPatternClientTooltipComponent(final int width, + final int height, + final PatternResolver.ResolvedCraftingPattern pattern) { this.width = width; this.height = height; - this.craftingPattern = craftingPattern; - final ItemResource outputResource = craftingPattern.getOutput().resource() instanceof ItemResource itemResource + this.pattern = pattern; + final ItemResource outputResource = pattern.output().resource() instanceof ItemResource itemResource ? itemResource : null; this.outputStack = outputResource != null - ? outputResource.toItemStack(craftingPattern.getOutput().amount()) + ? outputResource.toItemStack(pattern.output().amount()) : null; this.outputText = outputResource != null - ? Component.literal(String.format("%dx ", craftingPattern.getOutput().amount())) + ? Component.literal(String.format("%dx ", pattern.output().amount())) .append(outputResource.toItemStack().getHoverName()) .withStyle(ChatFormatting.GRAY) : null; } @@ -95,12 +98,12 @@ private void renderInputSlots(final int x, final int y, final GuiGraphics graphi private void renderInputSlot(final int x, final int y, final GuiGraphics graphics, final int sx, final int sy) { graphics.blitSprite(SLOT, x + sx * 18, y + sy * 18, 18, 18); final int index = sy * width + sx; - final Ingredient ingredient = craftingPattern.getIngredients().get(index); - if (ingredient.isEmpty()) { + final List inputs = pattern.inputs().get(index); + if (inputs.isEmpty()) { return; } - final int idx = currentCycle % ingredient.size(); - final ResourceKey resource = ingredient.get(idx); + final int idx = currentCycle % inputs.size(); + final ResourceKey resource = inputs.get(idx); RefinedStorageClientApi.INSTANCE.getResourceRendering(resource.getClass()).render( resource, graphics, diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternItem.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternItem.java index ce91d7d40..4d63dda66 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternItem.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternItem.java @@ -2,20 +2,16 @@ import com.refinedmods.refinedstorage.api.autocrafting.Pattern; import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; import com.refinedmods.refinedstorage.common.api.autocrafting.PatternProviderItem; import com.refinedmods.refinedstorage.common.api.support.HelpTooltipComponent; -import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; import com.refinedmods.refinedstorage.common.content.DataComponents; import com.refinedmods.refinedstorage.common.content.Items; -import com.refinedmods.refinedstorage.common.support.RecipeMatrixContainer; import com.refinedmods.refinedstorage.common.support.resource.ItemResource; import com.refinedmods.refinedstorage.common.util.ClientPlatformUtil; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; import javax.annotation.Nullable; @@ -31,22 +27,26 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.item.crafting.CraftingInput; -import net.minecraft.world.item.crafting.CraftingRecipe; -import net.minecraft.world.item.crafting.RecipeHolder; -import net.minecraft.world.item.crafting.RecipeType; -import net.minecraft.world.item.crafting.SingleRecipeInput; -import net.minecraft.world.item.crafting.SmithingRecipeInput; import net.minecraft.world.level.Level; import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createTranslation; import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createTranslationKey; public class PatternItem extends Item implements PatternProviderItem { + private static final Map CRAFTING_PATTERN_CACHE = new HashMap<>(); + private static final Map PROCESSING_PATTERN_CACHE = + new HashMap<>(); + private static final Map SMITHING_TABLE_PATTERN_CACHE = + new HashMap<>(); + private static final Map STONE_CUTTER_PATTERN_CACHE = + new HashMap<>(); + private static final Component HELP = createTranslation("item", "pattern.help"); private static final MutableComponent FUZZY_MODE = createTranslation("item", "pattern.fuzzy_mode") .withStyle(ChatFormatting.YELLOW); + private final PatternResolver resolver = new PatternResolver(); + public PatternItem() { super(new Item.Properties()); } @@ -87,21 +87,21 @@ public Optional getTooltipImage(final ItemStack stack) { return Optional.of(new HelpTooltipComponent(HELP)); } final Level level = ClientPlatformUtil.getClientLevel(); + if (level == null) { + return Optional.empty(); + } return switch (state.type()) { case CRAFTING -> { final CraftingPatternState craftingState = stack.get(DataComponents.INSTANCE.getCraftingPatternState()); - if (craftingState == null || level == null) { + if (craftingState == null) { yield Optional.empty(); } - yield RefinedStorageApi.INSTANCE.getPattern(stack, level) - .filter(CraftingPattern.class::isInstance) - .map(CraftingPattern.class::cast) - .map(craftingPattern -> new CraftingPatternTooltipComponent( - state.id(), - craftingPattern, - craftingState.input().input().width(), - craftingState.input().input().height() - )); + yield getCachedCraftingPattern(state, stack, level).map(pattern -> new CraftingPatternTooltipComponent( + state.id(), + pattern, + craftingState.input().input().width(), + craftingState.input().input().height() + )); } case PROCESSING -> { final ProcessingPatternState processingState = stack.get( @@ -112,33 +112,16 @@ public Optional getTooltipImage(final ItemStack stack) { } yield Optional.of(new ProcessingPatternTooltipComponent(state.id(), processingState)); } - case STONECUTTER -> { - final StonecutterPatternState stonecutterState = stack.get( - DataComponents.INSTANCE.getStonecutterPatternState() - ); - if (stonecutterState == null || level == null) { - yield Optional.empty(); - } - yield RefinedStorageApi.INSTANCE.getPattern(stack, level) - .filter(StonecutterPattern.class::isInstance) - .map(StonecutterPattern.class::cast) - .map(stonecutterPattern -> new StonecutterPatternTooltipComponent(state.id(), stonecutterPattern)); - } - case SMITHING_TABLE -> { - final SmithingTablePatternState smithingTableState = stack.get( - DataComponents.INSTANCE.getSmithingTablePatternState() - ); - if (smithingTableState == null || level == null) { - yield Optional.empty(); - } - yield RefinedStorageApi.INSTANCE.getPattern(stack, level) - .filter(SmithingTablePattern.class::isInstance) - .map(SmithingTablePattern.class::cast) - .map(smithingTablePattern -> new SmithingTablePatternTooltipComponent( - state.id(), - smithingTablePattern - )); - } + case STONECUTTER -> getCachedStonecutterPattern(state, stack, level).map( + pattern -> new StonecutterPatternTooltipComponent( + state.id(), + pattern + )); + case SMITHING_TABLE -> getCachedSmithingTablePattern(state, stack, level).map( + pattern -> new SmithingTablePatternTooltipComponent( + state.id(), + pattern + )); }; } @@ -159,147 +142,101 @@ public Optional getPattern(final ItemStack stack, final Level level) { return Optional.empty(); } return switch (state.type()) { - case CRAFTING -> getCraftingPattern(state.id(), stack, level); - case PROCESSING -> getProcessingPattern(state.id(), stack); - case STONECUTTER -> getStonecutterPattern(state.id(), stack, level); - case SMITHING_TABLE -> getSmithingTablePattern(state.id(), stack, level); + case CRAFTING -> resolver.getCraftingPattern(stack, level) + .map(PatternResolver.ResolvedCraftingPattern::pattern); + case PROCESSING -> resolver.getProcessingPattern(stack) + .map(PatternResolver.ResolvedProcessingPattern::pattern); + case STONECUTTER -> resolver.getStonecutterPattern(stack, level) + .map(PatternResolver.ResolvedStonecutterPattern::pattern); + case SMITHING_TABLE -> resolver.getSmithingTablePattern(stack, level) + .map(PatternResolver.ResolvedSmithingTablePattern::pattern); }; } - private Optional getCraftingPattern(final UUID id, final ItemStack stack, final Level level) { - final CraftingPatternState craftingState = stack.get(DataComponents.INSTANCE.getCraftingPatternState()); - if (craftingState == null) { - return Optional.empty(); - } - return getCraftingPattern(id, level, craftingState); - } - - private Optional getCraftingPattern(final UUID id, final Level level, final CraftingPatternState state) { - final RecipeMatrixContainer craftingMatrix = getFilledCraftingMatrix(state); - final CraftingInput.Positioned positionedCraftingInput = craftingMatrix.asPositionedCraftInput(); - final CraftingInput craftingInput = positionedCraftingInput.input(); - return level.getRecipeManager() - .getRecipeFor(RecipeType.CRAFTING, craftingInput, level) - .map(RecipeHolder::value) - .map(recipe -> toCraftingPattern(id, level, recipe, craftingInput, state)); - } - - private RecipeMatrixContainer getFilledCraftingMatrix(final CraftingPatternState state) { - final CraftingInput.Positioned positionedInput = state.input(); - final CraftingInput input = positionedInput.input(); - final RecipeMatrixContainer craftingMatrix = new RecipeMatrixContainer(null, input.width(), input.height()); - for (int i = 0; i < input.size(); ++i) { - craftingMatrix.setItem(i, input.getItem(i)); - } - return craftingMatrix; - } - - private CraftingPattern toCraftingPattern(final UUID id, - final Level level, - final CraftingRecipe recipe, - final CraftingInput craftingInput, - final CraftingPatternState state) { - final List> inputs = getInputs(recipe, state); - final ResourceAmount output = getOutput(level, recipe, craftingInput); - final List byproducts = getByproducts(recipe, craftingInput); - return new CraftingPattern(id, inputs, output, byproducts); - } - - private List> getInputs(final CraftingRecipe recipe, final CraftingPatternState state) { - final List> inputs = new ArrayList<>(); - for (int i = 0; i < state.input().input().size(); ++i) { - final ItemStack input = state.input().input().getItem(i); - if (input.isEmpty()) { - inputs.add(Collections.emptyList()); - } else if (state.fuzzyMode() && i < recipe.getIngredients().size()) { - final ItemStack[] ingredients = recipe.getIngredients().get(i).getItems(); - inputs.add(Arrays.stream(ingredients) - .map(item -> (PlatformResourceKey) ItemResource.ofItemStack(item)) - .toList()); - } else { - inputs.add(List.of(ItemResource.ofItemStack(input))); - } - } - return inputs; - } - - private ResourceAmount getOutput(final Level level, - final CraftingRecipe recipe, - final CraftingInput craftingInput) { - final ItemStack outputStack = recipe.assemble(craftingInput, level.registryAccess()); - return new ResourceAmount(ItemResource.ofItemStack(outputStack), outputStack.getCount()); - } - - private List getByproducts(final CraftingRecipe recipe, final CraftingInput craftingInput) { - return recipe.getRemainingItems(craftingInput) - .stream() - .filter(byproduct -> !byproduct.isEmpty()) - .map(byproduct -> new ResourceAmount(ItemResource.ofItemStack(byproduct), byproduct.getCount())) - .toList(); - } - - private Optional getProcessingPattern(final UUID id, final ItemStack stack) { - final ProcessingPatternState state = stack.get( - DataComponents.INSTANCE.getProcessingPatternState() - ); + @Override + public Optional getOutput(final ItemStack stack, final Level level) { + final PatternState state = stack.get(DataComponents.INSTANCE.getPatternState()); if (state == null) { return Optional.empty(); } - return Optional.of( - new ProcessingPattern(id, state.getFlatInputs(), state.getIngredients(), state.getFlatOutputs()) - ); + return switch (state.type()) { + case CRAFTING -> getCachedCraftingPattern(state, stack, level) + .map(PatternResolver.ResolvedCraftingPattern::output) + .map(ResourceAmount::resource) + .filter(ItemResource.class::isInstance) + .map(ItemResource.class::cast) + .map(ItemResource::toItemStack); + case PROCESSING -> getCachedProcessingPattern(state, stack) + .map(PatternResolver.ResolvedProcessingPattern::pattern) + .filter(pattern -> pattern.outputs().size() == 1) + .map(pattern -> pattern.outputs().getFirst().resource()) + .filter(ItemResource.class::isInstance) + .map(ItemResource.class::cast) + .map(ItemResource::toItemStack); + case STONECUTTER -> getCachedStonecutterPattern(state, stack, level) + .map(PatternResolver.ResolvedStonecutterPattern::output) + .map(ItemResource::toItemStack); + case SMITHING_TABLE -> getCachedSmithingTablePattern(state, stack, level) + .map(PatternResolver.ResolvedSmithingTablePattern::output) + .map(ItemResource::toItemStack); + }; } - private Optional getStonecutterPattern(final UUID id, final ItemStack stack, final Level level) { - final StonecutterPatternState state = stack.get(DataComponents.INSTANCE.getStonecutterPatternState()); - if (state == null) { - return Optional.empty(); + private Optional getCachedCraftingPattern(final PatternState state, + final ItemStack stack, + final Level level) { + final PatternResolver.ResolvedCraftingPattern pattern = CRAFTING_PATTERN_CACHE.get(state.id()); + if (pattern == null) { + return resolver.getCraftingPattern(stack, level).map(resolved -> { + CRAFTING_PATTERN_CACHE.put(state.id(), resolved); + return resolved; + }); } - return getStonecutterPattern(id, level, state); + return Optional.of(pattern); } - private Optional getStonecutterPattern(final UUID id, final Level level, - final StonecutterPatternState state) { - final SingleRecipeInput input = new SingleRecipeInput(state.input().toItemStack()); - final ItemStack selectedOutput = state.selectedOutput().toItemStack(); - final var recipes = level.getRecipeManager().getRecipesFor(RecipeType.STONECUTTING, input, level); - for (final var recipe : recipes) { - final ItemStack output = recipe.value().assemble(input, level.registryAccess()); - if (ItemStack.isSameItemSameComponents(output, selectedOutput)) { - return Optional.of(new StonecutterPattern( - id, - state.input(), - ItemResource.ofItemStack(output) - )); - } + private Optional getCachedSmithingTablePattern( + final PatternState state, + final ItemStack stack, + final Level level + ) { + final PatternResolver.ResolvedSmithingTablePattern pattern = SMITHING_TABLE_PATTERN_CACHE.get(state.id()); + if (pattern == null) { + return resolver.getSmithingTablePattern(stack, level).map(resolved -> { + SMITHING_TABLE_PATTERN_CACHE.put(state.id(), resolved); + return resolved; + }); } - return Optional.empty(); + return Optional.of(pattern); } - private Optional getSmithingTablePattern(final UUID id, final ItemStack stack, final Level level) { - final SmithingTablePatternState state = stack.get(DataComponents.INSTANCE.getSmithingTablePatternState()); - if (state == null) { - return Optional.empty(); + private Optional getCachedStonecutterPattern( + final PatternState state, + final ItemStack stack, + final Level level + ) { + final PatternResolver.ResolvedStonecutterPattern pattern = STONE_CUTTER_PATTERN_CACHE.get(state.id()); + if (pattern == null) { + return resolver.getStonecutterPattern(stack, level).map(resolved -> { + STONE_CUTTER_PATTERN_CACHE.put(state.id(), resolved); + return resolved; + }); } - return getSmithingTablePattern(id, level, state); + return Optional.of(pattern); } - private Optional getSmithingTablePattern(final UUID id, - final Level level, - final SmithingTablePatternState state) { - final SmithingRecipeInput input = new SmithingRecipeInput( - state.template().toItemStack(), - state.base().toItemStack(), - state.addition().toItemStack() - ); - return level.getRecipeManager().getRecipeFor(RecipeType.SMITHING, input, level) - .map(recipe -> new SmithingTablePattern( - id, - state.template(), - state.base(), - state.addition(), - ItemResource.ofItemStack(recipe.value().assemble(input, level.registryAccess()))) - ); + private Optional getCachedProcessingPattern( + final PatternState state, + final ItemStack stack + ) { + final PatternResolver.ResolvedProcessingPattern pattern = PROCESSING_PATTERN_CACHE.get(state.id()); + if (pattern == null) { + return resolver.getProcessingPattern(stack).map(resolved -> { + PROCESSING_PATTERN_CACHE.put(state.id(), resolved); + return resolved; + }); + } + return Optional.of(pattern); } @Override @@ -314,7 +251,10 @@ public InteractionResultHolder use(final Level level, final Player pl return new InteractionResultHolder<>(InteractionResult.PASS, stack); } - public record CraftingPatternTooltipComponent(UUID id, CraftingPattern craftingPattern, int width, int height) + public record CraftingPatternTooltipComponent(UUID id, + PatternResolver.ResolvedCraftingPattern pattern, + int width, + int height) implements TooltipComponent { } @@ -322,11 +262,11 @@ public record ProcessingPatternTooltipComponent(UUID id, ProcessingPatternState implements TooltipComponent { } - public record StonecutterPatternTooltipComponent(UUID id, StonecutterPattern stonecutterPattern) + public record StonecutterPatternTooltipComponent(UUID id, PatternResolver.ResolvedStonecutterPattern pattern) implements TooltipComponent { } - public record SmithingTablePatternTooltipComponent(UUID id, SmithingTablePattern smithingTablePattern) + public record SmithingTablePatternTooltipComponent(UUID id, PatternResolver.ResolvedSmithingTablePattern pattern) implements TooltipComponent { } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternRendering.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternRendering.java index 5d0d4d124..0a18acbd9 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternRendering.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternRendering.java @@ -1,11 +1,9 @@ package com.refinedmods.refinedstorage.common.autocrafting; -import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; import com.refinedmods.refinedstorage.common.api.autocrafting.PatternProviderItem; import com.refinedmods.refinedstorage.common.autocrafting.autocrafter.AutocrafterScreen; import com.refinedmods.refinedstorage.common.autocrafting.autocraftermanager.AutocrafterManagerScreen; import com.refinedmods.refinedstorage.common.autocrafting.patterngrid.PatternGridScreen; -import com.refinedmods.refinedstorage.common.support.resource.ItemResource; import com.refinedmods.refinedstorage.common.util.ClientPlatformUtil; import java.util.Optional; @@ -45,17 +43,9 @@ public static Optional getOutput(final ItemStack stack) { if (level == null) { return Optional.empty(); } - return RefinedStorageApi.INSTANCE.getPattern(stack, level).map(pattern -> switch (pattern) { - case CraftingPattern craftingPattern - when craftingPattern.getOutput().resource() instanceof ItemResource itemResource -> - itemResource.toItemStack(); - case ProcessingPattern processingPattern - when processingPattern.getOutputs().size() == 1 - && processingPattern.getOutputs().getFirst().resource() instanceof ItemResource itemResource -> - itemResource.toItemStack(); - case StonecutterPattern stonecutterPattern -> stonecutterPattern.getOutput().toItemStack(); - case SmithingTablePattern smithingTablePattern -> smithingTablePattern.getOutput().toItemStack(); - default -> null; - }); + if (stack.getItem() instanceof PatternProviderItem patternProviderItem) { + return patternProviderItem.getOutput(stack, level); + } + return Optional.empty(); } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternResolver.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternResolver.java new file mode 100644 index 000000000..882ace9c8 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternResolver.java @@ -0,0 +1,220 @@ +package com.refinedmods.refinedstorage.common.autocrafting; + +import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; +import com.refinedmods.refinedstorage.api.autocrafting.Pattern; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.content.DataComponents; +import com.refinedmods.refinedstorage.common.support.RecipeMatrixContainer; +import com.refinedmods.refinedstorage.common.support.resource.ItemResource; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import net.minecraft.world.item.crafting.SmithingRecipeInput; +import net.minecraft.world.level.Level; + +public class PatternResolver { + PatternResolver() { + } + + Optional getCraftingPattern(final ItemStack stack, final Level level) { + final CraftingPatternState craftingState = stack.get(DataComponents.INSTANCE.getCraftingPatternState()); + if (craftingState == null) { + return Optional.empty(); + } + return getCraftingPattern(level, craftingState); + } + + private Optional getCraftingPattern(final Level level, + final CraftingPatternState state) { + final RecipeMatrixContainer craftingMatrix = getFilledCraftingMatrix(state); + final CraftingInput.Positioned positionedCraftingInput = craftingMatrix.asPositionedCraftInput(); + final CraftingInput craftingInput = positionedCraftingInput.input(); + return level.getRecipeManager() + .getRecipeFor(RecipeType.CRAFTING, craftingInput, level) + .map(RecipeHolder::value) + .map(recipe -> toCraftingPattern(level, recipe, craftingInput, state)); + } + + private RecipeMatrixContainer getFilledCraftingMatrix(final CraftingPatternState state) { + final CraftingInput.Positioned positionedInput = state.input(); + final CraftingInput input = positionedInput.input(); + final RecipeMatrixContainer craftingMatrix = new RecipeMatrixContainer(null, input.width(), input.height()); + for (int i = 0; i < input.size(); ++i) { + craftingMatrix.setItem(i, input.getItem(i)); + } + return craftingMatrix; + } + + private ResolvedCraftingPattern toCraftingPattern(final Level level, + final CraftingRecipe recipe, + final CraftingInput craftingInput, + final CraftingPatternState state) { + final List> inputs = getInputs(recipe, state); + final ResourceAmount output = getOutput(level, recipe, craftingInput); + final List byproducts = getByproducts(recipe, craftingInput); + return new ResolvedCraftingPattern(inputs, output, byproducts); + } + + private List> getInputs(final CraftingRecipe recipe, final CraftingPatternState state) { + final List> inputs = new ArrayList<>(); + for (int i = 0; i < state.input().input().size(); ++i) { + final ItemStack input = state.input().input().getItem(i); + if (input.isEmpty()) { + inputs.add(Collections.emptyList()); + } else if (state.fuzzyMode() && i < recipe.getIngredients().size()) { + final ItemStack[] ingredients = recipe.getIngredients().get(i).getItems(); + inputs.add(Arrays.stream(ingredients) + .map(item -> (PlatformResourceKey) ItemResource.ofItemStack(item)) + .toList()); + } else { + inputs.add(List.of(ItemResource.ofItemStack(input))); + } + } + return inputs; + } + + private ResourceAmount getOutput(final Level level, + final CraftingRecipe recipe, + final CraftingInput craftingInput) { + final ItemStack outputStack = recipe.assemble(craftingInput, level.registryAccess()); + return new ResourceAmount(ItemResource.ofItemStack(outputStack), outputStack.getCount()); + } + + private List getByproducts(final CraftingRecipe recipe, final CraftingInput craftingInput) { + return recipe.getRemainingItems(craftingInput) + .stream() + .filter(byproduct -> !byproduct.isEmpty()) + .map(byproduct -> new ResourceAmount(ItemResource.ofItemStack(byproduct), byproduct.getCount())) + .toList(); + } + + Optional getProcessingPattern(final ItemStack stack) { + final ProcessingPatternState state = stack.get( + DataComponents.INSTANCE.getProcessingPatternState() + ); + if (state == null) { + return Optional.empty(); + } + return Optional.of( + new ResolvedProcessingPattern(state.getIngredients(), state.getFlatOutputs()) + ); + } + + Optional getStonecutterPattern(final ItemStack stack, + final Level level) { + final StonecutterPatternState state = stack.get(DataComponents.INSTANCE.getStonecutterPatternState()); + if (state == null) { + return Optional.empty(); + } + return getStonecutterPattern(level, state); + } + + private Optional getStonecutterPattern(final Level level, + final StonecutterPatternState state) { + final SingleRecipeInput input = new SingleRecipeInput(state.input().toItemStack()); + final ItemStack selectedOutput = state.selectedOutput().toItemStack(); + final var recipes = level.getRecipeManager().getRecipesFor(RecipeType.STONECUTTING, input, level); + for (final var recipe : recipes) { + final ItemStack output = recipe.value().assemble(input, level.registryAccess()); + if (ItemStack.isSameItemSameComponents(output, selectedOutput)) { + return Optional.of(new ResolvedStonecutterPattern( + state.input(), + ItemResource.ofItemStack(output) + )); + } + } + return Optional.empty(); + } + + Optional getSmithingTablePattern(final ItemStack stack, + final Level level) { + final SmithingTablePatternState state = stack.get(DataComponents.INSTANCE.getSmithingTablePatternState()); + if (state == null) { + return Optional.empty(); + } + return getSmithingTablePattern(level, state); + } + + private Optional getSmithingTablePattern(final Level level, + final SmithingTablePatternState state) { + final SmithingRecipeInput input = new SmithingRecipeInput( + state.template().toItemStack(), + state.base().toItemStack(), + state.addition().toItemStack() + ); + return level.getRecipeManager() + .getRecipeFor(RecipeType.SMITHING, input, level) + .map(recipe -> new ResolvedSmithingTablePattern( + state.template(), + state.base(), + state.addition(), + ItemResource.ofItemStack(recipe.value().assemble(input, level.registryAccess()))) + ); + } + + public record ResolvedCraftingPattern(List> inputs, + ResourceAmount output, + Pattern pattern) { + ResolvedCraftingPattern(final List> inputs, + final ResourceAmount output, + final List byproducts) { + this(inputs, output, new Pattern( + inputs.stream() + .filter(i -> !i.isEmpty()) + .map(i -> new Ingredient(1, i)) + .toList(), + Stream.concat(Stream.of(output), byproducts.stream()).toList() + )); + } + } + + public record ResolvedProcessingPattern(Pattern pattern) { + ResolvedProcessingPattern(final List ingredients, final List outputs) { + this(new Pattern(ingredients, outputs)); + } + } + + public record ResolvedStonecutterPattern(ItemResource input, + ItemResource output, + Pattern pattern) { + ResolvedStonecutterPattern(final ItemResource input, final ItemResource output) { + this(input, output, new Pattern( + List.of(new Ingredient(1, List.of(input))), + List.of(new ResourceAmount(output, 1)) + )); + } + } + + public record ResolvedSmithingTablePattern(ItemResource template, + ItemResource base, + ItemResource addition, + ItemResource output, + Pattern pattern) { + ResolvedSmithingTablePattern(final ItemResource template, + final ItemResource base, + final ItemResource addition, + final ItemResource output) { + this(template, base, addition, output, new Pattern( + List.of(single(template), single(base), single(addition)), + List.of(new ResourceAmount(output, 1)) + )); + } + + private static Ingredient single(final ResourceKey input) { + return new Ingredient(1, List.of(input)); + } + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternTooltipCache.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternTooltipCache.java index 969a65217..1b602cc02 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternTooltipCache.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/PatternTooltipCache.java @@ -19,7 +19,7 @@ public static ClientTooltipComponent getComponent(final PatternItem.CraftingPatt return CACHE.computeIfAbsent(key.id(), id -> new CraftingPatternClientTooltipComponent( key.width(), key.height(), - key.craftingPattern() + key.pattern() )); } @@ -35,7 +35,7 @@ public static ClientTooltipComponent getComponent(final PatternItem.StonecutterP CACHE.clear(); } return CACHE.computeIfAbsent(key.id(), id -> new StonecutterPatternClientTooltipComponent( - key.stonecutterPattern() + key.pattern() )); } @@ -44,7 +44,7 @@ public static ClientTooltipComponent getComponent(final PatternItem.SmithingTabl CACHE.clear(); } return CACHE.computeIfAbsent(key.id(), id -> new SmithingTablePatternClientTooltipComponent( - key.smithingTablePattern() + key.pattern() )); } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPattern.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPattern.java deleted file mode 100644 index e8ff11af7..000000000 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPattern.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.refinedmods.refinedstorage.common.autocrafting; - -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; -import com.refinedmods.refinedstorage.api.autocrafting.Pattern; -import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -class ProcessingPattern implements Pattern { - private final UUID id; - private final List ingredients; - private final List outputs; - private final Set inputResources; - private final Set outputResources; - - ProcessingPattern(final UUID id, - final List inputs, - final List ingredients, - final List outputs) { - this.id = id; - this.ingredients = ingredients; - this.outputs = outputs; - this.inputResources = inputs.stream().map(ResourceAmount::resource).collect(Collectors.toSet()); - this.outputResources = outputs.stream().map(ResourceAmount::resource).collect(Collectors.toSet()); - } - - @Override - public Set getOutputResources() { - return outputResources; - } - - @Override - public List getIngredients() { - return ingredients; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public Set getInputResources() { - return inputResources; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final ProcessingPattern that = (ProcessingPattern) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } -} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java index 7e0448a1f..251143bdb 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java @@ -1,13 +1,10 @@ package com.refinedmods.refinedstorage.common.autocrafting; -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.api.RefinedStorageClientApi; import com.refinedmods.refinedstorage.common.api.support.resource.ResourceRendering; import com.refinedmods.refinedstorage.common.support.ResourceSlotRendering; -import java.util.Collections; import java.util.List; import net.minecraft.ChatFormatting; @@ -22,14 +19,12 @@ import static com.refinedmods.refinedstorage.common.support.Sprites.SLOT; class ProcessingPatternClientTooltipComponent implements ClientTooltipComponent { - private static final Ingredient EMPTY_INGREDIENT = new Ingredient(0, Collections.emptyList()); - private static final long CYCLE_MS = 1000; private static final int ARROW_SPACING = 8; private final int rows; private final List outputTexts; - private final List ingredients; + private final List> inputs; private final List> outputs; private long cycleStart = 0; @@ -38,11 +33,14 @@ class ProcessingPatternClientTooltipComponent implements ClientTooltipComponent ProcessingPatternClientTooltipComponent(final ProcessingPatternState state) { this.rows = calculateMaxRows(state); this.outputTexts = getOutputText(state); - this.ingredients = state.ingredients() + this.inputs = state.ingredients() .stream() .map(processingIngredient -> - processingIngredient.map(ProcessingPatternState.ProcessingIngredient::toIngredient) - .orElse(EMPTY_INGREDIENT) + processingIngredient + .stream() + .flatMap(i -> i.calculateInputsIncludingAlternatives().stream() + .map(resource -> new ResourceAmount(resource, i.input().amount()))) + .toList() ).toList(); this.outputs = state.outputs().stream().map(output -> output.map(List::of).orElse(List.of())).toList(); } @@ -119,7 +117,7 @@ private void renderMatrixSlots(final int x, final int y, final boolean input, final GuiGraphics graphics) { - final int maxSize = input ? ingredients.size() : outputs.size(); + final int maxSize = input ? inputs.size() : outputs.size(); for (int row = 0; row < rows; ++row) { for (int column = 0; column < 3; ++column) { final int slotXOffset = !input ? ((18 * 3) + ARROW_SPACING + LIGHT_ARROW_WIDTH + ARROW_SPACING) : 0; @@ -130,7 +128,7 @@ private void renderMatrixSlots(final int x, break; } if (input) { - renderMatrixSlot(graphics, slotX, slotY, ingredients.get(idx)); + renderMatrixSlot(graphics, slotX, slotY, inputs.get(idx)); } else { renderMatrixSlot(graphics, slotX, slotY, outputs.get(idx)); } @@ -138,22 +136,6 @@ private void renderMatrixSlots(final int x, } } - private void renderMatrixSlot( - final GuiGraphics graphics, - final int slotX, - final int slotY, - final Ingredient ingredient - ) { - graphics.blitSprite(SLOT, slotX, slotY, 18, 18); - if (ingredient.isEmpty()) { - return; - } - final ResourceKey resource = ingredient.get(currentCycle % ingredient.size()); - final ResourceRendering rendering = RefinedStorageClientApi.INSTANCE.getResourceRendering(resource.getClass()); - rendering.render(resource, graphics, slotX + 1, slotY + 1); - ResourceSlotRendering.renderAmount(graphics, slotX + 1, slotY + 1, ingredient.getAmount(), rendering); - } - private void renderMatrixSlot( final GuiGraphics graphics, final int slotX, diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternState.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternState.java index 3a78d8afd..27b2ff14a 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternState.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternState.java @@ -84,7 +84,7 @@ public Ingredient toIngredient() { return new Ingredient(input.amount(), calculateInputsIncludingAlternatives()); } - private List calculateInputsIncludingAlternatives() { + public List calculateInputsIncludingAlternatives() { return Stream.concat( Stream.of(input.resource()), allowedAlternativeIds.stream() diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePattern.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePattern.java deleted file mode 100644 index 27c4f9d38..000000000 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePattern.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.refinedmods.refinedstorage.common.autocrafting; - -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; -import com.refinedmods.refinedstorage.api.autocrafting.Pattern; -import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; -import com.refinedmods.refinedstorage.common.support.resource.ItemResource; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -class SmithingTablePattern implements Pattern { - private final UUID id; - private final ItemResource template; - private final ItemResource base; - private final ItemResource addition; - private final List ingredients; - private final ItemResource output; - private final List outputs; - private final Set inputResources; - private final Set outputResources; - - SmithingTablePattern(final UUID id, - final ItemResource template, - final ItemResource base, - final ItemResource addition, - final ItemResource output) { - this.id = id; - this.template = template; - this.base = base; - this.addition = addition; - this.ingredients = List.of(single(template), single(base), single(addition)); - this.output = output; - this.outputs = List.of(new ResourceAmount(output, 1)); - this.inputResources = Set.of(template, base, addition); - this.outputResources = Set.of(output); - } - - private static Ingredient single(final ResourceKey input) { - return new Ingredient(1, List.of(input)); - } - - @Override - public Set getOutputResources() { - return outputResources; - } - - @Override - public List getIngredients() { - return ingredients; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public Set getInputResources() { - return inputResources; - } - - ItemResource getTemplate() { - return template; - } - - ItemResource getBase() { - return base; - } - - ItemResource getAddition() { - return addition; - } - - ItemResource getOutput() { - return output; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final SmithingTablePattern that = (SmithingTablePattern) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } -} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java index 3383aedcc..219122128 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java @@ -19,10 +19,10 @@ class SmithingTablePatternClientTooltipComponent implements ClientTooltipCompone private static final int ARROW_SPACING = 8; private final Component outputText; - private final SmithingTablePattern pattern; + private final PatternResolver.ResolvedSmithingTablePattern pattern; - SmithingTablePatternClientTooltipComponent(final SmithingTablePattern pattern) { - this.outputText = getOutputText(pattern.getOutput()); + SmithingTablePatternClientTooltipComponent(final PatternResolver.ResolvedSmithingTablePattern pattern) { + this.outputText = getOutputText(pattern.output()); this.pattern = pattern; } @@ -32,11 +32,11 @@ public void renderImage(final Font font, final int x, final int y, final GuiGrap final int slotsY = y + 9 + 2; graphics.blitSprite(Sprites.SLOT, x, slotsY, 18, 18); final ResourceRendering rendering = RefinedStorageClientApi.INSTANCE.getResourceRendering(ItemResource.class); - rendering.render(pattern.getTemplate(), graphics, x + 1, slotsY + 1); + rendering.render(pattern.template(), graphics, x + 1, slotsY + 1); graphics.blitSprite(Sprites.SLOT, x + 18, slotsY, 18, 18); - rendering.render(pattern.getBase(), graphics, x + 18 + 1, slotsY + 1); + rendering.render(pattern.base(), graphics, x + 18 + 1, slotsY + 1); graphics.blitSprite(Sprites.SLOT, x + 18 + 18, slotsY, 18, 18); - rendering.render(pattern.getAddition(), graphics, x + 18 + 18 + 1, slotsY + 1); + rendering.render(pattern.addition(), graphics, x + 18 + 18 + 1, slotsY + 1); graphics.blitSprite( LIGHT_ARROW, x + (18 * 3) + ARROW_SPACING, @@ -46,7 +46,7 @@ public void renderImage(final Font font, final int x, final int y, final GuiGrap ); final int lastSlotX = x + (18 * 3) + ARROW_SPACING + LIGHT_ARROW_WIDTH + ARROW_SPACING; graphics.blitSprite(Sprites.SLOT, lastSlotX, slotsY, 18, 18); - rendering.render(pattern.getOutput(), graphics, lastSlotX + 1, slotsY + 1); + rendering.render(pattern.output(), graphics, lastSlotX + 1, slotsY + 1); } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPattern.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPattern.java deleted file mode 100644 index 892ba1cda..000000000 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPattern.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.refinedmods.refinedstorage.common.autocrafting; - -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; -import com.refinedmods.refinedstorage.api.autocrafting.Pattern; -import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; -import com.refinedmods.refinedstorage.common.support.resource.ItemResource; - -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; - -class StonecutterPattern implements Pattern { - private final UUID id; - private final ItemResource input; - private final ItemResource output; - private final List ingredients; - private final List outputs; - private final Set inputResources; - private final Set outputResources; - - StonecutterPattern(final UUID id, final ItemResource input, final ItemResource output) { - this.id = id; - this.input = input; - this.output = output; - this.inputResources = Set.of(input); - this.outputResources = Set.of(output); - this.outputs = List.of(new ResourceAmount(output, 1)); - this.ingredients = List.of(new Ingredient(1, List.of(input))); - } - - @Override - public Set getOutputResources() { - return outputResources; - } - - @Override - public List getIngredients() { - return ingredients; - } - - @Override - public List getOutputs() { - return outputs; - } - - @Override - public Set getInputResources() { - return inputResources; - } - - ItemResource getInput() { - return input; - } - - ItemResource getOutput() { - return output; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final StonecutterPattern that = (StonecutterPattern) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } -} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java index 5a1c32daf..393814831 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java @@ -1,7 +1,6 @@ package com.refinedmods.refinedstorage.common.autocrafting; import com.refinedmods.refinedstorage.common.api.RefinedStorageClientApi; -import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; import com.refinedmods.refinedstorage.common.api.support.resource.ResourceRendering; import com.refinedmods.refinedstorage.common.support.resource.ItemResource; @@ -20,13 +19,13 @@ class StonecutterPatternClientTooltipComponent implements ClientTooltipComponent private static final int ARROW_SPACING = 8; private final Component outputText; - private final PlatformResourceKey input; - private final PlatformResourceKey output; + private final ItemResource input; + private final ItemResource output; - StonecutterPatternClientTooltipComponent(final StonecutterPattern pattern) { - this.outputText = getOutputText(pattern.getOutput()); - this.input = pattern.getInput(); - this.output = pattern.getOutput(); + StonecutterPatternClientTooltipComponent(final PatternResolver.ResolvedStonecutterPattern pattern) { + this.outputText = getOutputText(pattern.output()); + this.input = pattern.input(); + this.output = pattern.output(); } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/autocraftermanager/AutocrafterManagerContainerMenu.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/autocraftermanager/AutocrafterManagerContainerMenu.java index 9ce99fd5c..9a7f135d7 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/autocraftermanager/AutocrafterManagerContainerMenu.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/autocraftermanager/AutocrafterManagerContainerMenu.java @@ -1,5 +1,7 @@ package com.refinedmods.refinedstorage.common.autocrafting.autocraftermanager; +import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.Platform; import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; @@ -18,7 +20,6 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -import java.util.Set; import javax.annotation.Nullable; import it.unimi.dsi.fastutil.ints.IntIntPair; @@ -262,25 +263,34 @@ int getVisibleSlots() { boolean hasPatternInput(final Level level, final String normalizedQuery, final int index) { final ItemStack patternStack = backingInventory.getItem(index); return RefinedStorageApi.INSTANCE.getPattern(patternStack, level).map( - pattern -> hasResource(pattern.getInputResources(), normalizedQuery) + pattern -> hasIngredient(pattern.ingredients(), normalizedQuery) ).orElse(false); } boolean hasPatternOutput(final Level level, final String normalizedQuery, final int index) { final ItemStack patternStack = backingInventory.getItem(index); return RefinedStorageApi.INSTANCE.getPattern(patternStack, level).map( - pattern -> hasResource(pattern.getOutputResources(), normalizedQuery) + pattern -> hasResource(pattern.outputs(), normalizedQuery) ).orElse(false); } - private static boolean hasResource(final Set resources, final String normalizedQuery) { - return resources.stream().anyMatch(key -> - RefinedStorageClientApi.INSTANCE.getResourceRendering(key.getClass()) - .getDisplayName(key) - .getString() - .toLowerCase(Locale.ROOT) - .trim() - .contains(normalizedQuery)); + private static boolean hasIngredient(final List ingredients, final String normalizedQuery) { + return ingredients.stream().flatMap(i -> i.getAll().stream()).anyMatch(key -> + hasResource(normalizedQuery, key)); + } + + private static boolean hasResource(final List resources, final String normalizedQuery) { + return resources.stream().map(ResourceAmount::resource).anyMatch(key -> + hasResource(normalizedQuery, key)); + } + + private static boolean hasResource(final String normalizedQuery, final ResourceKey key) { + return RefinedStorageClientApi.INSTANCE.getResourceRendering(key.getClass()) + .getDisplayName(key) + .getString() + .toLowerCase(Locale.ROOT) + .trim() + .contains(normalizedQuery); } } diff --git a/refinedstorage-core-api/src/main/java/com/refinedmods/refinedstorage/api/core/CoreValidations.java b/refinedstorage-core-api/src/main/java/com/refinedmods/refinedstorage/api/core/CoreValidations.java index ac7b681df..411e1a27d 100644 --- a/refinedstorage-core-api/src/main/java/com/refinedmods/refinedstorage/api/core/CoreValidations.java +++ b/refinedstorage-core-api/src/main/java/com/refinedmods/refinedstorage/api/core/CoreValidations.java @@ -62,6 +62,12 @@ public static void validateEmpty(final Collection collection, final Strin } } + public static void validateNotEmpty(final Collection collection, final String message) { + if (collection.isEmpty()) { + throw new IllegalArgumentException(message); + } + } + public static void validateContains(final Collection collection, final T value, final String message) { if (!collection.contains(value)) { throw new IllegalArgumentException(message); diff --git a/refinedstorage-core-api/src/test/java/com/refinedmods/refinedstorage/api/core/CoreValidationsTest.java b/refinedstorage-core-api/src/test/java/com/refinedmods/refinedstorage/api/core/CoreValidationsTest.java index a1c3c3e94..2e90c6920 100644 --- a/refinedstorage-core-api/src/test/java/com/refinedmods/refinedstorage/api/core/CoreValidationsTest.java +++ b/refinedstorage-core-api/src/test/java/com/refinedmods/refinedstorage/api/core/CoreValidationsTest.java @@ -128,6 +128,19 @@ void shouldValidateLargerThanZero() { assertDoesNotThrow(() -> CoreValidations.validateLargerThanZero(2, "bla")); } + @Test + void shouldValidateNotEmpty() { + // Act & assert + final List badList = List.of(); + final Exception e = assertThrows( + IllegalArgumentException.class, + () -> CoreValidations.validateNotEmpty(badList, "bla") + ); + assertThat(e.getMessage()).isEqualTo("bla"); + + assertDoesNotThrow(() -> CoreValidations.validateNotEmpty(List.of(1), "bla")); + } + @Test void shouldValidateEmpty() { // Act & assert diff --git a/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayOutputPatternProvider.java b/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayOutputPatternProvider.java index 0501aed9e..9736b785c 100644 --- a/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayOutputPatternProvider.java +++ b/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayOutputPatternProvider.java @@ -5,6 +5,7 @@ import com.refinedmods.refinedstorage.api.network.autocrafting.ParentContainer; import com.refinedmods.refinedstorage.api.network.autocrafting.PatternListener; import com.refinedmods.refinedstorage.api.network.autocrafting.PatternProvider; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.api.resource.filter.Filter; import com.refinedmods.refinedstorage.api.resource.filter.FilterMode; @@ -65,7 +66,7 @@ private Set getPatterns() { } private boolean isPatternAllowed(final Pattern pattern) { - return pattern.getOutputResources().stream().anyMatch(filter::isAllowed); + return pattern.outputs().stream().map(ResourceAmount::resource).anyMatch(filter::isAllowed); } @Override diff --git a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java index 58b2470ca..0bda6c6e3 100644 --- a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java +++ b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java @@ -30,8 +30,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import static com.refinedmods.refinedstorage.api.autocrafting.PatternBuilder.pattern; import static com.refinedmods.refinedstorage.network.test.fixtures.ResourceFixtures.A; import static com.refinedmods.refinedstorage.network.test.fixtures.ResourceFixtures.B; +import static com.refinedmods.refinedstorage.network.test.fixtures.ResourceFixtures.C; import static org.assertj.core.api.Assertions.assertThat; class AutocraftingNetworkComponentImplTest { @@ -94,7 +96,7 @@ public void taskAdded(final TaskStatus status) { void shouldAddPatternsFromPatternProvider() { // Arrange final PatternProviderNetworkNode provider = new PatternProviderNetworkNode(0, 5); - provider.setPattern(1, new PatternImpl(A)); + provider.setPattern(1, pattern().output(A, 1).ingredient(C, 1).build()); final NetworkNodeContainer container = () -> provider; // Act @@ -108,7 +110,7 @@ void shouldAddPatternsFromPatternProvider() { void shouldRemovePatternsFromPatternProvider() { // Arrange final PatternProviderNetworkNode provider = new PatternProviderNetworkNode(0, 5); - provider.setPattern(1, new PatternImpl(A)); + provider.setPattern(1, pattern().output(A, 1).ingredient(C, 1).build()); final NetworkNodeContainer container = () -> provider; sut.onContainerAdded(container); @@ -132,9 +134,9 @@ void shouldGetPreview() throws ExecutionException, InterruptedException { rootStorage.insert(A, 10, Action.EXECUTE, Actor.EMPTY); final PatternProviderNetworkNode provider = new PatternProviderNetworkNode(0, 5); - provider.setPattern(1, new PatternImpl( + provider.setPattern(1, new Pattern( List.of(new Ingredient(3, List.of(A))), - new ResourceAmount(B, 1) + List.of(new ResourceAmount(B, 1)) )); final NetworkNodeContainer container = () -> provider; sut.onContainerAdded(container); @@ -159,9 +161,9 @@ void shouldGetMaxAmount() throws ExecutionException, InterruptedException { rootStorage.insert(A, 64, Action.EXECUTE, Actor.EMPTY); final PatternProviderNetworkNode provider = new PatternProviderNetworkNode(0, 5); - provider.setPattern(1, new PatternImpl( + provider.setPattern(1, new Pattern( List.of(new Ingredient(4, List.of(A))), - new ResourceAmount(B, 1) + List.of(new ResourceAmount(B, 1)) )); final NetworkNodeContainer container = () -> provider; sut.onContainerAdded(container); diff --git a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/PatternImpl.java b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/PatternImpl.java deleted file mode 100644 index 71a420dce..000000000 --- a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/PatternImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.refinedmods.refinedstorage.api.network.impl.autocrafting; - -import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; -import com.refinedmods.refinedstorage.api.autocrafting.Pattern; -import com.refinedmods.refinedstorage.api.resource.ResourceAmount; -import com.refinedmods.refinedstorage.api.resource.ResourceKey; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -public class PatternImpl implements Pattern { - private final List ingredients; - private final List outputs; - - public PatternImpl(final ResourceKey... outputs) { - this(List.of(), - Arrays.stream(outputs).map(output -> new ResourceAmount(output, 1)).toArray(ResourceAmount[]::new)); - } - - public PatternImpl(final List ingredients, final ResourceAmount... outputs) { - this.ingredients = ingredients; - this.outputs = Arrays.asList(outputs); - } - - @Override - public Set getInputResources() { - throw new UnsupportedOperationException(); - } - - @Override - public Set getOutputResources() { - return outputs.stream().map(ResourceAmount::resource).collect(Collectors.toSet()); - } - - @Override - public List getIngredients() { - return ingredients; - } - - @Override - public List getOutputs() { - return outputs; - } -} diff --git a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/patternprovider/PatternProviderNetworkNodeTest.java b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/patternprovider/PatternProviderNetworkNodeTest.java index 87ea5faa2..2bc055dbf 100644 --- a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/patternprovider/PatternProviderNetworkNodeTest.java +++ b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/patternprovider/PatternProviderNetworkNodeTest.java @@ -1,7 +1,7 @@ package com.refinedmods.refinedstorage.api.network.impl.node.patternprovider; +import com.refinedmods.refinedstorage.api.autocrafting.Pattern; import com.refinedmods.refinedstorage.api.network.autocrafting.AutocraftingNetworkComponent; -import com.refinedmods.refinedstorage.api.network.impl.autocrafting.PatternImpl; import com.refinedmods.refinedstorage.network.test.AddNetworkNode; import com.refinedmods.refinedstorage.network.test.InjectNetworkAutocraftingComponent; import com.refinedmods.refinedstorage.network.test.NetworkTest; @@ -11,13 +11,18 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static com.refinedmods.refinedstorage.api.autocrafting.PatternBuilder.pattern; import static com.refinedmods.refinedstorage.network.test.fixtures.ResourceFixtures.A; import static com.refinedmods.refinedstorage.network.test.fixtures.ResourceFixtures.B; +import static com.refinedmods.refinedstorage.network.test.fixtures.ResourceFixtures.C; import static org.assertj.core.api.Assertions.assertThat; @NetworkTest @SetupNetwork class PatternProviderNetworkNodeTest { + private static final Pattern PATTERN_A = pattern().output(A, 1).ingredient(C, 1).build(); + private static final Pattern PATTERN_B = pattern().output(B, 1).ingredient(C, 1).build(); + @AddNetworkNode(properties = { @AddNetworkNode.Property(key = PatternProviderNetworkNodeFactory.PROPERTY_SIZE, intValue = 3) }) @@ -36,8 +41,7 @@ void shouldSetPatternAndNotifyNetwork( @InjectNetworkAutocraftingComponent final AutocraftingNetworkComponent autocrafting ) { // Act - final PatternImpl pattern = new PatternImpl(A); - sut.setPattern(0, pattern); + sut.setPattern(0, PATTERN_A); // Assert assertThat(autocrafting.getOutputs()).containsExactly(A); @@ -48,8 +52,7 @@ void shouldRemovePatternAndNotifyNetwork( @InjectNetworkAutocraftingComponent final AutocraftingNetworkComponent autocrafting ) { // Arrange - final PatternImpl pattern = new PatternImpl(A); - sut.setPattern(0, pattern); + sut.setPattern(0, PATTERN_A); // Act sut.setPattern(0, null); @@ -63,12 +66,10 @@ void shouldReplacePatternAndNotifyNetwork( @InjectNetworkAutocraftingComponent final AutocraftingNetworkComponent autocrafting ) { // Arrange - final PatternImpl pattern = new PatternImpl(A); - sut.setPattern(0, pattern); + sut.setPattern(0, PATTERN_A); // Act - final PatternImpl replacedPattern = new PatternImpl(B); - sut.setPattern(0, replacedPattern); + sut.setPattern(0, PATTERN_B); // Assert assertThat(autocrafting.getOutputs()).containsExactly(B); @@ -79,8 +80,7 @@ void shouldRemovePatternsFromNetworkWhenInactive( @InjectNetworkAutocraftingComponent final AutocraftingNetworkComponent autocrafting ) { // Arrange - final PatternImpl pattern = new PatternImpl(A); - sut.setPattern(0, pattern); + sut.setPattern(0, PATTERN_A); // Act sut.setActive(false); @@ -94,8 +94,7 @@ void shouldAddPatternsFromNetworkWhenActive( @InjectNetworkAutocraftingComponent final AutocraftingNetworkComponent autocrafting ) { // Arrange - final PatternImpl pattern = new PatternImpl(A); - sut.setPattern(0, pattern); + sut.setPattern(0, PATTERN_A); sut.setActive(false); // Act @@ -121,10 +120,10 @@ void shouldSetPatternsRespectingPriority( sut.setPriority(0); // Act - final PatternImpl patternWithLowestPriority = new PatternImpl(A); + final Pattern patternWithLowestPriority = pattern().output(A, 1).ingredient(C, 1).build(); sut.setPattern(0, patternWithLowestPriority); - final PatternImpl patternWithHighestPriority = new PatternImpl(A); + final Pattern patternWithHighestPriority = pattern().output(A, 1).ingredient(C, 1).build(); other.setPattern(0, patternWithHighestPriority); // Assert @@ -141,10 +140,10 @@ void shouldRemovePatternsRespectingPriorityWhenInactive( other.setPriority(1); sut.setPriority(0); - final PatternImpl patternWithLowestPriority = new PatternImpl(A); + final Pattern patternWithLowestPriority = pattern().output(A, 1).ingredient(C, 1).build(); sut.setPattern(0, patternWithLowestPriority); - final PatternImpl patternWithHighestPriority = new PatternImpl(A); + final Pattern patternWithHighestPriority = pattern().output(A, 1).ingredient(C, 1).build(); other.setPattern(0, patternWithHighestPriority); // Act @@ -163,10 +162,10 @@ void shouldAddPatternsRespectingPriorityWhenActive( other.setPriority(1); sut.setPriority(0); - final PatternImpl patternWithLowestPriority = new PatternImpl(A); + final Pattern patternWithLowestPriority = pattern().output(A, 1).ingredient(C, 1).build(); sut.setPattern(0, patternWithLowestPriority); - final PatternImpl patternWithHighestPriority = new PatternImpl(A); + final Pattern patternWithHighestPriority = pattern().output(A, 1).ingredient(C, 1).build(); other.setPattern(0, patternWithHighestPriority); sut.setActive(false); @@ -190,10 +189,10 @@ void shouldModifyPriorityAfterAddingPatterns( other.setPriority(1); sut.setPriority(0); - final PatternImpl patternWithLowestPriority = new PatternImpl(A); + final Pattern patternWithLowestPriority = pattern().output(A, 1).ingredient(C, 1).build(); sut.setPattern(0, patternWithLowestPriority); - final PatternImpl patternWithHighestPriority = new PatternImpl(A); + final Pattern patternWithHighestPriority = pattern().output(A, 1).ingredient(C, 1).build(); other.setPattern(0, patternWithHighestPriority); // Act diff --git a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayNetworkNodeTest.java b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayNetworkNodeTest.java index 50c2b5f6b..8036f9f46 100644 --- a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayNetworkNodeTest.java +++ b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/node/relay/RelayNetworkNodeTest.java @@ -1,11 +1,11 @@ package com.refinedmods.refinedstorage.api.network.impl.node.relay; +import com.refinedmods.refinedstorage.api.autocrafting.Ingredient; import com.refinedmods.refinedstorage.api.autocrafting.Pattern; import com.refinedmods.refinedstorage.api.core.Action; import com.refinedmods.refinedstorage.api.network.Network; import com.refinedmods.refinedstorage.api.network.autocrafting.AutocraftingNetworkComponent; import com.refinedmods.refinedstorage.api.network.energy.EnergyNetworkComponent; -import com.refinedmods.refinedstorage.api.network.impl.autocrafting.PatternImpl; import com.refinedmods.refinedstorage.api.network.impl.node.patternprovider.PatternProviderNetworkNode; import com.refinedmods.refinedstorage.api.network.impl.security.SecurityDecisionProviderImpl; import com.refinedmods.refinedstorage.api.network.node.container.NetworkNodeContainer; @@ -28,6 +28,7 @@ import com.refinedmods.refinedstorage.network.test.fixtures.PermissionFixtures; import com.refinedmods.refinedstorage.network.test.fixtures.SecurityActorFixtures; +import java.util.List; import java.util.Set; import java.util.stream.Stream; @@ -343,7 +344,9 @@ void shouldResetComponentsIfNetworkIsChanged( new ResourceAmount(C, 1) ); assertThat(outputAutocrafting.getOutputs()).containsExactly(B); - assertThat(outputAutocrafting.getPatterns()).allMatch(p -> p.getOutputResources().contains(B)); + assertThat(outputAutocrafting.getPatterns()).allMatch(p -> p.outputs() + .stream() + .anyMatch(patternOutput -> patternOutput.resource().equals(B))); assertThat(inputAlternativeStorage.getAll()).usingRecursiveFieldByFieldElementComparator() .containsExactlyInAnyOrder(new ResourceAmount(A, 32), new ResourceAmount(C, 1)); assertThat(inputStorage.getAll()).usingRecursiveFieldByFieldElementComparator() @@ -392,7 +395,9 @@ void shouldResetComponentsWhenComponentTypeIsEnabled( assertThat(outputStorage.insert(A, 1, Action.EXECUTE, Actor.EMPTY)).isEqualTo(1); assertThat(outputStorage.extract(A, 1, Action.EXECUTE, Actor.EMPTY)).isEqualTo(1); assertThat(outputAutocrafting.getOutputs()).containsExactly(A); - assertThat(outputAutocrafting.getPatterns()).allMatch(p -> p.getOutputResources().contains(A)); + assertThat(outputAutocrafting.getPatterns()).allMatch(p -> p.outputs() + .stream() + .anyMatch(patternOutput -> patternOutput.resource().equals(A))); assertThat(output.getEnergyUsage()).isEqualTo(OUTPUT_ENERGY_USAGE); } @@ -435,7 +440,9 @@ void shouldResetComponentsWhenComponentTypeIsDisabled( assertThat(outputStorage.insert(A, 1, Action.EXECUTE, Actor.EMPTY)).isEqualTo(1); assertThat(outputStorage.extract(A, 1, Action.EXECUTE, Actor.EMPTY)).isEqualTo(1); assertThat(outputAutocrafting.getOutputs()).containsExactly(A); - assertThat(outputAutocrafting.getPatterns()).allMatch(p -> p.getOutputResources().contains(A)); + assertThat(outputAutocrafting.getPatterns()).allMatch(p -> p.outputs() + .stream() + .anyMatch(patternOutput -> patternOutput.resource().equals(A))); assertThat(output.getEnergyUsage()).isEqualTo(OUTPUT_ENERGY_USAGE); } @@ -469,7 +476,10 @@ static void addStorageSource(final StorageNetworkComponent storage) { } static Runnable addPattern(final AutocraftingNetworkComponent component, final ResourceKey output) { - final Pattern pattern = new PatternImpl(output); + final Pattern pattern = new Pattern( + List.of(new Ingredient(1, List.of(C))), + List.of(new ResourceAmount(output, 1)) + ); final PatternProviderNetworkNode patternProvider = new PatternProviderNetworkNode(0, 1); patternProvider.setPattern(0, pattern); final NetworkNodeContainer container = () -> patternProvider;