mirror of
https://github.com/GTNewHorizons/Applied-Energistics-2-Unofficial.git
synced 2026-10-25 20:22:23 +00:00
Make sure during fuzzy crafting we can fulfill pattern (#1253)
Co-authored-by: Martin Robertz <dream-master@gmx.net> Co-authored-by: Kogepan229 <kogepan25629@gmail.com>
This commit is contained in:
5 files changed
+134
-25
No files matched your search
+8
-8
@@ -2,7 +2,7 @@
|
||||
|
||||
dependencies {
|
||||
implementation('com.github.GTNewHorizons:NotEnoughItems:2.8.98-GTNH:dev')
|
||||
implementation("com.github.GTNewHorizons:GTNHLib:0.10.0:dev")
|
||||
implementation("com.github.GTNewHorizons:GTNHLib:0.10.2:dev")
|
||||
implementation('curse.maven:cofh-core-69162:2388751')
|
||||
|
||||
compileOnlyApi('com.github.GTNewHorizons:Angelica:2.1.25:dev')
|
||||
@@ -12,7 +12,7 @@ dependencies {
|
||||
compileOnly('com.github.GTNewHorizons:BuildCraft:7.1.60:dev') {transitive = false}
|
||||
compileOnly('com.github.GTNewHorizons:ForestryMC:4.11.23:dev') {transitive = false} // required to compile CraftingV2Tests.java now
|
||||
compileOnly('com.github.GTNewHorizons:ForgeMultipart:1.7.10:dev') {transitive = false}
|
||||
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.527:dev') {transitive = false}
|
||||
compileOnly('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.532:dev') {transitive = false}
|
||||
compileOnly('com.github.GTNewHorizons:ModularUI2:2.3.65-1.7.10:dev') {transitive = false}
|
||||
compileOnly('com.github.GTNewHorizons:Jabba:1.5.20:dev') {transitive = false}
|
||||
compileOnly('com.github.GTNewHorizons:inventory-tweaks:1.7.1:api') {transitive = false}
|
||||
@@ -27,11 +27,11 @@ dependencies {
|
||||
compileOnly('curse.maven:better-storage-232919:2731636')
|
||||
compileOnly('api:immibis:1')
|
||||
compileOnly('curse.maven:computercraft-67504:2269339')
|
||||
compileOnly('com.github.GTNewHorizons:EnderIO:5.2.62:dev') { transitive = false }
|
||||
compileOnly('com.github.GTNewHorizons:EnderIO:2.10.27:dev') { transitive = false }
|
||||
compileOnly(rfg.deobf('curse.maven:mekanism-268560:2475797')) // https://www.curseforge.com/minecraft/mc-mods/mekanism/files/2475797
|
||||
compileOnly(rfg.deobf('maven.modrinth:immibis-microblocks:59.1.2')) // https://modrinth.com/mod/immibis-microblocks/version/59.1.2
|
||||
compileOnly("curse.maven:endlessids-665730:7585931") {transitive = false }
|
||||
compileOnly('com.github.GTNewHorizons:AE2FluidCraft-Rework:1.5.84-gtnh:dev') { transitive = false }
|
||||
compileOnly('com.github.GTNewHorizons:AE2FluidCraft-Rework:1.5.85-gtnh:dev') { transitive = false }
|
||||
compileOnly('com.github.GTNewHorizons:ae2stuff:0.10.19-GTNH:dev') {
|
||||
exclude module: "Applied-Energistics-2-Unofficial"
|
||||
}
|
||||
@@ -48,7 +48,7 @@ dependencies {
|
||||
//runtimeOnlyNonPublishable('curse.maven:thermal-expansion-69163:2388759')
|
||||
|
||||
//Uncomment to test with GT5 machines
|
||||
//runtimeOnlyNonPublishable('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.527:dev') {transitive = false}
|
||||
//runtimeOnlyNonPublishable('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.532:dev') {transitive = false}
|
||||
//runtimeOnlyNonPublishable('com.github.GTNewHorizons:StructureLib:1.4.34:dev') {transitive = false}
|
||||
//runtimeOnlyNonPublishable('com.github.GTNewHorizons:ModularUI:1.3.4:dev') {transitive = false}
|
||||
//runtimeOnlyNonPublishable('com.github.GTNewHorizons:ModularUI2:2.3.65-1.7.10:dev') {transitive = false}
|
||||
@@ -68,7 +68,7 @@ dependencies {
|
||||
functionalTestImplementation('org.junit.platform:junit-platform-engine')
|
||||
functionalTestImplementation('org.junit.platform:junit-platform-launcher')
|
||||
functionalTestImplementation('org.junit.platform:junit-platform-reporting')
|
||||
functionalTestImplementation('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.527:dev') {
|
||||
functionalTestImplementation('com.github.GTNewHorizons:GT5-Unofficial:5.09.52.532:dev') {
|
||||
exclude module: "Applied-Energistics-2-Unofficial"
|
||||
exclude module: "Hodgepodge"
|
||||
exclude module: "waila"
|
||||
@@ -81,8 +81,8 @@ dependencies {
|
||||
runtimeOnlyNonPublishable('thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev') {
|
||||
exclude module: "Baubles"
|
||||
}
|
||||
runtimeOnlyNonPublishable('com.github.GTNewHorizons:ThaumicEnergistics:1.7.50-GTNH:dev') { transitive = false }
|
||||
runtimeOnlyNonPublishable('com.github.GTNewHorizons:AE2FluidCraft-Rework:1.5.84-gtnh:dev') { transitive = false }
|
||||
runtimeOnlyNonPublishable('com.github.GTNewHorizons:ThaumicEnergistics:1.7.51-GTNH:dev') { transitive = false }
|
||||
runtimeOnlyNonPublishable('com.github.GTNewHorizons:AE2FluidCraft-Rework:1.5.85-gtnh:dev') { transitive = false }
|
||||
runtimeOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughEnergistics:1.7.29:dev') {
|
||||
exclude module: "Applied-Energistics-2-Unofficial"
|
||||
exclude module: "waila"
|
||||
|
||||
@@ -221,6 +221,23 @@ public class CraftingV2Tests {
|
||||
.addOutput(new ItemStack(Blocks.chest, 1)).buildAndAdd();
|
||||
}
|
||||
|
||||
private void addFuzzyProcessingChestPattern(MockAESystem aeSystem) {
|
||||
aeSystem.newProcessingPattern().allowUsingSubstitutes().addInput(new ItemStack(Blocks.planks, 8, 0))
|
||||
.addOutput(new ItemStack(Blocks.chest, 1)).buildAndAdd();
|
||||
}
|
||||
|
||||
private void addFuzzyBedPattern(MockAESystem aeSystem) {
|
||||
aeSystem.newCraftingPattern().allowUsingSubstitutes()
|
||||
// row 1
|
||||
.addInput(new ItemStack(Blocks.wool, 1, 0)).addInput(new ItemStack(Blocks.wool, 1, 0))
|
||||
.addInput(new ItemStack(Blocks.wool, 1, 0))
|
||||
// row 2
|
||||
.addInput(new ItemStack(Blocks.planks, 1, 0)).addInput(new ItemStack(Blocks.planks, 1, 0))
|
||||
.addInput(new ItemStack(Blocks.planks, 1, 0))
|
||||
// end
|
||||
.addOutput(new ItemStack(Items.bed, 1)).buildAndAdd();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(ints = { 0, 1 })
|
||||
void craftChestFromLogs(int woodMetadata) {
|
||||
@@ -265,6 +282,70 @@ public class CraftingV2Tests {
|
||||
AEItemStack.create(new ItemStack(Blocks.chest, 0)).setCountRequestable(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void craftingPatternFuzzyCanUseMixedSubstitutes() {
|
||||
MockAESystem aeSystem = new MockAESystem(dummyWorld);
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.wool, 1, 0));
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.wool, 2, 1));
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.planks, 3, 0));
|
||||
aeSystem.addStoredItem(new ItemStack(Items.gold_ingot, 64));
|
||||
addFuzzyBedPattern(aeSystem);
|
||||
// Another pattern that shouldn't match
|
||||
addDummyGappleRecipe(aeSystem);
|
||||
final CraftingJobV2 job = aeSystem.makeCraftingJob(new ItemStack(Items.bed, 1));
|
||||
simulateJobAndCheck(job, SIMPLE_SIMULATION_TIMEOUT_MS);
|
||||
assertFalse(job.isSimulation());
|
||||
assertEquals(job.getOutput(), AEItemStack.create(new ItemStack(Items.bed, 1)));
|
||||
assertJobPlanEquals(
|
||||
job,
|
||||
AEItemStack.create(new ItemStack(Blocks.wool, 1, 0)),
|
||||
AEItemStack.create(new ItemStack(Blocks.wool, 2, 1)),
|
||||
AEItemStack.create(new ItemStack(Blocks.planks, 3, 0)),
|
||||
AEItemStack.create(new ItemStack(Items.bed, 0)).setCountRequestable(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void processingPatternFuzzySubstitutesCompleteInputGroupsOnly() {
|
||||
MockAESystem aeSystem = new MockAESystem(dummyWorld);
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.planks, 12, 0));
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.planks, 20, 1));
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.planks, 8, 2));
|
||||
aeSystem.addStoredItem(new ItemStack(Items.gold_ingot, 64));
|
||||
addFuzzyProcessingChestPattern(aeSystem);
|
||||
// Another pattern that shouldn't match
|
||||
addDummyGappleRecipe(aeSystem);
|
||||
final CraftingJobV2 job = aeSystem.makeCraftingJob(new ItemStack(Blocks.chest, 4));
|
||||
simulateJobAndCheck(job, SIMPLE_SIMULATION_TIMEOUT_MS);
|
||||
assertFalse(job.isSimulation());
|
||||
assertEquals(job.getOutput(), AEItemStack.create(new ItemStack(Blocks.chest, 4)));
|
||||
assertJobPlanEquals(
|
||||
job,
|
||||
AEItemStack.create(new ItemStack(Blocks.planks, 8, 0)),
|
||||
AEItemStack.create(new ItemStack(Blocks.planks, 16, 1)),
|
||||
AEItemStack.create(new ItemStack(Blocks.planks, 8, 2)),
|
||||
AEItemStack.create(new ItemStack(Blocks.chest, 0)).setCountRequestable(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
void processingPatternFuzzyDoesNotTreatPartialGroupsAsCraftable() {
|
||||
MockAESystem aeSystem = new MockAESystem(dummyWorld);
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.planks, 12, 0));
|
||||
aeSystem.addStoredItem(new ItemStack(Blocks.planks, 20, 1));
|
||||
aeSystem.addStoredItem(new ItemStack(Items.gold_ingot, 64));
|
||||
addFuzzyProcessingChestPattern(aeSystem);
|
||||
// Another pattern that shouldn't match
|
||||
addDummyGappleRecipe(aeSystem);
|
||||
final CraftingJobV2 job = aeSystem.makeCraftingJob(new ItemStack(Blocks.chest, 4));
|
||||
simulateJobAndCheck(job, SIMPLE_SIMULATION_TIMEOUT_MS);
|
||||
assertTrue(job.isSimulation());
|
||||
assertEquals(job.getOutput(), AEItemStack.create(new ItemStack(Blocks.chest, 4)));
|
||||
assertJobPlanEquals(
|
||||
job,
|
||||
AEItemStack.create(new ItemStack(Blocks.planks, 16, 0)),
|
||||
AEItemStack.create(new ItemStack(Blocks.planks, 16, 1)),
|
||||
AEItemStack.create(new ItemStack(Blocks.chest, 0)).setCountRequestable(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
void canHandleCyclicalPatterns() {
|
||||
MockAESystem aeSystem = new MockAESystem(dummyWorld);
|
||||
|
||||
@@ -84,6 +84,7 @@ public class CraftingRequest implements ITreeSerializable {
|
||||
|
||||
public final SubstitutionMode substitutionMode;
|
||||
public final Predicate<IAEStack<?>> acceptableSubstituteFn;
|
||||
public final long substitutionGroupSize;
|
||||
// (task, amount fulfilled by task)
|
||||
|
||||
public final CraftingMode craftingMode;
|
||||
@@ -124,6 +125,7 @@ public class CraftingRequest implements ITreeSerializable {
|
||||
buffer.writeBoolean(wasSimulated);
|
||||
buffer.writeBoolean(incomplete);
|
||||
buffer.writeInt(craftingMode.ordinal());
|
||||
buffer.writeLong(substitutionGroupSize);
|
||||
return usedResolvers;
|
||||
}
|
||||
|
||||
@@ -151,6 +153,7 @@ public class CraftingRequest implements ITreeSerializable {
|
||||
if (index < 0 || index >= CraftingMode.values().length || CraftingMode.values()[index] == CraftingMode.STANDARD)
|
||||
craftingMode = CraftingMode.STANDARD;
|
||||
else craftingMode = CraftingMode.IGNORE_MISSING;
|
||||
substitutionGroupSize = buffer.readLong();
|
||||
acceptableSubstituteFn = x -> true;
|
||||
}
|
||||
|
||||
@@ -162,6 +165,19 @@ public class CraftingRequest implements ITreeSerializable {
|
||||
*/
|
||||
public CraftingRequest(CraftingRequest parentRequest, @Nonnull IAEStack<?> stack, SubstitutionMode substitutionMode,
|
||||
boolean allowSimulation, CraftingMode craftingMode, Predicate<IAEStack<?>> acceptableSubstituteFn) {
|
||||
this(parentRequest, stack, substitutionMode, allowSimulation, craftingMode, acceptableSubstituteFn, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parentRequest From which this crafting request is initiated. null if it's the root
|
||||
* @param stack The item/fluid and stack to request
|
||||
* @param substitutionMode Whether and how to allow substitutions when resolving this request
|
||||
* @param acceptableSubstituteFn A predicate testing if a given item (in fuzzy mode) can fulfill the request
|
||||
* @param substitutionGroupSize The amount that must be fulfilled by a single substitute stack in fuzzy mode
|
||||
*/
|
||||
public CraftingRequest(CraftingRequest parentRequest, @Nonnull IAEStack<?> stack, SubstitutionMode substitutionMode,
|
||||
boolean allowSimulation, CraftingMode craftingMode, Predicate<IAEStack<?>> acceptableSubstituteFn,
|
||||
long substitutionGroupSize) {
|
||||
this.parentRequest = parentRequest;
|
||||
if (parentRequest == null) {
|
||||
this.parentRequests = Collections.emptySet();
|
||||
@@ -174,6 +190,7 @@ public class CraftingRequest implements ITreeSerializable {
|
||||
this.stack = stack;
|
||||
this.substitutionMode = substitutionMode;
|
||||
this.acceptableSubstituteFn = acceptableSubstituteFn;
|
||||
this.substitutionGroupSize = Math.max(1, substitutionGroupSize);
|
||||
this.remainingToProcess = stack.getStackSize();
|
||||
this.allowSimulation = allowSimulation;
|
||||
this.craftingMode = craftingMode;
|
||||
|
||||
@@ -446,7 +446,8 @@ public class CraftableItemResolver implements CraftingRequestResolver {
|
||||
childMode,
|
||||
allowSimulation,
|
||||
request.craftingMode,
|
||||
stack -> this.isValidSubstitute(input, stack, context.world, finalSlot));
|
||||
stack -> this.isValidSubstitute(input, stack, context.world, finalSlot),
|
||||
1);
|
||||
complexRequestPerSlot.add(req);
|
||||
newChildren.add(req);
|
||||
childRequests.add(new RequestAndPerCraftAmount(req, input.getStackSize()));
|
||||
@@ -472,7 +473,8 @@ public class CraftableItemResolver implements CraftingRequestResolver {
|
||||
childMode,
|
||||
allowSimulation,
|
||||
request.craftingMode,
|
||||
stack -> this.isValidSubstitute(recInput, stack, context.world));
|
||||
stack -> this.isValidSubstitute(recInput, stack, context.world),
|
||||
pattern.isCraftable() ? 1 : recInput.getStackSize());
|
||||
newChildren.add(req);
|
||||
childRecursionRequests.put(recInput, req);
|
||||
}
|
||||
@@ -500,7 +502,8 @@ public class CraftableItemResolver implements CraftingRequestResolver {
|
||||
childMode,
|
||||
allowSimulation,
|
||||
request.craftingMode,
|
||||
stack -> this.isValidSubstitute(input, stack, context.world));
|
||||
stack -> this.isValidSubstitute(input, stack, context.world),
|
||||
pattern.isCraftable() ? 1 : input.getStackSize());
|
||||
newChildren.add(req);
|
||||
childRequests.add(new RequestAndPerCraftAmount(req, input.getStackSize()));
|
||||
}
|
||||
|
||||
@@ -54,16 +54,16 @@ public class ExtractItemResolver implements CraftingRequestResolver {
|
||||
|
||||
@Override
|
||||
public StepOutput calculateOneStep(CraftingContext context) {
|
||||
final boolean isFuzzy = request.substitutionMode == CraftingRequest.SubstitutionMode.ACCEPT_FUZZY;
|
||||
state = State.SUCCESS;
|
||||
if (request.remainingToProcess <= 0) {
|
||||
return new StepOutput(Collections.emptyList());
|
||||
}
|
||||
extractExact(context, context.byproductsInventory, removedFromByproducts);
|
||||
extractExact(context, context.byproductsInventory, removedFromByproducts, isFuzzy);
|
||||
if (request.remainingToProcess > 0) {
|
||||
extractExact(context, context.itemModel, removedFromSystem);
|
||||
extractExact(context, context.itemModel, removedFromSystem, isFuzzy);
|
||||
}
|
||||
if (request.remainingToProcess > 0
|
||||
&& request.substitutionMode == CraftingRequest.SubstitutionMode.ACCEPT_FUZZY) {
|
||||
if (request.remainingToProcess > 0 && isFuzzy) {
|
||||
extractFuzzy(context, context.byproductsInventory, removedFromByproducts);
|
||||
if (request.remainingToProcess > 0) {
|
||||
extractFuzzy(context, context.itemModel, removedFromSystem);
|
||||
@@ -74,10 +74,12 @@ public class ExtractItemResolver implements CraftingRequestResolver {
|
||||
return new StepOutput(Collections.emptyList());
|
||||
}
|
||||
|
||||
private void extractExact(CraftingContext context, MECraftingInventory source, List<IAEStack<?>> removedList) {
|
||||
private void extractExact(CraftingContext context, MECraftingInventory source, List<IAEStack<?>> removedList,
|
||||
boolean isFuzzy) {
|
||||
StackType exactMatching = source.extractItems((StackType) request.stack, Actionable.SIMULATE);
|
||||
if (exactMatching != null) {
|
||||
final long requestSize = Math.min(request.remainingToProcess, exactMatching.getStackSize());
|
||||
if (exactMatching != null && exactMatching.getStackSize() > 0) {
|
||||
final long requestSize = this.getRequestSize(exactMatching.getStackSize(), isFuzzy);
|
||||
if (requestSize <= 0) return;
|
||||
final StackType extracted = source
|
||||
.extractItems(exactMatching.copy().setStackSize(requestSize), Actionable.MODULATE);
|
||||
if (extracted != null && extracted.getStackSize() > 0) {
|
||||
@@ -91,16 +93,13 @@ public class ExtractItemResolver implements CraftingRequestResolver {
|
||||
private void extractFuzzy(CraftingContext context, MECraftingInventory source, List<IAEStack<?>> removedList) {
|
||||
Collection<StackType> fuzzyMatching = source.findFuzzy((StackType) request.stack, FuzzyMode.IGNORE_ALL);
|
||||
for (final StackType candidate : fuzzyMatching) {
|
||||
if (candidate == null) {
|
||||
continue;
|
||||
}
|
||||
if (candidate == null || candidate.getStackSize() <= 0) continue;
|
||||
if (request.acceptableSubstituteFn.test(candidate)) {
|
||||
final long requestSize = Math.min(request.remainingToProcess, candidate.getStackSize());
|
||||
final long requestSize = this.getRequestSize(candidate.getStackSize(), true);
|
||||
if (requestSize <= 0) continue;
|
||||
final StackType extracted = source
|
||||
.extractItems(candidate.copy().setStackSize(requestSize), Actionable.MODULATE);
|
||||
if (extracted == null || extracted.getStackSize() <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (extracted == null || extracted.getStackSize() <= 0) continue;
|
||||
extracted.setCraftable(false);
|
||||
request.fulfill(this, extracted, context);
|
||||
removedList.add(extracted.copy());
|
||||
@@ -108,6 +107,15 @@ public class ExtractItemResolver implements CraftingRequestResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private long getRequestSize(final long available, final boolean isFuzzy) {
|
||||
final long upperBound = Math.min(request.remainingToProcess, available);
|
||||
if (!isFuzzy) return upperBound;
|
||||
// Fuzzy substitutions must not mix candidates inside one pattern input group. Extract as many complete
|
||||
// groups as this candidate can cover, but ignore any remainder smaller than the group.
|
||||
final long groupSize = request.substitutionGroupSize;
|
||||
return upperBound / groupSize * groupSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long partialRefund(CraftingContext context, long amount) {
|
||||
final long originalAmount = amount;
|
||||
|
||||
Reference in new issue
Block a user