Skip to content

Commit 242a889

Browse files
authored
Add game tests (#977)
1 parent b7e31a1 commit 242a889

File tree

14 files changed

+949
-38
lines changed

14 files changed

+949
-38
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,9 @@ jobs:
2626
run: ./gradlew build
2727
env:
2828
MI_VERSION: git-${{ steps.var.outputs.commit_hash }}
29-
- name: Autotest Server
29+
- name: Gametest Server
3030
run: |
31-
rm -rf run || echo "no run directory to remove"
32-
mkdir run
33-
echo eula=true >> run/eula.txt
34-
./gradlew runAutotestServer --stacktrace
35-
! grep -q FATAL runs/server/logs/latest.log
36-
! grep -q JsonSyntaxException runs/server/logs/latest.log
31+
./gradlew runGameTestServer
3732
- name: Upload artifacts
3833
uses: actions/upload-artifact@v4
3934
with:

build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,9 @@ neoForge {
237237
programArguments.addAll '--mod', "modern_industrialization", '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
238238
}
239239

240-
autotestServer {
241-
server()
242-
systemProperty 'modern_industrialization.autoTest', 'true'
240+
gameTestServer {
241+
type = "gameTestServer"
242+
gameDirectory = project.file("build/gametest")
243243
}
244244
}
245245
}
Binary file not shown.

src/main/java/aztech/modern_industrialization/MI.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import aztech.modern_industrialization.machines.init.SingleBlockSpecialMachines;
4545
import aztech.modern_industrialization.machines.multiblocks.world.ChunkEventListeners;
4646
import aztech.modern_industrialization.materials.MIMaterials;
47-
import aztech.modern_industrialization.misc.autotest.MIAutoTesting;
4847
import aztech.modern_industrialization.misc.guidebook.GuidebookEvents;
4948
import aztech.modern_industrialization.misc.runtime_datagen.RuntimeDataGen;
5049
import aztech.modern_industrialization.network.MIPackets;
@@ -53,6 +52,7 @@
5352
import aztech.modern_industrialization.proxy.CommonProxy;
5453
import aztech.modern_industrialization.resource.GeneratedPathPackResources;
5554
import aztech.modern_industrialization.stats.PlayerStatisticsData;
55+
import aztech.modern_industrialization.test.framework.MIGameTests;
5656
import java.util.List;
5757
import java.util.Objects;
5858
import java.util.Optional;
@@ -79,6 +79,7 @@
7979
import net.neoforged.neoforge.data.event.GatherDataEvent;
8080
import net.neoforged.neoforge.event.AddPackFindersEvent;
8181
import net.neoforged.neoforge.event.AnvilUpdateEvent;
82+
import net.neoforged.neoforge.event.RegisterGameTestsEvent;
8283
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
8384
import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent;
8485
import net.neoforged.neoforge.event.village.VillagerTradesEvent;
@@ -123,10 +124,6 @@ public MI(IEventBus modBus, Dist dist) {
123124
GuidebookEvents.init();
124125
MIArmorEffects.init();
125126

126-
if (System.getProperty("modern_industrialization.autoTest") != null) {
127-
MIAutoTesting.init();
128-
}
129-
130127
NeoForge.EVENT_BUS.addListener(PlayerEvent.PlayerChangedDimensionEvent.class, event -> MIKeyMap.clear(event.getEntity()));
131128
NeoForge.EVENT_BUS.addListener(PlayerEvent.PlayerLoggedOutEvent.class, event -> MIKeyMap.clear(event.getEntity()));
132129
NeoForge.EVENT_BUS.addListener(PlayerEvent.PlayerLoggedInEvent.class, event -> {
@@ -233,6 +230,10 @@ public MI(IEventBus modBus, Dist dist) {
233230
}
234231
});
235232

233+
modBus.addListener(RegisterGameTestsEvent.class, event -> {
234+
event.register(MIGameTests.class);
235+
});
236+
236237
LOGGER.info("Modern Industrialization setup done!");
237238
}
238239
}

