Skip to content

Commit a1ff393

Browse files
committed
feat: improve recipe test system
set default tick time to 1 test all 'ingredients' separately
1 parent f60c235 commit a1ff393

File tree

10 files changed

+320
-137
lines changed

10 files changed

+320
-137
lines changed

build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ val isCI = System.getenv().getOrDefault("CI", "false") == "true";
4646
plugins {
4747
java
4848
`maven-publish`
49-
id("fabric-loom") version("1.5-SNAPSHOT")
49+
id("fabric-loom") version("1.6-SNAPSHOT")
5050
id("org.cadixdev.licenser") version("0.6.1")
5151
id("org.ajoberstar.grgit") version("5.2.1")
52-
id("dev.galacticraft.mojarn") version("0.1.1")
52+
id("dev.galacticraft.mojarn") version("0.1.2")
5353
}
5454

5555
group = "dev.galacticraft"

gradle/wrapper/gradle-wrapper.jar

-9 Bytes
Binary file not shown.

gradle/wrapper/gradle-wrapper.properties

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
4-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
3+
distributionSha256Sum=544c35d6bd849ae8a5ed0bcea39ba677dc40f49df7d1835561582da2009b961d
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
55
networkTimeout=10000
66
validateDistributionUrl=true
77
zipStoreBase=GRADLE_USER_HOME

src/main/java/dev/galacticraft/machinelib/api/gametest/MachineGameTest.java

+53-10
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,16 @@
2626
import dev.galacticraft.machinelib.api.gametest.annotation.BasicTest;
2727
import dev.galacticraft.machinelib.api.gametest.annotation.MachineTest;
2828
import dev.galacticraft.machinelib.api.machine.MachineType;
29+
import dev.galacticraft.machinelib.impl.gametest.GameTestUtils;
30+
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants;
2931
import net.minecraft.core.BlockPos;
3032
import net.minecraft.gametest.framework.GameTestAssertException;
3133
import net.minecraft.gametest.framework.GameTestGenerator;
3234
import net.minecraft.gametest.framework.GameTestHelper;
3335
import net.minecraft.gametest.framework.TestFunction;
3436
import net.minecraft.world.item.Item;
37+
import net.minecraft.world.item.Items;
38+
import net.minecraft.world.level.material.Fluid;
3539
import org.jetbrains.annotations.MustBeInvokedByOverriders;
3640
import org.jetbrains.annotations.NotNull;
3741

