Skip to content

Commit c757032

Browse files
committed
Start proxy and recipe handling tests
1 parent 80c861e commit c757032

File tree

19 files changed

+218
-24
lines changed

19 files changed

+218
-24
lines changed

build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ minecraft {
145145
environment 'MOD_MODULES', String.join(File.pathSeparator, "${mod_id}%%${project.name}.test")
146146
environment 'target', 'fmltestserver'
147147
environment 'targetModId', "${mod_id}"
148+
environment "TEST_RESOURCES", sourceSets.test.resources.srcDirs[0]
148149
arg '--keepAlive'
149150
forceExit = false
150151
mods {
@@ -166,6 +167,7 @@ minecraft {
166167
environment 'MOD_MODULES', String.join(File.pathSeparator, "${mod_id}%%${project.name}.test")
167168
environment 'target', 'fmltestserver'
168169
environment 'targetModId', "${mod_id}"
170+
environment "TEST_RESOURCES", sourceSets.test.resources.srcDirs[0]
169171
arg '--crashOnFailedTests'
170172
forceExit = false
171173
mods {

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod_version=1.0.0-beta.5
1212
# Dependencies and Libs
1313
jei_version=7.7.1.110
1414
top_version=1.16-3.1.4-22
15-
mcunittest_version=1.7.0-1.16.5
15+
mcunittest_version=1.8.1-1.16.5
1616

1717
# Curseforge
1818
cf_project=429735

src/main/java/dev/compactmods/crafting/field/MiniaturizationField.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,6 @@ public void doRecipeScan() {
258258
if (level == null)
259259
return;
260260

261-
// TODO - This is giving bad data with mixed layers (CM4 recipes) - fix it
262-
263261
if (ServerConfig.FIELD_BLOCK_CHANGES.get())
264262
CompactCrafting.LOGGER.debug("Beginning field recipe scan: {}", this.center);
265263

@@ -457,22 +455,16 @@ public void handleProjectorBroken() {
457455
break;
458456

459457
case RESTORE_BLOCKS:
458+
case DESTROY_CATALYST:
460459
restoreBlocks = true;
461460
break;
462461

463462
case RESTORE_CATALYST:
464-
restoreCatalyst = true;
465-
break;
466-
467-
case DESTROY_ALL:
468-
break;
469-
470463
case DESTROY_BLOCKS:
471464
restoreCatalyst = true;
472465
break;
473466

474-
case DESTROY_CATALYST:
475-
restoreBlocks = true;
467+
case DESTROY_ALL:
476468
break;
477469
}
478470

src/main/resources/pack.mcmeta

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"pack": {
33
"description": "Compact Crafting resources",
4-
"pack_format": 5,
5-
"_comment": "A pack_format of 5 requires json lang files and some texture changes from 1.15. Note: we require v5 pack meta for all mods."
4+
"pack_format": 6
65
}
76
}
Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,70 @@
11
package dev.compactmods.crafting.tests;
22

3+
import java.io.File;
4+
import java.nio.file.Path;
5+
import java.nio.file.Paths;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import com.google.common.collect.ImmutableMap;
39
import dev.compactmods.crafting.CompactCrafting;
10+
import dev.compactmods.crafting.Registration;
11+
import dev.compactmods.crafting.recipes.MiniaturizationRecipe;
12+
import dev.compactmods.crafting.tests.recipes.util.RecipeTestUtil;
413
import net.minecraft.entity.player.PlayerEntity;
14+
import net.minecraft.item.crafting.IRecipe;
15+
import net.minecraft.item.crafting.IRecipeType;
16+
import net.minecraft.item.crafting.RecipeManager;
517
import net.minecraft.server.MinecraftServer;
618
import net.minecraft.server.management.PlayerList;
19+
import net.minecraft.util.ResourceLocation;
720
import net.minecraftforge.event.entity.player.PlayerEvent;
821
import net.minecraftforge.eventbus.api.SubscribeEvent;
922
import net.minecraftforge.fml.common.Mod;
23+
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
1024
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
1125

1226
@Mod.EventBusSubscriber(modid = CompactCrafting.MOD_ID)
1327
public class ServerEventListener {
28+
1429
@SubscribeEvent
1530
public static void onServerStarted(final FMLServerStartedEvent evt) {
1631

1732
final MinecraftServer server = evt.getServer();
1833
// final File root = server.getServerDirectory().getParentFile();
1934
// server.getPackRepository().addPackFinder(new FolderPackFinder());
35+
36+
hackyRecipeLoad(server);
37+
}
38+
39+
private static void hackyRecipeLoad(MinecraftServer server) {
40+
final RecipeManager recipeManager = server.overworld().getRecipeManager();
41+
final ImmutableMap<IRecipeType<?>, Map<ResourceLocation, IRecipe<?>>> recipes = ObfuscationReflectionHelper
42+
.getPrivateValue(RecipeManager.class, recipeManager, "recipes");
43+
final HashMap<IRecipeType<?>, Map<ResourceLocation, IRecipe<?>>> moreRecipes = new HashMap<>();
44+
45+
final HashMap<ResourceLocation, IRecipe<?>> miniRecipes = new HashMap<>();
46+
final Path pf = new File(System.getenv("TEST_RESOURCES")).toPath();
47+
final Path testRecipes = pf.resolve(Paths.get("data", "compactcrafting", "recipes"));
48+
49+
final File recipeDir = testRecipes.toFile();
50+
final String dp = recipeDir.getAbsolutePath();
51+
if (!recipeDir.exists())
52+
return;
53+
54+
final File[] files = recipeDir.listFiles();
55+
if (files == null)
56+
return;
57+
58+
for (File f : files) {
59+
final MiniaturizationRecipe recipe = RecipeTestUtil.getRecipeFromFile(f.getAbsolutePath());
60+
if (recipe != null)
61+
miniRecipes.put(recipe.getRecipeIdentifier(), recipe);
62+
}
63+
64+
moreRecipes.put(Registration.MINIATURIZATION_RECIPE_TYPE, miniRecipes);
65+
moreRecipes.putAll(recipes);
66+
67+
ObfuscationReflectionHelper.setPrivateValue(RecipeManager.class, recipeManager, moreRecipes, "recipes");
2068
}
2169

2270
@SubscribeEvent
@@ -25,7 +73,7 @@ static void onPlayerJoined(final PlayerEvent.PlayerLoggedInEvent evt) {
2573
final MinecraftServer server = player.getServer();
2674
final PlayerList players = server.getPlayerList();
2775
final boolean op = players.isOp(player.getGameProfile());
28-
if(!op)
76+
if (!op)
2977
players.op(player.getGameProfile());
3078
}
3179
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package dev.compactmods.crafting.tests.proxies;
2+
3+
import javax.annotation.Nonnull;
4+
import com.alcatrazescapee.mcjunitlib.framework.IntegrationTest;
5+
import com.alcatrazescapee.mcjunitlib.framework.IntegrationTestClass;
6+
import com.alcatrazescapee.mcjunitlib.framework.IntegrationTestHelper;
7+
import dev.compactmods.crafting.Registration;
8+
import dev.compactmods.crafting.api.field.IFieldListener;
9+
import dev.compactmods.crafting.api.field.IMiniaturizationField;
10+
import dev.compactmods.crafting.api.field.MiniaturizationFieldSize;
11+
import dev.compactmods.crafting.api.recipe.IMiniaturizationRecipe;
12+
import dev.compactmods.crafting.field.capability.CapabilityMiniaturizationField;
13+
import dev.compactmods.crafting.proxies.data.MatchFieldProxyEntity;
14+
import dev.compactmods.crafting.server.ServerConfig;
15+
import dev.compactmods.crafting.tests.recipes.util.RecipeTestUtil;
16+
import net.minecraft.block.Blocks;
17+
import net.minecraft.block.RedstoneLampBlock;
18+
import net.minecraft.tileentity.TileEntity;
19+
import net.minecraft.util.Direction;
20+
import net.minecraft.util.ResourceLocation;
21+
import net.minecraft.util.math.BlockPos;
22+
import net.minecraftforge.common.util.LazyOptional;
23+
import org.junit.jupiter.api.Assertions;
24+
import org.junit.jupiter.api.Tag;
25+
26+
@IntegrationTestClass("proxies")
27+
public class ProxyLinkingTests {
28+
29+
@Tag("minecraft")
30+
@org.junit.jupiter.api.BeforeAll
31+
static void BeforeAllTests() {
32+
ServerConfig.RECIPE_REGISTRATION.set(true);
33+
ServerConfig.RECIPE_MATCHING.set(true);
34+
ServerConfig.FIELD_BLOCK_CHANGES.set(true);
35+
}
36+
37+
@IntegrationTest("empty_medium")
38+
void CanPlaceProxy(IntegrationTestHelper test) {
39+
test.setBlockState(new BlockPos(2, 0, 2), Registration.MATCH_FIELD_PROXY_BLOCK.get().defaultBlockState());
40+
test.setBlockState(new BlockPos(2, 0, 4), Registration.RESCAN_FIELD_PROXY_BLOCK.get().defaultBlockState());
41+
}
42+
43+
@IntegrationTest("medium_field")
44+
void CanLinkProxy(IntegrationTestHelper test) {
45+
MatchFieldProxyEntity proxy = setupProxyForMediumField(test);
46+
47+
final LazyOptional<IMiniaturizationField> cap = proxy.getCapability(CapabilityMiniaturizationField.MINIATURIZATION_FIELD);
48+
49+
Assertions.assertTrue(cap.isPresent());
50+
}
51+
52+
@IntegrationTest("medium_field")
53+
void MatchProxyPowersOnForRecipeMatch(IntegrationTestHelper test) {
54+
MatchFieldProxyEntity proxy = setupProxyForMediumField(test);
55+
56+
// Set up a deferred check, so we can schedule a block check after the recipe changes
57+
test.addNamedRunnable("postRecipeMatch", () -> {
58+
final IntegrationTestHelper.ScheduleHelper scheduler = test.scheduler();
59+
scheduler.thenRun(5, () -> {
60+
final Boolean lit = test.getBlockState(BlockPos.ZERO).getValue(RedstoneLampBlock.LIT);
61+
Assertions.assertTrue(lit);
62+
}).thenWait(5);
63+
});
64+
65+
RecipeTestUtil.loadStructureIntoTestArea(test,
66+
new ResourceLocation("compactcrafting", "recipes/ender_crystal"),
67+
new BlockPos(4, 1, 4));
68+
69+
proxy.getCapability(CapabilityMiniaturizationField.MINIATURIZATION_FIELD)
70+
.ifPresent(field -> {
71+
field.registerListener(LazyOptional.of(() -> new IFieldListener() {
72+
@Override
73+
public void onRecipeMatched(IMiniaturizationField field, IMiniaturizationRecipe recipe) {
74+
Assertions.assertNotNull(recipe);
75+
test.executeNamedRunnable("postRecipeMatch");
76+
}
77+
}));
78+
79+
field.fieldContentsChanged();
80+
});
81+
}
82+
83+
@IntegrationTest("medium_field")
84+
void ProxyDisconnectsIfFieldDestabilizes(IntegrationTestHelper test) {
85+
BlockPos relFieldCenter = new BlockPos(6, 3, 6);
86+
87+
MatchFieldProxyEntity proxy = setupProxyForMediumField(test);
88+
89+
final LazyOptional<IMiniaturizationField> fieldRef = proxy.getCapability(CapabilityMiniaturizationField.MINIATURIZATION_FIELD);
90+
fieldRef.resolve();
91+
92+
// Ensure proxy is connected to field
93+
Assertions.assertTrue(fieldRef.isPresent());
94+
95+
test.addNamedRunnable("postBreak", () -> {
96+
final LazyOptional<IMiniaturizationField> fieldPostBreak = proxy.getCapability(CapabilityMiniaturizationField.MINIATURIZATION_FIELD);
97+
fieldPostBreak.resolve();
98+
99+
Assertions.assertFalse(fieldPostBreak.isPresent());
100+
});
101+
102+
BlockPos relNorthProjector = MiniaturizationFieldSize.MEDIUM.getProjectorLocationForDirection(relFieldCenter, Direction.NORTH);
103+
test.destroyBlock(relNorthProjector, false);
104+
105+
test.scheduler().thenRun(5, () -> test.executeNamedRunnable("postBreak"));
106+
}
107+
108+
109+
@Nonnull
110+
private MatchFieldProxyEntity setupProxyForMediumField(IntegrationTestHelper test) {
111+
final BlockPos proxyLocation = new BlockPos(0, 1, 0);
112+
113+
test.setBlockState(proxyLocation, Registration.MATCH_FIELD_PROXY_BLOCK.get().defaultBlockState());
114+
test.setBlockState(BlockPos.ZERO, Blocks.REDSTONE_LAMP.defaultBlockState());
115+
116+
final TileEntity tile = test.getTileEntity(proxyLocation);
117+
Assertions.assertTrue(tile instanceof MatchFieldProxyEntity);
118+
119+
MatchFieldProxyEntity proxy = (MatchFieldProxyEntity) tile;
120+
121+
BlockPos centerField = new BlockPos(6, 3, 6);
122+
proxy.updateField(test.relativePos(centerField).orElse(BlockPos.ZERO));
123+
return proxy;
124+
}
125+
}

src/test/java/dev/compactmods/crafting/tests/recipes/data/MiniaturizationRecipeCodecTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void LoadsRecipeFromJson() {
4141
@Test
4242
@Tag("minecraft")
4343
void RequiresRecipeSizeOnAllDynamicLayers() {
44-
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("data/compactcrafting/recipes/fail_no_size_dynamic.json");
44+
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("recipe_tests/fail_no_size_dynamic.json");
4545

4646
Optional<DataResult.PartialResult<MiniaturizationRecipe>> loaded = MiniaturizationRecipe.CODEC
4747
.parse(JsonOps.INSTANCE, json)
@@ -56,7 +56,7 @@ void RequiresRecipeSizeOnAllDynamicLayers() {
5656
@Test
5757
@Tag("minecraft")
5858
void DoesNotFailIfNoComponentsDefined() {
59-
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("data/compactcrafting/recipes/warn_no_components.json");
59+
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("recipe_tests/warn_no_components.json");
6060

6161
Either<MiniaturizationRecipe, DataResult.PartialResult<MiniaturizationRecipe>> loaded = MiniaturizationRecipe.CODEC
6262
.parse(JsonOps.INSTANCE, json)
@@ -76,7 +76,7 @@ void DoesNotFailIfNoComponentsDefined() {
7676
@Test
7777
@Tag("minecraft")
7878
void PartialResultIfNoOutputsEntryExists() {
79-
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("data/compactcrafting/recipes/fail_no_outputs_entry.json");
79+
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("recipe_tests/fail_no_outputs_entry.json");
8080

8181
Either<MiniaturizationRecipe, DataResult.PartialResult<MiniaturizationRecipe>> loaded = MiniaturizationRecipe.CODEC
8282
.parse(JsonOps.INSTANCE, json)
@@ -92,7 +92,7 @@ void PartialResultIfNoOutputsEntryExists() {
9292
@Test
9393
@Tag("minecraft")
9494
void PartialResultIfNoOutputsExist() {
95-
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("data/compactcrafting/recipes/fail_no_outputs.json");
95+
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("recipe_tests/fail_no_outputs.json");
9696

9797
Either<MiniaturizationRecipe, DataResult.PartialResult<MiniaturizationRecipe>> loaded = MiniaturizationRecipe.CODEC
9898
.parse(JsonOps.INSTANCE, json)
@@ -138,7 +138,7 @@ void LoadsCatalystCorrectly() {
138138
Assertions.assertNotNull(recipe);
139139
Assertions.assertFalse(recipe.getCatalyst().isEmpty());
140140

141-
MiniaturizationRecipe noComponents = RecipeTestUtil.getRecipeFromFile("data/compactcrafting/recipes/warn_no_catalyst.json");
141+
MiniaturizationRecipe noComponents = RecipeTestUtil.getRecipeFromFile("recipe_tests/warn_no_catalyst.json");
142142
Assertions.assertNotNull(noComponents);
143143
Assertions.assertTrue(noComponents.getCatalyst().isEmpty());
144144
}

src/test/java/dev/compactmods/crafting/tests/recipes/data/MiniaturizationRecipeSerializerTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void SerializerCanDeserializeJson() {
9292
@Test
9393
@Tag("minecraft")
9494
void SerializerHandlesJsonErrorsAppropriately() {
95-
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("data/compactcrafting/recipes/fail_no_size_dynamic.json");
95+
JsonElement json = FileHelper.INSTANCE.getJsonFromFile("recipe_tests/fail_no_size_dynamic.json");
9696

9797
MiniaturizationRecipeSerializer s = new MiniaturizationRecipeSerializer();
9898
final ResourceLocation id = new ResourceLocation(CompactCrafting.MOD_ID, "test");

src/test/java/dev/compactmods/crafting/tests/recipes/util/RecipeTestUtil.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Map;
44
import java.util.Optional;
55
import com.alcatrazescapee.mcjunitlib.framework.IntegrationTestHelper;
6+
import com.google.common.io.Files;
67
import com.google.gson.JsonElement;
78
import com.mojang.serialization.Codec;
89
import com.mojang.serialization.JsonOps;
@@ -13,8 +14,12 @@
1314
import dev.compactmods.crafting.recipes.components.MiniaturizationRecipeComponents;
1415
import dev.compactmods.crafting.tests.util.FileHelper;
1516
import dev.compactmods.crafting.util.BlockSpaceUtil;
17+
import net.minecraft.util.ResourceLocation;
1618
import net.minecraft.util.math.AxisAlignedBB;
1719
import net.minecraft.util.math.BlockPos;
20+
import net.minecraft.world.gen.feature.template.PlacementSettings;
21+
import net.minecraft.world.gen.feature.template.Template;
22+
import net.minecraft.world.gen.feature.template.TemplateManager;
1823
import org.junit.jupiter.api.Assertions;
1924

2025
public class RecipeTestUtil {
@@ -28,13 +33,16 @@ public static MiniaturizationRecipe getRecipeFromFile(String filename) {
2833
Assertions.fail("Recipe did not load from file.");
2934
return null;
3035
} else {
31-
return loaded.get();
36+
final MiniaturizationRecipe rec = loaded.get();
37+
rec.setId(new ResourceLocation("compactcrafting", Files.getNameWithoutExtension(filename)));
38+
return rec;
3239
}
3340
}
3441

3542
public static MiniaturizationRecipeComponents getComponentsFromRecipeFile(String filename) {
3643
final JsonElement data = FileHelper.INSTANCE.getJsonFromFile(filename);
3744

45+
3846
final Map<String, BlockComponent> blocks = Codec.unboundedMap(Codec.STRING, BlockComponent.CODEC)
3947
.fieldOf("components")
4048
.codec()
@@ -54,4 +62,13 @@ public static AxisAlignedBB getFieldBounds(MiniaturizationFieldSize fieldSize, I
5462
public static AxisAlignedBB getFloorLayerBounds(MiniaturizationFieldSize fieldSize, IntegrationTestHelper helper) {
5563
return BlockSpaceUtil.getLayerBounds(getFieldBounds(fieldSize, helper), 0);
5664
}
65+
66+
public static void loadStructureIntoTestArea(IntegrationTestHelper test, ResourceLocation structure, BlockPos location) {
67+
final TemplateManager structures = test.getWorld().getStructureManager();
68+
final Template ender = structures.get(structure);
69+
if(ender == null)
70+
return;
71+
72+
ender.placeInWorld(test.getWorld(), test.getOrigin().offset(location), new PlacementSettings(), test.getWorld().getRandom());
73+
}
5774
}

0 commit comments

Comments
 (0)