src/main/java/aztech/modern_industrialization/blocks/storage/tank/creativetank/CreativeTankBlockEntity.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ public boolean onPlayerUse(Player player) {
4545
if (isResourceBlank()) {
4646
var fluid = FluidUtil.getFluidContained(player.getItemInHand(InteractionHand.MAIN_HAND));
4747
if (fluid.isPresent()) {
48-
resource = FluidVariant.of(fluid.get());
49-
onChanged();
48+
setFluid(FluidVariant.of(fluid.get()));
5049
return true;
5150
}
5251
return !isResourceBlank();
@@ -64,4 +63,8 @@ public boolean onPlayerUse(Player player) {
6463
return false;
6564
}
6665

66+
public void setFluid(FluidVariant variant) {
67+
resource = variant;
68+
onChanged();
69+
}
6770
}

src/main/java/aztech/modern_industrialization/datagen/MIDatagenServer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import aztech.modern_industrialization.datagen.recipe.PlankRecipesProvider;
4040
import aztech.modern_industrialization.datagen.recipe.UpgradeProvider;
4141
import aztech.modern_industrialization.datagen.recipe.VanillaCompatRecipesProvider;
42+
import aztech.modern_industrialization.datagen.structure.EmptyTestStructureGenerator;
4243
import aztech.modern_industrialization.datagen.tag.MIBlockTagProvider;
4344
import aztech.modern_industrialization.datagen.tag.MIFluidTagProvider;
4445
import aztech.modern_industrialization.datagen.tag.MIItemTagProvider;
@@ -78,6 +79,8 @@ public static void configure(
7879
aggregate.addProvider(UpgradeProvider::new);
7980
aggregate.addProvider(VanillaCompatRecipesProvider::new);
8081

82+
aggregate.addProvider(EmptyTestStructureGenerator::new);
83+
8184
gen.addProvider(run, new LootTableProvider(gen.getPackOutput(), Set.of(), List.of(
8285
new LootTableProvider.SubProviderEntry(BlockLootTableProvider::new, LootContextParamSets.BLOCK)),
8386
lookupProvider));
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2020 Azercoco & Technici4n
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package aztech.modern_industrialization.datagen.structure;
25+
26+
import aztech.modern_industrialization.MI;
27+
import com.google.common.hash.HashCode;
28+
import com.mojang.brigadier.exceptions.CommandSyntaxException;
29+
import java.io.ByteArrayOutputStream;
30+
import java.io.DataOutputStream;
31+
import java.io.IOException;
32+
import java.io.UncheckedIOException;
33+
import java.nio.charset.StandardCharsets;
34+
import java.util.concurrent.CompletableFuture;
35+
import net.minecraft.data.CachedOutput;
36+
import net.minecraft.data.DataProvider;
37+
import net.minecraft.data.PackOutput;
38+
import net.minecraft.nbt.CompoundTag;
39+
import net.minecraft.nbt.NbtIo;
40+
import net.minecraft.nbt.NbtUtils;
41+
42+
public class EmptyTestStructureGenerator implements DataProvider {
43+
private final PackOutput.PathProvider pathProvider;
44+
45+
public EmptyTestStructureGenerator(PackOutput output) {
46+
this.pathProvider = output.createPathProvider(PackOutput.Target.DATA_PACK, "structure");
47+
}
48+
49+
@Override
50+
public CompletableFuture<?> run(CachedOutput output) {
51+
String structureIn;
52+
try (var in = getClass().getResourceAsStream("/data/modern_industrialization/structure/empty.snbt")) {
53+
structureIn = new String(in.readAllBytes(), StandardCharsets.UTF_8);
54+
} catch (IOException e) {
55+
throw new UncheckedIOException(e);
56+
}
57+
58+
CompoundTag structureTag;
59+
try {
60+
structureTag = NbtUtils.snbtToStructure(structureIn);
61+
} catch (CommandSyntaxException e) {
62+
throw new RuntimeException(e);
63+
}
64+
65+
structureTag = NbtUtils.addCurrentDataVersion(structureTag);
66+
67+
var out = new ByteArrayOutputStream();
68+
try {
69+
NbtIo.writeCompressed(structureTag, new DataOutputStream(out));
70+
output.writeIfNeeded(
71+
pathProvider.file(MI.id("empty"), "nbt"),
72+
out.toByteArray(),
73+
HashCode.fromBytes(out.toByteArray()));
74+
} catch (IOException e) {
75+
throw new UncheckedIOException(e);
76+
}
77+
78+
return CompletableFuture.completedFuture(null);
79+
}
80+
81+
@Override
82+
public String getName() {
83+
return "Empty Test Structure";
84+
}
85+
}

src/main/java/aztech/modern_industrialization/pipes/impl/PipeBlockEntity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ boolean canAddPipe(PipeNetworkType type) {
166166
*
167167
* @param type The type to add.
168168
*/
169-
void addPipe(PipeNetworkType type, PipeNetworkData data) {
169+
public void addPipe(PipeNetworkType type, PipeNetworkData data) {
170170
if (!canAddPipe(type))
171171
return;
172172

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2020 Azercoco & Technici4n
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package aztech.modern_industrialization.test;
25+
26+
import aztech.modern_industrialization.MI;
27+
import aztech.modern_industrialization.pipes.api.PipeNetworkType;
28+
import aztech.modern_industrialization.test.framework.MIGameTest;
29+
import aztech.modern_industrialization.test.framework.MIGameTestHelper;
30+
import net.minecraft.core.BlockPos;
31+
import net.minecraft.core.Direction;
32+
import net.minecraft.world.level.material.Fluids;
33+
34+
public class FluidPipeTests {
35+
private final PipeNetworkType fluidPipe = PipeNetworkType.get(MI.id("fluid_pipe"));
36+
37+
@MIGameTest
38+
public void testSinglePipeThroughput(MIGameTestHelper helper) {
39+
helper.creativeTank(new BlockPos(0, 1, 0), Fluids.WATER);
40+
helper.emptyTank(new BlockPos(2, 1, 0));
41+
helper.pipe(new BlockPos(1, 1, 0), fluidPipe, pipe -> {
42+
pipe.addConnection(Direction.EAST);
43+
pipe.addConnection(Direction.WEST);
44+
// Switch WEST to OUT
45+
pipe.removeConnection(Direction.WEST);
46+
pipe.removeConnection(Direction.WEST);
47+
});
48+
helper.startSequence()
49+
.thenIdle(1)
50+
.thenExecute(() -> {
51+
helper.assertFluid(new BlockPos(2, 1, 0), Fluids.WATER, 1000);
52+
})
53+
.thenSucceed();
54+
}
55+
56+
@MIGameTest
57+
public void testDoublePipeThroughput(MIGameTestHelper helper) {
58+
helper.creativeTank(new BlockPos(0, 1, 0), Fluids.WATER);
59+
helper.emptyTank(new BlockPos(2, 1, 0));
60+
helper.pipe(new BlockPos(1, 1, 0), fluidPipe, pipe -> {
61+
pipe.addConnection(Direction.EAST);
62+
pipe.addConnection(Direction.WEST);
63+
// Switch WEST to OUT
64+
pipe.removeConnection(Direction.WEST);
65+
pipe.removeConnection(Direction.WEST);
66+
});
67+
helper.pipe(new BlockPos(1, 2, 0), fluidPipe, pipe -> {
68+
});
69+
helper.startSequence()
70+
.thenIdle(1)
71+
.thenExecute(() -> {
72+
helper.assertFluid(new BlockPos(2, 1, 0), Fluids.WATER, 2000);
73+
})
74+
.thenSucceed();
75+
}
76+
}

src/main/java/aztech/modern_industrialization/misc/autotest/MIAutoTesting.java renamed to src/main/java/aztech/modern_industrialization/test/framework/MIGameTest.java

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,31 @@
2121
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2222
* SOFTWARE.
2323
*/
24-
package aztech.modern_industrialization.misc.autotest;
24+
package aztech.modern_industrialization.test.framework;
2525

26-
import net.neoforged.neoforge.common.NeoForge;
27-
import net.neoforged.neoforge.event.tick.ServerTickEvent;
28-
import org.spongepowered.asm.mixin.MixinEnvironment;
26+
import java.lang.annotation.ElementType;
27+
import java.lang.annotation.Retention;
28+
import java.lang.annotation.RetentionPolicy;
29+
import java.lang.annotation.Target;
2930

30-
/**
31-
* MI auto-testing. Can be enabled with "modern_industrialization.autoTest".
32-
*/
33-
public class MIAutoTesting {
34-
private static int ticks = 0;
35-
36-
public static void init() {
37-
NeoForge.EVENT_BUS.addListener(ServerTickEvent.Pre.class, event -> {
38-
ticks++;
39-
40-
if (ticks == 40) {
41-
MixinEnvironment.getCurrentEnvironment().audit();
42-
event.getServer().halt(false);
43-
}
44-
});
45-
}
31+
@Retention(RetentionPolicy.RUNTIME)
32+
@Target(ElementType.METHOD)
33+
public @interface MIGameTest {
34+
int timeoutTicks() default 100;
35+
36+
String batch() default "defaultBatch";
37+
38+
boolean skyAccess() default false;
39+
40+
int rotationSteps() default 0;
41+
42+
boolean required() default true;
43+
44+
boolean manualOnly() default false;
45+
46+
long setupTicks() default 0L;
47+
48+
int attempts() default 1;
49+
50+
int requiredSuccesses() default 1;
4651
}

0 commit comments

Comments
 (0)