From 0286c47f04040af3f9218eb48c5fe0a0e7dce67b Mon Sep 17 00:00:00 2001 From: Aton-Kish <38515249+Aton-Kish@users.noreply.github.com> Date: Sat, 15 Jun 2024 20:08:51 +0900 Subject: [PATCH] [v3.0.0+1.20] organized entrypoints & introduced gametest (#75) * bump deps * introduced gametest * renamed reinfshulkerclient to reinfshulker-client * fixed entrypoints * added gametest utils * added gametest testcases * added gametest phase to workflows * re-integrated with shulker box tooltip * fixed fabric.mod.json format * fixed methods * fixed styles * bump mod version to v3.0.0+1.20 --- .github/workflows/build.yaml | 7 +- .github/workflows/publish.yaml | 2 +- .github/workflows/release.yaml | 2 +- build.gradle | 41 +- gradle.properties | 14 +- .../ReinforcedShulkerBoxesClientMod.java | 4 +- .../ReinforcedShulkerBoxesModGameTest.java | 40 ++ .../gametest/testcase/AdvancementTests.java | 230 +++++++++ .../testcase/CauldronBehaviorTests.java | 172 +++++++ .../testcase/DispenserBehaviorTests.java | 123 +++++ .../gametest/testcase/InventoryTests.java | 110 ++++ .../gametest/testcase/LootTableTests.java | 213 ++++++++ .../gametest/testcase/OpenTests.java | 149 ++++++ .../gametest/testcase/PiglinTests.java | 155 ++++++ .../testcase/PistonBehaviorTests.java | 117 +++++ .../gametest/testcase/RecipeTests.java | 471 ++++++++++++++++++ .../gametest/util/MockServerPlayerHelper.java | 46 ++ .../gametest/util/VoidScreenHander.java | 21 + .../ReinforcedShulkerBoxPreviewProvider.java | 69 +++ .../shulkerboxtooltip/ShulkerBoxTooltip.java | 32 ++ .../atonkish/reinfshulker/stat/ModStats.java | 4 +- src/main/resources/fabric.mod.json | 6 +- 22 files changed, 1998 insertions(+), 30 deletions(-) create mode 100644 src/main/java/atonkish/reinfshulker/gametest/ReinforcedShulkerBoxesModGameTest.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/AdvancementTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/CauldronBehaviorTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/DispenserBehaviorTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/InventoryTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/LootTableTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/OpenTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/PiglinTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/PistonBehaviorTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/testcase/RecipeTests.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/util/MockServerPlayerHelper.java create mode 100644 src/main/java/atonkish/reinfshulker/gametest/util/VoidScreenHander.java create mode 100644 src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ReinforcedShulkerBoxPreviewProvider.java create mode 100644 src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ShulkerBoxTooltip.java diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index ccde79e..0e67099 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -27,10 +27,15 @@ jobs: - name: make gradle wrapper executable run: chmod +x ./gradlew - name: build - run: ./gradlew build + run: ./gradlew runServerTest build - name: capture build artifacts if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java uses: actions/upload-artifact@v4 with: name: Artifacts path: build/libs/ + - name: publish test report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() # always run even if the previous step fails + with: + report_paths: build/gametest/junit.xml diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 36a8eac..0971710 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -29,7 +29,7 @@ jobs: - name: make gradle wrapper executable run: chmod +x ./gradlew - name: publish - run: ./gradlew publish + run: ./gradlew runServerTest publish - name: push to mcmod repository uses: cpina/github-action-push-to-another-repository@main env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0b00553..b3635de 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -24,7 +24,7 @@ jobs: - name: make gradle wrapper executable run: chmod +x ./gradlew - name: release - run: ./gradlew build curseforge modrinth + run: ./gradlew runServerTest build curseforge modrinth - name: capture build artifacts uses: actions/upload-artifact@v4 with: diff --git a/build.gradle b/build.gradle index c9f7c67..3a9da0e 100644 --- a/build.gradle +++ b/build.gradle @@ -39,15 +39,10 @@ repositories { // url "https://maven.kyrptonaught.dev" // } - // // Shulker Box Tooltip - // maven { - // url "https://maven.misterpemodder.com/libs-release" - // } - - // // Fabric ASM (Shulker Box Tooltip deps) - // maven { - // url "https://jitpack.io" - // } + // Shulker Box Tooltip + maven { + url "https://maven.misterpemodder.com/libs-release" + } } loom { @@ -59,6 +54,26 @@ loom { sourceSet sourceSets.client } } + + runs { + serverTest { + server() + ideConfigGenerated true + name "Minecraft Server Test" + vmArg "-Dfabric-api.gametest" + vmArg "-Dfabric-api.gametest.report-file=${project.buildDir}/gametest/junit.xml" + vmArg "-Datonkish.reinfshulker.gametest" + runDir "build/gametest" + } + + clientTest { + client() + ideConfigGenerated true + name "Minecraft Client Test" + vmArg "-Datonkish.reinfshulker.gametest" + runDir "build/gametest" + } + } } dependencies { @@ -82,8 +97,8 @@ dependencies { // // Quick Shulker deps // modImplementation "net.kyrptonaught:shulkerutils:${project.shulkerutils_version}" - // // Shulker Box Tooltip - // modImplementation "com.misterpemodder:shulkerboxtooltip-fabric:${project.shulker_box_tooltip_version}" + // Shulker Box Tooltip + modImplementation "com.misterpemodder:shulkerboxtooltip-fabric:${project.shulker_box_tooltip_version}" } processResources { @@ -158,7 +173,7 @@ curseforge { requiredDependency "fabric-api" embeddedLibrary "cloth-config" optionalDependency "modmenu" - // optionalDependency "shulkerboxtooltip" + optionalDependency "shulkerboxtooltip" // optionalDependency "quick-shulker" optionalDependency "reinforced-chests" } @@ -183,7 +198,7 @@ modrinth { required.project "fabric-api" embedded.project "cloth-config" optional.project "modmenu" - // optional.project "shulkerboxtooltip" + optional.project "shulkerboxtooltip" // optional.project "quickshulker" optional.project "reinforced-chests" } diff --git a/gradle.properties b/gradle.properties index 771cee9..51946b3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,21 +5,21 @@ org.gradle.parallel=true # Fabric Properties # check these on https://fabricmc.net/develop minecraft_version=1.20.6 - yarn_mappings=1.20.6+build.1 - loader_version=0.15.10 + yarn_mappings=1.20.6+build.3 + loader_version=0.15.11 # Mod Properties - mod_version=2.6.0+1.20 + mod_version=3.0.0+1.20 mod_id=reinfshulker maven_group=atonkish.reinfshulker archives_base_name=reinforced-shulker-boxes # Dependencies - fabric_version=0.97.8+1.20.6 - reinforced_core_version=3.1.4+1.20 - reinforced_chests_version=2.4.6+1.20 + fabric_version=0.100.0+1.20.6 + reinforced_core_version=4.0.0+1.20 + reinforced_chests_version=3.0.0+1.20 # quick_shulker_version=1.4.0-1.20 - # shulker_box_tooltip_version=4.0.8+1.20.4 + shulker_box_tooltip_version=4.1.0-alpha.4+1.20.6 # # Quick Shulker deps # shulkerutils_version=1.0.4-1.19 diff --git a/src/client/java/atonkish/reinfshulker/ReinforcedShulkerBoxesClientMod.java b/src/client/java/atonkish/reinfshulker/ReinforcedShulkerBoxesClientMod.java index 4198483..89093f1 100644 --- a/src/client/java/atonkish/reinfshulker/ReinforcedShulkerBoxesClientMod.java +++ b/src/client/java/atonkish/reinfshulker/ReinforcedShulkerBoxesClientMod.java @@ -36,9 +36,9 @@ public void onInitializeReinforcedCoreClient() { // init Reinforced Shulker Boxes initializeReinforcedShulkerBoxesClient(); - // entrypoint: "reinfshulkerclient" + // entrypoint: "reinfshulker-client" FabricLoader.getInstance() - .getEntrypoints(ReinforcedShulkerBoxesMod.MOD_ID + "client", + .getEntrypoints(String.format("%s-client", ReinforcedShulkerBoxesMod.MOD_ID), ReinforcedShulkerBoxesClientModInitializer.class) .forEach(ReinforcedShulkerBoxesClientModInitializer::onInitializeReinforcedShulkerBoxesClient); } diff --git a/src/main/java/atonkish/reinfshulker/gametest/ReinforcedShulkerBoxesModGameTest.java b/src/main/java/atonkish/reinfshulker/gametest/ReinforcedShulkerBoxesModGameTest.java new file mode 100644 index 0000000..86f91a9 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/ReinforcedShulkerBoxesModGameTest.java @@ -0,0 +1,40 @@ +package atonkish.reinfshulker.gametest; + +import java.util.ArrayList; +import java.util.Collection; + +import net.minecraft.test.CustomTestProvider; +import net.minecraft.test.TestFunction; + +import atonkish.reinfshulker.gametest.testcase.AdvancementTests; +import atonkish.reinfshulker.gametest.testcase.CauldronBehaviorTests; +import atonkish.reinfshulker.gametest.testcase.DispenserBehaviorTests; +import atonkish.reinfshulker.gametest.testcase.InventoryTests; +import atonkish.reinfshulker.gametest.testcase.LootTableTests; +import atonkish.reinfshulker.gametest.testcase.OpenTests; +import atonkish.reinfshulker.gametest.testcase.PiglinTests; +import atonkish.reinfshulker.gametest.testcase.PistonBehaviorTests; +import atonkish.reinfshulker.gametest.testcase.RecipeTests; + +public class ReinforcedShulkerBoxesModGameTest { + @CustomTestProvider + public Collection registerTests() { + Collection testFunctions = new ArrayList<>(); + + if (System.getProperty(this.getClass().getPackageName()) == null) { + return testFunctions; + } + + testFunctions.addAll(AdvancementTests.TEST_FUNCTIONS); + testFunctions.addAll(CauldronBehaviorTests.TEST_FUNCTIONS); + testFunctions.addAll(DispenserBehaviorTests.TEST_FUNCTIONS); + testFunctions.addAll(InventoryTests.TEST_FUNCTIONS); + testFunctions.addAll(LootTableTests.TEST_FUNCTIONS); + testFunctions.addAll(OpenTests.TEST_FUNCTIONS); + testFunctions.addAll(PiglinTests.TEST_FUNCTIONS); + testFunctions.addAll(PistonBehaviorTests.TEST_FUNCTIONS); + testFunctions.addAll(RecipeTests.TEST_FUNCTIONS); + + return testFunctions; + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/AdvancementTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/AdvancementTests.java new file mode 100644 index 0000000..5e2efe0 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/AdvancementTests.java @@ -0,0 +1,230 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.advancement.AdvancementEntry; +import net.minecraft.advancement.AdvancementProgress; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.gametest.util.MockServerPlayerHelper; +import atonkish.reinfshulker.item.ModItems; + +public class AdvancementTests { + private static final Map SHULKER_BOX_MAP = new LinkedHashMap<>() { + { + put((DyeColor) null, Items.SHULKER_BOX); + put(DyeColor.WHITE, Items.WHITE_SHULKER_BOX); + put(DyeColor.ORANGE, Items.ORANGE_SHULKER_BOX); + put(DyeColor.MAGENTA, Items.MAGENTA_SHULKER_BOX); + put(DyeColor.LIGHT_BLUE, Items.LIGHT_BLUE_SHULKER_BOX); + put(DyeColor.YELLOW, Items.YELLOW_SHULKER_BOX); + put(DyeColor.LIME, Items.LIME_SHULKER_BOX); + put(DyeColor.PINK, Items.PINK_SHULKER_BOX); + put(DyeColor.GRAY, Items.GRAY_SHULKER_BOX); + put(DyeColor.LIGHT_GRAY, Items.LIGHT_GRAY_SHULKER_BOX); + put(DyeColor.CYAN, Items.CYAN_SHULKER_BOX); + put(DyeColor.PURPLE, Items.PURPLE_SHULKER_BOX); + put(DyeColor.BLUE, Items.BLUE_SHULKER_BOX); + put(DyeColor.BROWN, Items.BROWN_SHULKER_BOX); + put(DyeColor.GREEN, Items.GREEN_SHULKER_BOX); + put(DyeColor.RED, Items.RED_SHULKER_BOX); + put(DyeColor.BLACK, Items.BLACK_SHULKER_BOX); + } + }; + + private static final String BATCH_ID = String.format("%s:AdvancementBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Item item : SHULKER_BOX_MAP.values()) { + add(AdvancementTests.createTest( + String.format("Obtain Copper Shulker Box recipe advancement by having %s", + item.getName().getString()), + item, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/copper_shulker_box"))); + } + add(AdvancementTests.createTest( + "Obtain Copper Shulker Box recipe advancement by having Copper Ingot", + Items.COPPER_INGOT, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/copper_shulker_box"))); + add(AdvancementTests.createTest( + "Obtain Copper Shulker Box recipe advancement by having Copper Chest", + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP.get(ReinforcingMaterials.MAP.get("copper")), + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/copper_shulker_box_from_copper_chest"))); + + // Iron Shulker Box + for (Item item : ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(AdvancementTests.createTest( + String.format("Obtain Iron Shulker Box recipe advancement by having %s", + item.getName().getString()), + item, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/iron_shulker_box"))); + } + add(AdvancementTests.createTest( + "Obtain Iron Shulker Box recipe advancement by having Iron Ingot", + Items.IRON_INGOT, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/iron_shulker_box"))); + add(AdvancementTests.createTest( + "Obtain Iron Shulker Box recipe advancement by having Iron Chest", + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP.get(ReinforcingMaterials.MAP.get("iron")), + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/iron_shulker_box_from_iron_chest"))); + + // Gold Shulker Box + for (Item item : ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(AdvancementTests.createTest( + String.format("Obtain Gold Shulker Box recipe advancement by having %s", + item.getName().getString()), + item, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/gold_shulker_box"))); + } + add(AdvancementTests.createTest( + "Obtain Gold Shulker Box recipe advancement by having Gold Ingot", + Items.GOLD_INGOT, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/gold_shulker_box"))); + add(AdvancementTests.createTest( + "Obtain Gold Shulker Box recipe advancement by having Gold Chest", + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP.get(ReinforcingMaterials.MAP.get("gold")), + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/gold_shulker_box_from_gold_chest"))); + + // Diamond Shulker Box + for (Item item : ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(AdvancementTests.createTest( + String.format("Obtain Diamond Shulker Box recipe advancement by having %s", + item.getName().getString()), + item, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/diamond_shulker_box"))); + } + add(AdvancementTests.createTest( + "Obtain Diamond Shulker Box recipe advancement by having Diamond Ingot", + Items.DIAMOND, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, "recipes/decorations/diamond_shulker_box"))); + add(AdvancementTests.createTest( + "Obtain Diamond Shulker Box recipe advancement by having Diamond Chest", + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP.get(ReinforcingMaterials.MAP.get("diamond")), + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/diamond_shulker_box_from_diamond_chest"))); + + // Netherite Shulker Box + for (Item item : ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(AdvancementTests.createTest( + String.format("Obtain Netherite Shulker Box recipe advancement by having %s", + item.getName().getString()), + item, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/netherite_shulker_box_smithing"))); + } + add(AdvancementTests.createTest( + "Obtain Netherite Shulker Box recipe advancement by having Netherite Ingot", + Items.NETHERITE_INGOT, + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/netherite_shulker_box_smithing"))); + add(AdvancementTests.createTest( + "Obtain Netherite Shulker Box recipe advancement by having Netherite Chest", + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP + .get(ReinforcingMaterials.MAP.get("netherite")), + new Identifier(ReinforcedShulkerBoxesMod.MOD_ID, + "recipes/decorations/netherite_shulker_box_from_netherite_chest"))); + } + }; + + private static TestFunction createTest(String name, Item item, Identifier advancementId) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + AdvancementTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + AdvancementTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + ServerPlayerEntity player = MockServerPlayerHelper.spawn(context, + GameMode.SURVIVAL, Vec3d.of(BlockPos.ORIGIN)); + AdvancementEntry entry = context.getWorld().getServer().getAdvancementLoader().get(advancementId); + AdvancementProgress progress = player.getAdvancementTracker().getProgress(entry); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + Map progressMap = new HashMap(); + String progressMapKeyBeforeHavingItem = "beforeHavingItem"; + String progressMapKeyAfterHavingItem = "afterHavingItem"; + + long tickOrigin = 0; + context.runAtTick(tickOrigin, () -> { + progressMap.put(progressMapKeyBeforeHavingItem, progress.isDone()); + + player.giveItemStack(new ItemStack(item)); + + futurePartialAct1.complete(null); + }); + + long tickObtained = 1; + context.runAtTick(tickObtained, () -> { + progressMap.put(progressMapKeyAfterHavingItem, progress.isDone()); + + futurePartialAct2.complete(null); + }); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.assertFalse( + progressMap.get(progressMapKeyBeforeHavingItem), String.format( + "Expected that advancement %s has not been done yet, but it has been already done.", + entry)); + context.assertTrue( + progressMap.get(progressMapKeyAfterHavingItem), String.format( + "Expected that advancement %s has been done, but it has not been done yet.", + entry)); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } finally { + MockServerPlayerHelper.destroy(context, player); + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/CauldronBehaviorTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/CauldronBehaviorTests.java new file mode 100644 index 0000000..cb3183c --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/CauldronBehaviorTests.java @@ -0,0 +1,172 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stat; +import net.minecraft.stat.Stats; +import net.minecraft.state.property.Properties; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.DyeColor; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; +import atonkish.reinfshulker.block.ReinforcedShulkerBoxBlock; +import atonkish.reinfshulker.gametest.util.MockServerPlayerHelper; +import atonkish.reinfshulker.item.ModItems; +import atonkish.reinfshulker.stat.ModStats; + +public class CauldronBehaviorTests { + private static final String BATCH_ID = String.format("%s:CauldronBehaviorBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (DyeColor color : DyeColor.values()) { + ReinforcedShulkerBoxBlock shulkerBoxBlock = (ReinforcedShulkerBoxBlock) ModBlocks.REINFORCED_SHULKER_BOX_MAP + .get(ReinforcingMaterials.MAP.get("copper")).get(color); + + add(CauldronBehaviorTests.createTest( + String.format("Clean %s", shulkerBoxBlock.getName().getString()), + shulkerBoxBlock)); + } + + // Iron Shulker Box + for (DyeColor color : DyeColor.values()) { + ReinforcedShulkerBoxBlock shulkerBoxBlock = (ReinforcedShulkerBoxBlock) ModBlocks.REINFORCED_SHULKER_BOX_MAP + .get(ReinforcingMaterials.MAP.get("iron")).get(color); + + add(CauldronBehaviorTests.createTest( + String.format("Clean %s", shulkerBoxBlock.getName().getString()), + shulkerBoxBlock)); + } + + // Gold Shulker Box + for (DyeColor color : DyeColor.values()) { + ReinforcedShulkerBoxBlock shulkerBoxBlock = (ReinforcedShulkerBoxBlock) ModBlocks.REINFORCED_SHULKER_BOX_MAP + .get(ReinforcingMaterials.MAP.get("gold")).get(color); + + add(CauldronBehaviorTests.createTest( + String.format("Clean %s", shulkerBoxBlock.getName().getString()), + shulkerBoxBlock)); + } + + // Diamond Shulker Box + for (DyeColor color : DyeColor.values()) { + ReinforcedShulkerBoxBlock shulkerBoxBlock = (ReinforcedShulkerBoxBlock) ModBlocks.REINFORCED_SHULKER_BOX_MAP + .get(ReinforcingMaterials.MAP.get("diamond")).get(color); + + add(CauldronBehaviorTests.createTest( + String.format("Clean %s", shulkerBoxBlock.getName().getString()), + shulkerBoxBlock)); + } + + // Netherite Shulker Box + for (DyeColor color : DyeColor.values()) { + ReinforcedShulkerBoxBlock shulkerBoxBlock = (ReinforcedShulkerBoxBlock) ModBlocks.REINFORCED_SHULKER_BOX_MAP + .get(ReinforcingMaterials.MAP.get("netherite")).get(color); + + add(CauldronBehaviorTests.createTest( + String.format("Clean %s", shulkerBoxBlock.getName().getString()), + shulkerBoxBlock)); + } + } + }; + + private static TestFunction createTest(String name, ReinforcedShulkerBoxBlock shulkerBoxBlock) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + CauldronBehaviorTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + CauldronBehaviorTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, Blocks.WATER_CAULDRON + .getDefaultState().with(Properties.LEVEL_3, 3)); + + ServerPlayerEntity player = MockServerPlayerHelper.spawn(context, + GameMode.SURVIVAL, Vec3d.of(blockPos.south(4))); + player.setStackInHand(Hand.MAIN_HAND, new ItemStack(shulkerBoxBlock.asItem())); + + Stat stat = Stats.CUSTOM + .getOrCreateStat( + ModStats.CLEAN_REINFORCED_SHULKER_BOX_MAP.get(shulkerBoxBlock.getMaterial())); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + Map statMap = new HashMap(); + String statMapKeyBeforeCleaning = "beforeCleaning"; + String statMapKeyAfterCleaning = "afterCleaning"; + + long tickOrigin = 0; + context.runAtTick(tickOrigin, () -> { + statMap.put(statMapKeyBeforeCleaning, player.getStatHandler().getStat(stat)); + + context.useBlock(blockPos, player); + + futurePartialAct1.complete(null); + }); + + long tickShulkerBoxCleaning = 1; + context.runAtTick(tickShulkerBoxCleaning, () -> { + statMap.put(statMapKeyAfterCleaning, player.getStatHandler().getStat(stat)); + + futurePartialAct2.complete(null); + }); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.assertEquals( + player.getMainHandStack().getItem(), ModItems.REINFORCED_SHULKER_BOX_MAP + .get(shulkerBoxBlock.getMaterial()).get((DyeColor) null), + "main hand item"); + context.assertEquals(context.getBlockState(blockPos).get(Properties.LEVEL_3), 2, + "fluid level"); + context.assertEquals( + statMap.get(statMapKeyAfterCleaning) - statMap.get(statMapKeyBeforeCleaning), 1, + String.format("diff %s value", stat.getName())); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } finally { + MockServerPlayerHelper.destroy(context, player); + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/DispenserBehaviorTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/DispenserBehaviorTests.java new file mode 100644 index 0000000..d4d9ba0 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/DispenserBehaviorTests.java @@ -0,0 +1,123 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.block.DispenserBlock; +import net.minecraft.block.entity.DispenserBlockEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; + +public class DispenserBehaviorTests { + private static final String BATCH_ID = String.format("%s:DispenserBehaviorBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(DispenserBehaviorTests.createTest( + String.format("Dispense %s", block.getName().getString()), block)); + } + + // Iron Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(DispenserBehaviorTests.createTest( + String.format("Dispense %s", block.getName().getString()), block)); + } + + // Gold Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(DispenserBehaviorTests.createTest( + String.format("Dispense %s", block.getName().getString()), block)); + } + + // Diamond Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(DispenserBehaviorTests.createTest( + String.format("Dispense %s", block.getName().getString()), block)); + } + + // Netherite Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .values()) { + add(DispenserBehaviorTests.createTest( + String.format("Dispense %s", block.getName().getString()), block)); + } + } + }; + + private static TestFunction createTest(String name, Block shulkerBoxBlock) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + DispenserBehaviorTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + DispenserBehaviorTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, Blocks.DISPENSER + .getDefaultState().with(DispenserBlock.FACING, Direction.SOUTH)); + + DispenserBlockEntity entity = (DispenserBlockEntity) context.getBlockEntity(blockPos); + entity.setStack(0, new ItemStack(shulkerBoxBlock.asItem())); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + long tickOrigin = 0; + context.runAtTick(tickOrigin, () -> { + context.putAndRemoveRedstoneBlock(blockPos.up(1), 0); + + futurePartialAct1.complete(null); + }); + + long tickShulkerBoxPlaced = 4; + context.runAtTick(tickShulkerBoxPlaced, () -> { + futurePartialAct2.complete(null); + }); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.expectBlock(shulkerBoxBlock, blockPos.south(1)); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/InventoryTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/InventoryTests.java new file mode 100644 index 0000000..a66e2dc --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/InventoryTests.java @@ -0,0 +1,110 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Block; +import net.minecraft.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.math.BlockPos; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; + +public class InventoryTests { + private static final String BATCH_ID = String.format("%s:InventoryBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(InventoryTests.createTest( + String.format("%s inventory size", block.getName().getString()), + block, + 45)); + } + + // Iron Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(InventoryTests.createTest( + String.format("%s inventory size", block.getName().getString()), + block, + 54)); + } + + // Gold Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(InventoryTests.createTest( + String.format("%s inventory size", block.getName().getString()), + block, + 81)); + } + + // Diamond Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(InventoryTests.createTest( + String.format("%s inventory size", block.getName().getString()), + block, + 108)); + } + + // Netherite Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .values()) { + add(InventoryTests.createTest( + String.format("%s inventory size", block.getName().getString()), + block, + 108)); + } + } + }; + + private static TestFunction createTest(String name, Block shulkerBoxBlock, int size) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + InventoryTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + InventoryTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, shulkerBoxBlock); + + // Act + ShulkerBoxBlockEntity entity = (ShulkerBoxBlockEntity) context.getBlockEntity(blockPos); + + // Assert + try { + context.assertEquals(entity.size(), size, + String.format("%s inventory size", shulkerBoxBlock.getName().getString())); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } + + context.complete(); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/LootTableTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/LootTableTests.java new file mode 100644 index 0000000..3a6714a --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/LootTableTests.java @@ -0,0 +1,213 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; +import atonkish.reinfshulker.gametest.util.MockServerPlayerHelper; + +public class LootTableTests { + private static final String BATCH_ID = String.format("%s:LootTableBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(LootTableTests.createTest( + String.format("Break %s with Netherite Pickaxe", block.getName().getString()), + block, + Items.NETHERITE_PICKAXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s with Netherite Axe", block.getName().getString()), + block, + Items.NETHERITE_AXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s without tools", block.getName().getString()), + block, + Items.AIR, + true)); + } + + // Iron Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(LootTableTests.createTest( + String.format("Break %s with Netherite Pickaxe", block.getName().getString()), + block, + Items.NETHERITE_PICKAXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s with Netherite Axe", block.getName().getString()), + block, + Items.NETHERITE_AXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s without tools", block.getName().getString()), + block, + Items.AIR, + true)); + } + + // Gold Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(LootTableTests.createTest( + String.format("Break %s with Netherite Pickaxe", block.getName().getString()), + block, + Items.NETHERITE_PICKAXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s with Netherite Axe", block.getName().getString()), + block, + Items.NETHERITE_AXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s without tools", block.getName().getString()), + block, + Items.AIR, + true)); + } + + // Diamond Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(LootTableTests.createTest( + String.format("Break %s with Netherite Pickaxe", block.getName().getString()), + block, + Items.NETHERITE_PICKAXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s with Netherite Axe", block.getName().getString()), + block, + Items.NETHERITE_AXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s without tools", block.getName().getString()), + block, + Items.AIR, + true)); + } + + // Netherite Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .values()) { + add(LootTableTests.createTest( + String.format("Break %s with Netherite Pickaxe", block.getName().getString()), + block, + Items.NETHERITE_PICKAXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s with Netherite Axe", block.getName().getString()), + block, + Items.NETHERITE_AXE, + true)); + add(LootTableTests.createTest( + String.format("Break %s without tools", block.getName().getString()), + block, + Items.AIR, + true)); + } + } + }; + + private static TestFunction createTest(String name, Block shulkerBoxBlock, Item tool, boolean shouldDrop) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + LootTableTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + LootTableTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 1000, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, shulkerBoxBlock); + + ServerPlayerEntity player = MockServerPlayerHelper.spawn(context, + GameMode.SURVIVAL, Vec3d.of(blockPos.south(4))); + player.setStackInHand(Hand.MAIN_HAND, new ItemStack(tool)); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + long tickOrigin = 0; + context.runAtTick(tickOrigin, () -> { + player.interactionManager.processBlockBreakingAction( + context.getAbsolutePos(blockPos), PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, + Direction.NORTH, context.getWorld().getTopY(), 0); + + futurePartialAct1.complete(null); + }); + + long tickBlockBreaking = (long) Math.ceil( + 1.0D / context.getBlockState(blockPos).calcBlockBreakingDelta(player, + context.getWorld(), blockPos)); + context.runAtTick(tickBlockBreaking, () -> { + player.interactionManager.processBlockBreakingAction( + context.getAbsolutePos(blockPos), + PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, + Direction.NORTH, context.getWorld().getTopY(), 0); + + futurePartialAct2.complete(null); + }); + + ReinforcedShulkerBoxesMod.LOGGER.info("[{}] {} can be mined in {} ticks by {}", + testName, + shulkerBoxBlock.getName().getString(), + tickBlockBreaking, + tool.getName().getString()); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.expectBlock(Blocks.AIR, blockPos); + context.expectEntitiesAround(EntityType.ITEM, blockPos, shouldDrop ? 1 : 0, 1); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } finally { + MockServerPlayerHelper.destroy(context, player); + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/OpenTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/OpenTests.java new file mode 100644 index 0000000..9f533f4 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/OpenTests.java @@ -0,0 +1,149 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Block; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stat; +import net.minecraft.stat.Stats; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; +import atonkish.reinfshulker.block.ReinforcedShulkerBoxBlock; +import atonkish.reinfshulker.gametest.util.MockServerPlayerHelper; +import atonkish.reinfshulker.stat.ModStats; + +public class OpenTests { + private static final String BATCH_ID = String.format("%s:OpenBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(OpenTests.createTest( + String.format("Open %s", block.getName().getString()), + (ReinforcedShulkerBoxBlock) block)); + } + + // Iron Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(OpenTests.createTest( + String.format("Open %s", block.getName().getString()), + (ReinforcedShulkerBoxBlock) block)); + } + + // Gold Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(OpenTests.createTest( + String.format("Open %s", block.getName().getString()), + (ReinforcedShulkerBoxBlock) block)); + } + + // Diamond Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(OpenTests.createTest( + String.format("Open %s", block.getName().getString()), + (ReinforcedShulkerBoxBlock) block)); + } + + // Netherite Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .values()) { + add(OpenTests.createTest( + String.format("Open %s", block.getName().getString()), + (ReinforcedShulkerBoxBlock) block)); + } + } + }; + + private static TestFunction createTest(String name, ReinforcedShulkerBoxBlock shulkerBoxBlock) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + OpenTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + OpenTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, shulkerBoxBlock); + + ServerPlayerEntity player = MockServerPlayerHelper.spawn(context, + GameMode.SURVIVAL, Vec3d.of(blockPos.south(4))); + + Stat stat = Stats.CUSTOM + .getOrCreateStat( + ModStats.OPEN_REINFORCED_SHULKER_BOX_MAP.get(shulkerBoxBlock.getMaterial())); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + Map statMap = new HashMap(); + String statMapKeyBeforeOpening = "beforeOpening"; + String statMapKeyAfterOpening = "afterOpening"; + + long tickOrigin = 0; + context.runAtTick(tickOrigin, () -> { + statMap.put(statMapKeyBeforeOpening, player.getStatHandler().getStat(stat)); + + context.useBlock(blockPos, player); + + futurePartialAct1.complete(null); + }); + + long tickShulkerBoxOpening = 1; + context.runAtTick(tickShulkerBoxOpening, () -> { + statMap.put(statMapKeyAfterOpening, player.getStatHandler().getStat(stat)); + + futurePartialAct2.complete(null); + }); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.assertEquals( + statMap.get(statMapKeyAfterOpening) - statMap.get(statMapKeyBeforeOpening), 1, + String.format("diff %s value", stat.getName())); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } finally { + MockServerPlayerHelper.destroy(context, player); + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/PiglinTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/PiglinTests.java new file mode 100644 index 0000000..2829879 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/PiglinTests.java @@ -0,0 +1,155 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Block; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ai.brain.MemoryModuleType; +import net.minecraft.entity.mob.PiglinEntity; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; +import atonkish.reinfshulker.gametest.util.MockServerPlayerHelper; + +public class PiglinTests { + private static final String BATCH_ID = String.format("%s:PiglinBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(PiglinTests.createTest( + String.format("Piglin get angry after opening %s", block.getName().getString()), + block)); + } + + // Iron Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(PiglinTests.createTest( + String.format("Piglin get angry after opening %s", block.getName().getString()), + block)); + } + + // Gold Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(PiglinTests.createTest( + String.format("Piglin get angry after opening %s", block.getName().getString()), + block)); + } + + // Diamond Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(PiglinTests.createTest( + String.format("Piglin get angry after opening %s", block.getName().getString()), + block)); + } + + // Netherite Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .values()) { + add(PiglinTests.createTest( + String.format("Piglin get angry after opening %s", block.getName().getString()), + block)); + } + } + }; + + private static TestFunction createTest(String name, Block shulkerBoxBlock) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + PiglinTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + PiglinTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, shulkerBoxBlock); + + ServerPlayerEntity player = MockServerPlayerHelper.spawn(context, + GameMode.SURVIVAL, Vec3d.of(blockPos.south(4))); + ArmorItem armor = (ArmorItem) Items.GOLDEN_CHESTPLATE; + player.equipStack(armor.getSlotType(), new ItemStack(armor)); + + PiglinEntity piglin = context.spawnMob(EntityType.PIGLIN, blockPos.east(1)); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + Map angryAtMap = new HashMap(); + String angryAtMapKeyBeforeAngryAtPlayer = "beforeAngryAtPlayer"; + String angryAtMapKeyAfterAngryAtPlayer = "afterAngryAtPlayer"; + + long tickChestOpen = 20; + context.runAtTick(tickChestOpen, () -> { + angryAtMap.put(angryAtMapKeyBeforeAngryAtPlayer, + piglin.getBrain().hasMemoryModuleWithValue(MemoryModuleType.ANGRY_AT, + player.getUuid())); + + context.useBlock(blockPos, player); + + futurePartialAct1.complete(null); + }); + + long tickAngryAtPlayer = 21; + context.runAtTick(tickAngryAtPlayer, () -> { + angryAtMap.put(angryAtMapKeyAfterAngryAtPlayer, + piglin.getBrain().hasMemoryModuleWithValue(MemoryModuleType.ANGRY_AT, + player.getUuid())); + + futurePartialAct2.complete(null); + }); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.assertFalse(angryAtMap.get(angryAtMapKeyBeforeAngryAtPlayer), + "Expected that the piglin is not angry at player, but it has been already angry."); + context.assertTrue(angryAtMap.get(angryAtMapKeyAfterAngryAtPlayer), + "Expected that the piglin is angry at player, but it has not been angry yet."); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } finally { + MockServerPlayerHelper.destroy(context, player); + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/PistonBehaviorTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/PistonBehaviorTests.java new file mode 100644 index 0000000..4b02e9c --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/PistonBehaviorTests.java @@ -0,0 +1,117 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.math.BlockPos; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.block.ModBlocks; + +public class PistonBehaviorTests { + private static final String BATCH_ID = String.format("%s:PistonBehaviorBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .values()) { + add(PistonBehaviorTests.createTest( + String.format("Piston breaks %s", block.getName().getString()), block)); + } + + // Iron Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .values()) { + add(PistonBehaviorTests.createTest( + String.format("Piston breaks %s", block.getName().getString()), block)); + } + + // Gold Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .values()) { + add(PistonBehaviorTests.createTest( + String.format("Piston breaks %s", block.getName().getString()), block)); + } + + // Diamond Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .values()) { + add(PistonBehaviorTests.createTest( + String.format("Piston breaks %s", block.getName().getString()), block)); + } + + // Netherite Shulker Box + for (Block block : ModBlocks.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .values()) { + add(PistonBehaviorTests.createTest( + String.format("Piston breaks %s", block.getName().getString()), block)); + } + } + }; + + private static TestFunction createTest(String name, Block shulkerBoxBlock) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + PistonBehaviorTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + PistonBehaviorTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + BlockPos blockPos = BlockPos.ORIGIN; + context.setBlockState(blockPos, shulkerBoxBlock); + context.setBlockState(blockPos.south(1), Blocks.PISTON); + + // Act + CompletableFuture futurePartialAct1 = new CompletableFuture<>(); + CompletableFuture futurePartialAct2 = new CompletableFuture<>(); + + long tickOrigin = 0; + context.runAtTick(tickOrigin, () -> { + context.putAndRemoveRedstoneBlock(blockPos.south(1).up(1), 1); + + futurePartialAct1.complete(null); + }); + + long tickShulkerBoxBreaking = 2; + context.runAtTick(tickShulkerBoxBreaking, () -> { + futurePartialAct2.complete(null); + }); + + // Assert + CompletableFuture.allOf(futurePartialAct1, futurePartialAct2).thenRun(() -> { + try { + context.expectBlock(Blocks.AIR, blockPos); + context.expectItemAt(shulkerBoxBlock.asItem(), blockPos, 1); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } + + context.complete(); + }); + }); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/testcase/RecipeTests.java b/src/main/java/atonkish/reinfshulker/gametest/testcase/RecipeTests.java new file mode 100644 index 0000000..afd9d36 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/testcase/RecipeTests.java @@ -0,0 +1,471 @@ +package atonkish.reinfshulker.gametest.testcase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; + +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.ContainerComponent; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.RecipeInputInventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.DyeItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeManager; +import net.minecraft.recipe.RecipeType; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.test.StructureTestUtil; +import net.minecraft.test.TestFunction; +import net.minecraft.util.DyeColor; + +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.ReinforcedShulkerBoxesMod; +import atonkish.reinfshulker.gametest.util.VoidScreenHander; +import atonkish.reinfshulker.item.ModItems; + +public class RecipeTests { + private static final Map SHULKER_BOX_MAP = new LinkedHashMap<>() { + { + put((DyeColor) null, Items.SHULKER_BOX); + put(DyeColor.WHITE, Items.WHITE_SHULKER_BOX); + put(DyeColor.ORANGE, Items.ORANGE_SHULKER_BOX); + put(DyeColor.MAGENTA, Items.MAGENTA_SHULKER_BOX); + put(DyeColor.LIGHT_BLUE, Items.LIGHT_BLUE_SHULKER_BOX); + put(DyeColor.YELLOW, Items.YELLOW_SHULKER_BOX); + put(DyeColor.LIME, Items.LIME_SHULKER_BOX); + put(DyeColor.PINK, Items.PINK_SHULKER_BOX); + put(DyeColor.GRAY, Items.GRAY_SHULKER_BOX); + put(DyeColor.LIGHT_GRAY, Items.LIGHT_GRAY_SHULKER_BOX); + put(DyeColor.CYAN, Items.CYAN_SHULKER_BOX); + put(DyeColor.PURPLE, Items.PURPLE_SHULKER_BOX); + put(DyeColor.BLUE, Items.BLUE_SHULKER_BOX); + put(DyeColor.BROWN, Items.BROWN_SHULKER_BOX); + put(DyeColor.GREEN, Items.GREEN_SHULKER_BOX); + put(DyeColor.RED, Items.RED_SHULKER_BOX); + put(DyeColor.BLACK, Items.BLACK_SHULKER_BOX); + } + }; + + private static final String BATCH_ID = String.format("%s:RecipeBatch", + ReinforcedShulkerBoxesMod.MOD_ID); + + public static final Collection TEST_FUNCTIONS = new ArrayList<>() { + { + // Copper Shulker Box + for (DyeColor color : SHULKER_BOX_MAP.keySet()) { + ItemStack baseShulkerBox = new ItemStack(SHULKER_BOX_MAP.get(color)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack material = new ItemStack(Items.COPPER_INGOT); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")).get(color)); + shulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Craft %s", baseShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + material, material, material, + material, baseShulkerBox, material, + material, material, material), + shulkerBox)); + } + + for (DyeColor baseColor : SHULKER_BOX_MAP.keySet()) { + for (DyeColor dyeColor : DyeColor.values()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .get(baseColor)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack dye = new ItemStack(DyeItem.byColor(dyeColor)); + ItemStack dyedShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .get(dyeColor)); + dyedShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Coloring from %s to %s", + baseShulkerBox.getItem().getName().getString(), + dyedShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + baseShulkerBox, dye, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY), + dyedShulkerBox)); + } + } + + { + ItemStack chest = new ItemStack( + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP + .get(ReinforcingMaterials.MAP.get("copper"))); + ItemStack shell = new ItemStack(Items.SHULKER_SHELL); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")) + .get((DyeColor) null)); + + add(RecipeTests.createTest( + String.format("Craft %s from %s", + shulkerBox.getItem().getName().getString(), + chest.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + shell, ItemStack.EMPTY, ItemStack.EMPTY, + chest, ItemStack.EMPTY, ItemStack.EMPTY, + shell, ItemStack.EMPTY, ItemStack.EMPTY), + shulkerBox)); + } + + // Iron Shulker Box + for (DyeColor color : SHULKER_BOX_MAP.keySet()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("copper")).get(color)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack material = new ItemStack(Items.IRON_INGOT); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")).get(color)); + shulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Craft %s", baseShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + material, material, material, + material, baseShulkerBox, material, + material, material, material), + shulkerBox)); + } + + for (DyeColor baseColor : SHULKER_BOX_MAP.keySet()) { + for (DyeColor dyeColor : DyeColor.values()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .get(baseColor)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack dye = new ItemStack(DyeItem.byColor(dyeColor)); + ItemStack dyedShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .get(dyeColor)); + dyedShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Coloring from %s to %s", + baseShulkerBox.getItem().getName().getString(), + dyedShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + baseShulkerBox, dye, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY), + dyedShulkerBox)); + } + } + + { + ItemStack chest = new ItemStack( + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP + .get(ReinforcingMaterials.MAP.get("iron"))); + ItemStack shell = new ItemStack(Items.SHULKER_SHELL); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")) + .get((DyeColor) null)); + + add(RecipeTests.createTest( + String.format("Craft %s from %s", + shulkerBox.getItem().getName().getString(), + chest.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + shell, ItemStack.EMPTY, ItemStack.EMPTY, + chest, ItemStack.EMPTY, ItemStack.EMPTY, + shell, ItemStack.EMPTY, ItemStack.EMPTY), + shulkerBox)); + } + + // Gold Shulker Box + for (DyeColor color : SHULKER_BOX_MAP.keySet()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("iron")).get(color)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack material = new ItemStack(Items.GOLD_INGOT); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")).get(color)); + shulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Craft %s", baseShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + material, material, material, + material, baseShulkerBox, material, + material, material, material), + shulkerBox)); + } + + for (DyeColor baseColor : SHULKER_BOX_MAP.keySet()) { + for (DyeColor dyeColor : DyeColor.values()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .get(baseColor)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack dye = new ItemStack(DyeItem.byColor(dyeColor)); + ItemStack dyedShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .get(dyeColor)); + dyedShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Coloring from %s to %s", + baseShulkerBox.getItem().getName().getString(), + dyedShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + baseShulkerBox, dye, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY), + dyedShulkerBox)); + } + } + + { + ItemStack chest = new ItemStack( + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP + .get(ReinforcingMaterials.MAP.get("gold"))); + ItemStack shell = new ItemStack(Items.SHULKER_SHELL); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")) + .get((DyeColor) null)); + + add(RecipeTests.createTest( + String.format("Craft %s from %s", + shulkerBox.getItem().getName().getString(), + chest.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + shell, ItemStack.EMPTY, ItemStack.EMPTY, + chest, ItemStack.EMPTY, ItemStack.EMPTY, + shell, ItemStack.EMPTY, ItemStack.EMPTY), + shulkerBox)); + } + + // Diamond Shulker Box + for (DyeColor color : SHULKER_BOX_MAP.keySet()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("gold")).get(color)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack material = new ItemStack(Items.DIAMOND); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")).get(color)); + shulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Craft %s", baseShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + material, material, material, + material, baseShulkerBox, material, + material, material, material), + shulkerBox)); + } + + for (DyeColor baseColor : SHULKER_BOX_MAP.keySet()) { + for (DyeColor dyeColor : DyeColor.values()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .get(baseColor)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack dye = new ItemStack(DyeItem.byColor(dyeColor)); + ItemStack dyedShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .get(dyeColor)); + dyedShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Coloring from %s to %s", + baseShulkerBox.getItem().getName().getString(), + dyedShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + baseShulkerBox, dye, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY), + dyedShulkerBox)); + } + } + + { + ItemStack chest = new ItemStack( + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP + .get(ReinforcingMaterials.MAP.get("diamond"))); + ItemStack shell = new ItemStack(Items.SHULKER_SHELL); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")) + .get((DyeColor) null)); + + add(RecipeTests.createTest( + String.format("Craft %s from %s", + shulkerBox.getItem().getName().getString(), + chest.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + shell, ItemStack.EMPTY, ItemStack.EMPTY, + chest, ItemStack.EMPTY, ItemStack.EMPTY, + shell, ItemStack.EMPTY, ItemStack.EMPTY), + shulkerBox)); + } + + // Netherite Shulker Box + for (DyeColor color : SHULKER_BOX_MAP.keySet()) { + ItemStack template = new ItemStack(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE); + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("diamond")).get(color)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack material = new ItemStack(Items.NETHERITE_INGOT); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")).get(color)); + shulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Smithing %s", baseShulkerBox.getItem().getName().getString()), + RecipeType.SMITHING, + new SimpleInventory(template, baseShulkerBox, material), + shulkerBox)); + } + + for (DyeColor baseColor : SHULKER_BOX_MAP.keySet()) { + for (DyeColor dyeColor : DyeColor.values()) { + ItemStack baseShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .get(baseColor)); + baseShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + ItemStack dye = new ItemStack(DyeItem.byColor(dyeColor)); + ItemStack dyedShulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .get(dyeColor)); + dyedShulkerBox.set(DataComponentTypes.CONTAINER, + ContainerComponent.fromStacks(List.of(new ItemStack(Items.DIRT)))); + + add(RecipeTests.createTest( + String.format("Coloring from %s to %s", + baseShulkerBox.getItem().getName().getString(), + dyedShulkerBox.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + baseShulkerBox, dye, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY), + dyedShulkerBox)); + } + } + + { + ItemStack chest = new ItemStack( + atonkish.reinfchest.item.ModItems.REINFORCED_CHEST_MAP + .get(ReinforcingMaterials.MAP.get("netherite"))); + ItemStack shell = new ItemStack(Items.SHULKER_SHELL); + ItemStack shulkerBox = new ItemStack( + ModItems.REINFORCED_SHULKER_BOX_MAP.get(ReinforcingMaterials.MAP.get("netherite")) + .get((DyeColor) null)); + + add(RecipeTests.createTest( + String.format("Craft %s from %s", + shulkerBox.getItem().getName().getString(), + chest.getItem().getName().getString()), + RecipeType.CRAFTING, + RecipeTests.create3x3CraftingInventory( + shell, ItemStack.EMPTY, ItemStack.EMPTY, + chest, ItemStack.EMPTY, ItemStack.EMPTY, + shell, ItemStack.EMPTY, ItemStack.EMPTY), + shulkerBox)); + } + } + }; + + private static > TestFunction createTest( + String name, RecipeType type, C inventory, ItemStack expected) { + String testName = String.format("%s %s %s", + ReinforcedShulkerBoxesMod.MOD_ID, + RecipeTests.class.getSimpleName(), + name) + .replace(" ", "_"); + + return new TestFunction( + RecipeTests.BATCH_ID, + testName, + FabricGameTest.EMPTY_STRUCTURE, + StructureTestUtil.getRotation(0), + 100, + 0L, + true, + false, + 1, + 1, + false, + (context) -> { + // Arrange + ServerWorld world = context.getWorld(); + RecipeManager recipeManager = world.getRecipeManager(); + DynamicRegistryManager registryManager = world.getRegistryManager(); + T recipe = recipeManager.getFirstMatch(type, inventory, world).orElseThrow().value(); + + // Act + ItemStack actual = recipe.craft(inventory, registryManager); + + // Assert + try { + context.assertTrue(ItemStack.areEqual(actual, expected), + "Recipe result differs from expected."); + } catch (Exception e) { + ReinforcedShulkerBoxesMod.LOGGER.error("[{}] {}", testName, e.getMessage()); + throw e; + } + + context.complete(); + }); + } + + private static RecipeInputInventory create3x3CraftingInventory( + ItemStack stack1, ItemStack stack2, ItemStack stack3, + ItemStack stack4, ItemStack stack5, ItemStack stack6, + ItemStack stack7, ItemStack stack8, ItemStack stack9) { + RecipeInputInventory inventory = new CraftingInventory(new VoidScreenHander(), 3, 3); + inventory.setStack(0, stack1); + inventory.setStack(1, stack2); + inventory.setStack(2, stack3); + inventory.setStack(3, stack4); + inventory.setStack(4, stack5); + inventory.setStack(5, stack6); + inventory.setStack(6, stack7); + inventory.setStack(7, stack8); + inventory.setStack(8, stack9); + return inventory; + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/util/MockServerPlayerHelper.java b/src/main/java/atonkish/reinfshulker/gametest/util/MockServerPlayerHelper.java new file mode 100644 index 0000000..5d0eb00 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/util/MockServerPlayerHelper.java @@ -0,0 +1,46 @@ +package atonkish.reinfshulker.gametest.util; + +import net.minecraft.network.ClientConnection; +import net.minecraft.network.NetworkSide; +import net.minecraft.server.network.ConnectedClientData; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.test.TestContext; +import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.GameMode; + +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +import com.mojang.authlib.GameProfile; + +import io.netty.channel.embedded.EmbeddedChannel; + +public class MockServerPlayerHelper { + private static AtomicInteger playerId = new AtomicInteger(1); + + public static ServerPlayerEntity spawn(TestContext context, GameMode gameMode, Vec3d pos) { + ConnectedClientData data = ConnectedClientData + .createDefault( + new GameProfile(UUID.randomUUID(), String.format("player-%d", playerId.getAndIncrement())), + false); + ServerPlayerEntity player = new ServerPlayerEntity(context.getWorld().getServer(), context.getWorld(), + data.gameProfile(), data.syncedOptions()); + ClientConnection connection = new ClientConnection(NetworkSide.SERVERBOUND); + new EmbeddedChannel(connection); + context.getWorld().getServer().getPlayerManager().onPlayerConnect(connection, player, data); + + player.changeGameMode(gameMode); + player.setPosition(context.getAbsolute(pos)); + player.setOnGround(true); + + return player; + } + + public static void destroy(TestContext context, ServerPlayerEntity player) { + player.discard(); + player.getInventory().clear(); + player.networkHandler.disconnect(Text.of(String.format("%s (%s) left the game", + player.getGameProfile().getName(), player.getUuidAsString()))); + } +} diff --git a/src/main/java/atonkish/reinfshulker/gametest/util/VoidScreenHander.java b/src/main/java/atonkish/reinfshulker/gametest/util/VoidScreenHander.java new file mode 100644 index 0000000..c709742 --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/gametest/util/VoidScreenHander.java @@ -0,0 +1,21 @@ +package atonkish.reinfshulker.gametest.util; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; + +public class VoidScreenHander extends ScreenHandler { + public VoidScreenHander() { + super(null, 0); + } + + @Override + public ItemStack quickMove(PlayerEntity player, int index) { + throw new UnsupportedOperationException("not implemented"); + }; + + @Override + public boolean canUse(PlayerEntity player) { + throw new UnsupportedOperationException("not implemented"); + }; +} diff --git a/src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ReinforcedShulkerBoxPreviewProvider.java b/src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ReinforcedShulkerBoxPreviewProvider.java new file mode 100644 index 0000000..4803b4b --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ReinforcedShulkerBoxPreviewProvider.java @@ -0,0 +1,69 @@ +package atonkish.reinfshulker.integration.shulkerboxtooltip; + +import com.misterpemodder.shulkerboxtooltip.api.PreviewContext; +import com.misterpemodder.shulkerboxtooltip.api.color.ColorKey; +import com.misterpemodder.shulkerboxtooltip.api.provider.BlockEntityPreviewProvider; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +import net.minecraft.block.Block; +import net.minecraft.util.DyeColor; + +import atonkish.reinfcore.util.ReinforcingMaterial; +import atonkish.reinfshulker.block.ReinforcedShulkerBoxBlock; + +public class ReinforcedShulkerBoxPreviewProvider extends BlockEntityPreviewProvider { + protected final int maxRowSize; + private final ReinforcingMaterial material; + + public ReinforcedShulkerBoxPreviewProvider(ReinforcingMaterial material) { + super(material.getSize(), true); + + int size = material.getSize(); + this.maxRowSize = size <= 81 ? 9 : size / 9; + + this.material = material; + } + + @Override + public boolean showTooltipHints(PreviewContext context) { + return true; + } + + @Override + @Environment(EnvType.CLIENT) + public ColorKey getWindowColorKey(PreviewContext context) { + DyeColor dye = ((ReinforcedShulkerBoxBlock) Block.getBlockFromItem(context.stack().getItem())).getColor(); + + if (dye == null) + return ColorKey.SHULKER_BOX; + return switch (dye) { + case ORANGE -> ColorKey.ORANGE_SHULKER_BOX; + case MAGENTA -> ColorKey.MAGENTA_SHULKER_BOX; + case LIGHT_BLUE -> ColorKey.LIGHT_BLUE_SHULKER_BOX; + case YELLOW -> ColorKey.YELLOW_SHULKER_BOX; + case LIME -> ColorKey.LIME_SHULKER_BOX; + case PINK -> ColorKey.PINK_SHULKER_BOX; + case GRAY -> ColorKey.GRAY_SHULKER_BOX; + case LIGHT_GRAY -> ColorKey.LIGHT_GRAY_SHULKER_BOX; + case CYAN -> ColorKey.CYAN_SHULKER_BOX; + case PURPLE -> ColorKey.PURPLE_SHULKER_BOX; + case BLUE -> ColorKey.BLUE_SHULKER_BOX; + case BROWN -> ColorKey.BROWN_SHULKER_BOX; + case GREEN -> ColorKey.GREEN_SHULKER_BOX; + case RED -> ColorKey.RED_SHULKER_BOX; + case BLACK -> ColorKey.BLACK_SHULKER_BOX; + default -> ColorKey.WHITE_SHULKER_BOX; + }; + } + + @Override + public int getMaxRowSize(PreviewContext context) { + return this.maxRowSize; + } + + public ReinforcingMaterial getMaterial() { + return this.material; + } +} diff --git a/src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ShulkerBoxTooltip.java b/src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ShulkerBoxTooltip.java new file mode 100644 index 0000000..0349c0b --- /dev/null +++ b/src/main/java/atonkish/reinfshulker/integration/shulkerboxtooltip/ShulkerBoxTooltip.java @@ -0,0 +1,32 @@ +package atonkish.reinfshulker.integration.shulkerboxtooltip; + +import com.misterpemodder.shulkerboxtooltip.api.ShulkerBoxTooltipApi; +import com.misterpemodder.shulkerboxtooltip.api.provider.PreviewProvider; +import com.misterpemodder.shulkerboxtooltip.api.provider.PreviewProviderRegistry; + +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.item.Item; +import net.minecraft.util.Identifier; + +import atonkish.reinfcore.util.ReinforcingMaterial; +import atonkish.reinfcore.util.ReinforcingMaterials; +import atonkish.reinfshulker.block.entity.ModBlockEntityType; +import atonkish.reinfshulker.item.ModItems; + +public class ShulkerBoxTooltip implements ShulkerBoxTooltipApi { + private static void register(PreviewProviderRegistry registry, String namespace, String id, + PreviewProvider provider, Item... items) { + registry.register(new Identifier(namespace, id), provider, items); + } + + @Override + public void registerProviders(PreviewProviderRegistry registry) { + for (ReinforcingMaterial material : ReinforcingMaterials.MAP.values()) { + String namespace = BlockEntityType.getId(ModBlockEntityType.REINFORCED_SHULKER_BOX_MAP.get(material)) + .getNamespace(); + String id = material.getName() + "_shulker_box"; + Item[] items = ModItems.REINFORCED_SHULKER_BOX_MAP.get(material).values().toArray(new Item[0]); + register(registry, namespace, id, new ReinforcedShulkerBoxPreviewProvider(material), items); + } + } +} diff --git a/src/main/java/atonkish/reinfshulker/stat/ModStats.java b/src/main/java/atonkish/reinfshulker/stat/ModStats.java index 2a15528..5487793 100644 --- a/src/main/java/atonkish/reinfshulker/stat/ModStats.java +++ b/src/main/java/atonkish/reinfshulker/stat/ModStats.java @@ -15,7 +15,7 @@ public class ModStats { public static final Map CLEAN_REINFORCED_SHULKER_BOX_MAP = new LinkedHashMap<>(); public static final Map OPEN_REINFORCED_SHULKER_BOX_MAP = new LinkedHashMap<>(); - public static Identifier registerMaterialOpen(String namespace, ReinforcingMaterial material) { + public static Identifier registerMaterialClean(String namespace, ReinforcingMaterial material) { if (!CLEAN_REINFORCED_SHULKER_BOX_MAP.containsKey(material)) { String id = "clean_" + material.getName() + "_shulker_box"; Identifier identifier = register(namespace, id, StatFormatter.DEFAULT); @@ -25,7 +25,7 @@ public static Identifier registerMaterialOpen(String namespace, ReinforcingMater return CLEAN_REINFORCED_SHULKER_BOX_MAP.get(material); } - public static Identifier registerMaterialClean(String namespace, ReinforcingMaterial material) { + public static Identifier registerMaterialOpen(String namespace, ReinforcingMaterial material) { if (!OPEN_REINFORCED_SHULKER_BOX_MAP.containsKey(material)) { String id = "open_" + material.getName() + "_shulker_box"; Identifier identifier = register(namespace, id, StatFormatter.DEFAULT); diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 94333e8..cd24a45 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -19,9 +19,9 @@ "entrypoints": { "main": ["atonkish.reinfshulker.ReinforcedShulkerBoxesMod"], "reinfcore": ["atonkish.reinfshulker.ReinforcedShulkerBoxesMod"], - "reinfcoreclient": [ - "atonkish.reinfshulker.ReinforcedShulkerBoxesClientMod" - ], + "reinfcore-client": ["atonkish.reinfshulker.ReinforcedShulkerBoxesClientMod"], + "reinfcore-gametest": ["atonkish.reinfshulker.gametest.ReinforcedShulkerBoxesModGameTest"], + "shulkerboxtooltip": ["atonkish.reinfshulker.integration.shulkerboxtooltip.ShulkerBoxTooltip"], "modmenu": ["atonkish.reinfcore.integration.modmenu.ModMenu"] }, "mixins": [