@@ -72,12 +76,20 @@ protected MachineGameTest(MachineType<Machine, ?> type) {
7276
tests.add(this.createTest(machineTest.batch(), machineTest.group(), method.getName(), machineTest.structure(), machineTest.workTime(), machineTest.setupTime(), helper -> {
7377
Machine machine = this.createMachine(helper);
7478

75-
Runnable runnable = this.invokeTestMethod(method, machine, helper);
76-
if (runnable != null) {
77-
helper.runAfterDelay(machineTest.workTime(), () -> {
78-
runnable.run();
79-
helper.succeed();
80-
});
79+
try {
80+
Runnable runnable = GameTestUtils.invokeUnorderedArguments(this, method, machine, helper, new MachineTestContext(MACHINE_POS, helper));
81+
if (runnable != null) {
82+
helper.runAfterDelay(machineTest.workTime(), () -> {
83+
try {
84+
runnable.run();
85+
helper.succeed();
86+
} catch (AssertionError e) {
87+
GameTestUtils.unwrapAssertions(helper, MACHINE_POS, e, machineTest.captureAssertions());
88+
}
89+
});
90+
}
91+
} catch (AssertionError e) {
92+
GameTestUtils.unwrapAssertions(helper, MACHINE_POS, e, machineTest.captureAssertions());
8193
}
8294
}));
8395
}
@@ -86,10 +98,10 @@ protected MachineGameTest(MachineType<Machine, ?> type) {
8698
return tests;
8799
}
88100

89-
public TestFunction createChargeFromEnergyItemTest(int slot, Item infiniteBattery) {
101+
public TestFunction createChargeFromEnergyItemTest(int slot, Item energyProvider) {
90102
return this.createTest("chargeFromItem", STRUCTURE_3x3, 2, 1, helper -> {
91103
Machine machine = this.createMachine(helper);
92-
machine.itemStorage().getSlot(slot).set(infiniteBattery, 1);
104+
machine.itemStorage().getSlot(slot).set(energyProvider, 1);
93105
helper.runAfterDelay(1, () -> {
94106
if (machine.energyStorage().isEmpty()) {
95107
helper.fail("Machine did not charge from the stack!", machine.getBlockPos());
@@ -100,12 +112,12 @@ public TestFunction createChargeFromEnergyItemTest(int slot, Item infiniteBatter
100112
});
101113
}
102114

103-
public TestFunction createDrainToEnergyItemTest(int slot, Item battery) {
115+
public TestFunction createDrainToEnergyItemTest(int slot, Item energyConsumer) {
104116
return this.createTest("drainToItem", STRUCTURE_3x3, 2, 1, helper -> {
105117
Machine machine = this.createMachine(helper);
106118

107119
machine.energyStorage().setEnergy(machine.energyStorage().getCapacity());
108-
machine.itemStorage().getSlot(slot).set(battery, 1);
120+
machine.itemStorage().getSlot(slot).set(energyConsumer, 1);
109121

110122
helper.runAfterDelay(1, () -> {
111123
if (machine.energyStorage().isFull()) {
@@ -117,6 +129,37 @@ public TestFunction createDrainToEnergyItemTest(int slot, Item battery) {
117129
});
118130
}
119131

132+
public TestFunction createTakeFromFluidItemTest(int slot, Item fluidProvider, int tank) {
133+
return this.createTest("takeFluidFromItem", STRUCTURE_3x3, 2, 1, helper -> {
134+
Machine machine = this.createMachine(helper);
135+
machine.itemStorage().getSlot(slot).set(fluidProvider, 1);
136+
helper.runAfterDelay(1, () -> {
137+
if (machine.fluidStorage().getSlot(tank).isEmpty()) {
138+
helper.fail("Machine did not take fluid from the stack!", machine.getBlockPos());
139+
} else {
140+
helper.succeed();
141+
}
142+
});
143+
});
144+
}
145+
146+
public TestFunction createDrainFluidIntoItemTest(int slot, Fluid fluid, int tank) {
147+
return this.createTest("drainFluidIntoItem", STRUCTURE_3x3, 2, 1, helper -> {
148+
Machine machine = this.createMachine(helper);
149+
150+
machine.fluidStorage().getSlot(tank).set(fluid, FluidConstants.BUCKET);
151+
machine.itemStorage().getSlot(slot).set(Items.BUCKET, 1);
152+
153+
helper.runAfterDelay(1, () -> {
154+
if (machine.energyStorage().isFull()) {
155+
helper.fail("Machine did not drain fluid into the stack!", BlockPos.ZERO);
156+
} else {
157+
helper.succeed();
158+
}
159+
});
160+
});
161+
}
162+
120163
protected Machine createMachine(GameTestHelper helper) {
121164
helper.setBlock(MACHINE_POS, this.type.getBlock());
122165
return (Machine) helper.getBlockEntity(MACHINE_POS);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (c) 2021-2024 Team Galacticraft
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package dev.galacticraft.machinelib.api.gametest;
24+
25+
import net.minecraft.core.BlockPos;
26+
import net.minecraft.gametest.framework.GameTestAssertPosException;
27+
import net.minecraft.gametest.framework.GameTestHelper;
28+
29+
import java.text.MessageFormat;
30+
import java.util.ArrayList;
31+
import java.util.List;
32+
33+
public class MachineTestContext {
34+
private final BlockPos pos;
35+
private final GameTestHelper helper;
36+
private final List<String> logs = new ArrayList<>();
37+
38+
public MachineTestContext(BlockPos pos, GameTestHelper helper) {
39+
this.pos = pos;
40+
this.helper = helper;
41+
}
42+
43+
public GameTestHelper helper() {
44+
return this.helper;
45+
}
46+
47+
public void log(String message) {
48+
this.logs.add(message);
49+
}
50+
51+
public void assertTrue(boolean b, String message) {
52+
if (!b) {
53+
throw this.fail(message);
54+
}
55+
}
56+
57+
public GameTestAssertPosException fail(String message, Object... objects) {
58+
return new GameTestAssertPosException(new MessageFormat(message).format(objects), this.helper.absolutePos(this.pos), this.pos, this.helper.getTick());
59+
}
60+
61+
public GameTestAssertPosException fail(String message) {
62+
return new GameTestAssertPosException(message, this.helper.absolutePos(this.pos), this.pos, this.helper.getTick());
63+
}
64+
}

src/main/java/dev/galacticraft/machinelib/api/gametest/RecipeGameTest.java

+54-74
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424

2525
import dev.galacticraft.machinelib.api.block.entity.RecipeMachineBlockEntity;
2626
import dev.galacticraft.machinelib.api.gametest.annotation.MachineTest;
27+
import dev.galacticraft.machinelib.api.gametest.recipe.IngredientSupplier;
2728
import dev.galacticraft.machinelib.api.machine.MachineType;
2829
import dev.galacticraft.machinelib.api.storage.MachineItemStorage;
2930
import net.minecraft.gametest.framework.GameTestAssertException;
3031
import net.minecraft.gametest.framework.GameTestGenerator;
32+
import net.minecraft.gametest.framework.GameTestHelper;
3133
import net.minecraft.gametest.framework.TestFunction;
3234
import net.minecraft.world.Container;
3335
import net.minecraft.world.item.Items;
@@ -47,112 +49,96 @@
4749
* @see RecipeMachineBlockEntity
4850
*/
4951
public abstract class RecipeGameTest<C extends Container, R extends Recipe<C>, Machine extends RecipeMachineBlockEntity<C, R>> extends MachineGameTest<Machine> {
50-
private final int inputSlotsStart;
51-
private final int inputSlotsLength;
5252
private final int outputSlotsStart;
5353
private final int outputSlotsLength;
54+
protected final int recipeRuntime;
5455

55-
protected RecipeGameTest(@NotNull MachineType<Machine, ?> type, int inputSlot, int outputSlot) {
56-
this(type, inputSlot, 1, outputSlot);
56+
private final List<IngredientSupplier<C, R, Machine>> conditions;
57+
58+
protected RecipeGameTest(@NotNull MachineType<Machine, ?> type, List<IngredientSupplier<C, R, Machine>> conditions, int recipeRuntime) {
59+
this(type, conditions, -1, 0, recipeRuntime);
5760
}
5861

59-
protected RecipeGameTest(@NotNull MachineType<Machine, ?> type, int inputSlotsStart, int inputSlotsLength, int outputSlot) {
60-
this(type, inputSlotsStart, inputSlotsLength, outputSlot, 1);
62+
protected RecipeGameTest(@NotNull MachineType<Machine, ?> type, List<IngredientSupplier<C, R, Machine>> conditions, int outputSlot, int recipeRuntime) {
63+
this(type, conditions, outputSlot, 1, recipeRuntime);
6164
}
6265

63-
protected RecipeGameTest(@NotNull MachineType<Machine, ?> type, int inputSlotsStart, int inputSlotsLength, int outputSlotsStart, int outputSlotsLength) {
66+
protected RecipeGameTest(@NotNull MachineType<Machine, ?> type, List<IngredientSupplier<C, R, Machine>> conditions, int outputSlotsStart, int outputSlotsLength, int recipeRuntime) {
6467
super(type);
6568

66-
this.inputSlotsStart = inputSlotsStart;
67-
this.inputSlotsLength = inputSlotsLength;
6869
this.outputSlotsStart = outputSlotsStart;
6970
this.outputSlotsLength = outputSlotsLength;
71+
this.recipeRuntime = recipeRuntime;
72+
this.conditions = conditions;
7073
}
7174

72-
protected abstract void fulfillRunRequirements(@NotNull Machine machine);
73-
protected abstract int getRecipeRuntime();
74-
protected abstract void createValidRecipe(@NotNull MachineItemStorage storage);
75-
7675
protected boolean anyRecipeCrafted(@NotNull MachineItemStorage storage) {
7776
return !storage.isEmpty(this.outputSlotsStart, this.outputSlotsLength);
7877
}
7978

80-
protected void createInvalidRecipe(@NotNull MachineItemStorage storage) {
81-
for (int i = 0; i < this.inputSlotsLength; i++) {
82-
storage.getSlot(this.inputSlotsStart + i).set(Items.BARRIER, 1);
83-
}
84-
}
85-
8679
protected void fillOutputSlots(@NotNull MachineItemStorage storage) {
8780
for (int i = 0; i < this.outputSlotsLength; i++) {
8881
storage.getSlot(this.outputSlotsStart + i).set(Items.BARRIER, 1);
8982
}
9083
}
9184

92-
@MachineTest(group = "recipe", workTime = 1)
85+
protected void fulfillRunConditions(Machine machine) {
86+
for (IngredientSupplier<C, R, Machine> condition : this.conditions) {
87+
condition.fulfillRunRequirements(machine);
88+
}
89+
}
90+
91+
@MachineTest(group = "recipe")
9392
public Runnable initialize(Machine machine) {
94-
this.fulfillRunRequirements(machine);
95-
this.createValidRecipe(machine.itemStorage());
93+
this.fulfillRunConditions(machine);
9694
return () -> {
9795
if (machine.getActiveRecipe() == null) {
9896
throw new GameTestAssertException("Failed to find recipe!");
9997
}
10098
};
10199
}
102100

103-
@MachineTest(group = "recipe", workTime = 1)
104-
public Runnable invalid(Machine machine) {
105-
this.fulfillRunRequirements(machine);
106-
this.createInvalidRecipe(machine.itemStorage());
107-
return () -> {
108-
if (machine.getActiveRecipe() != null) {
109-
throw new GameTestAssertException("Crafting something despite recipe being invalid!");
110-
}
111-
};
112-
}
113-
114-
@MachineTest(group = "recipe", workTime = 1)
101+
@MachineTest(group = "recipe")
115102
public Runnable full(Machine machine) {
116-
this.fulfillRunRequirements(machine);
103+
this.fulfillRunConditions(machine);
117104
this.fillOutputSlots(machine.itemStorage());
118-
this.createValidRecipe(machine.itemStorage());
105+
119106
return () -> {
120107
if (machine.getActiveRecipe() != null) {
121108
throw new GameTestAssertException("Crafting something despite the output being full!");
122109
}
123110
};
124111
}
125112

126-
@MachineTest(group = "recipe", workTime = 1)
127-
public Runnable craft(Machine machine) {
128-
this.fulfillRunRequirements(machine);
129-
this.fillOutputSlots(machine.itemStorage());
130-
this.createValidRecipe(machine.itemStorage());
131-
return () -> {
132-
if (machine.getActiveRecipe() != null) {
133-
throw new GameTestAssertException("Crafting something despite the output being full!");
113+
protected void tryCraft(GameTestHelper helper) {
114+
Machine machine = createMachine(helper);
115+
116+
fulfillRunConditions(machine);
117+
118+
helper.runAfterDelay(this.recipeRuntime, () -> {
119+
if (!this.anyRecipeCrafted(machine.itemStorage())) {
120+
helper.fail("Failed to craft recipe!", machine.getBlockPos());
121+
} else {
122+
helper.succeed();
134123
}
135-
};
124+
});
136125
}
137126

138-
// @InstantTest(group = "recipe")
139-
// public Runnable recipeNoResources(Machine machine) {
140-
// this.createValidRecipe(machine.itemStorage());
141-
// return () -> {
142-
// if (machine.getMaxProgress() != 0) { //fixme: recipe detection works differently
143-
// throw new GameTestAssertException("Machine is crafting a recipe, despite not having relevant resources (e.g. energy)!");
144-
// }
145-
// };
146-
// }
147-
148-
@MachineTest(group = "recipe", workTime = 1)
149-
public Runnable resourcesNoRecipe(Machine machine) {
150-
this.fulfillRunRequirements(machine);
151-
return () -> {
152-
if (machine.getActiveRecipe() != null) {
153-
throw new GameTestAssertException("Machine is doing something, despite not having a recipe!");
127+
protected void tryCraftPartial(GameTestHelper helper, int ignored) {
128+
Machine machine = createMachine(helper);
129+
130+
for (int i = 0; i < this.conditions.size(); i++) {
131+
if (i == ignored) continue;
132+
this.conditions.get(i).fulfillRunRequirements(machine);
133+
}
134+
135+
helper.runAfterDelay(this.recipeRuntime, () -> {
136+
if (this.anyRecipeCrafted(machine.itemStorage())) {
137+
helper.fail("Partial recipe %s crafted!".formatted(ignored), machine.getBlockPos());
138+
} else {
139+
helper.succeed();
154140
}
155-
};
141+
});
156142
}
157143

158144
@Override
@@ -161,18 +147,12 @@ public Runnable resourcesNoRecipe(Machine machine) {
161147
public @NotNull List<TestFunction> registerTests() {
162148
List<TestFunction> tests = super.registerTests();
163149
// variable runtime
164-
tests.add(this.createTest("recipe", "craft", STRUCTURE_3x3, this.getRecipeRuntime(), 1, helper -> {
165-
Machine machine = createMachine(helper);
166-
this.fulfillRunRequirements(machine);
167-
this.createValidRecipe(machine.itemStorage());
168-
helper.runAfterDelay(this.getRecipeRuntime(), () -> {
169-
if (!this.anyRecipeCrafted(machine.itemStorage())) {
170-
helper.fail("Failed to craft recipe!", machine.getBlockPos());
171-
} else {
172-
helper.succeed();
173-
}
174-
});
175-
}));
150+
tests.add(this.createTest("recipe", "craft", STRUCTURE_3x3, this.recipeRuntime, 1, this::tryCraft));
151+
152+
for (int i = 0; i < this.conditions.size(); i++) {
153+
int finalI = i;
154+
tests.add(this.createTest("recipe", "craft.partial." + i, STRUCTURE_3x3, this.recipeRuntime, 1, helper -> this.tryCraftPartial(helper, finalI)));
155+
}
176156
return tests;
177157
}
178158
}

0 commit comments

Comments
 (0)