From ab2dd39f8fa9ca5f0e1bf80ca76b145dd39ee88e Mon Sep 17 00:00:00 2001 From: Deniz Demiroglu Date: Wed, 19 Jul 2023 10:59:12 +0200 Subject: [PATCH 01/61] Start writing some new tests, this not even near finished. The plan is to code test the most code which does not need a running minecraft instance. For other parts of the project, gametests will be created at a later point Also make a static helper function to create the tooltips to minimize duplication and maintenance time --- gradle.properties | 6 +- .../common/items/MemoryCardItem.java | 3 +- .../common/items/WeakAutomataCore.java | 2 +- .../common/items/base/BaseBlockItem.java | 13 +-- .../common/items/base/BaseItem.java | 14 +--- .../common/util/inventory/ItemUtil.java | 13 +++ .../owner/OperationAbilityTest.java | 77 ------------------ .../test/DummyPeripheralOwner.java | 79 ------------------- .../utiltests/TranslationAndStringTests.java | 23 ++++++ 9 files changed, 48 insertions(+), 182 deletions(-) delete mode 100644 src/test/java/de/srendi/advancedperipherals/lib/peripherals/owner/OperationAbilityTest.java delete mode 100644 src/test/java/de/srendi/advancedperipherals/test/DummyPeripheralOwner.java create mode 100644 src/test/java/de/srendi/advancedperipherals/tests/utiltests/TranslationAndStringTests.java diff --git a/gradle.properties b/gradle.properties index b534cadfe..0f7a87a5a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,10 +12,10 @@ mappings_version=2022.09.18-1.19.2 jb_annotations=21.0.1 # Test dependencies -junit_version=5.7.2 +junit_version=5.9.3 hamcrest_version=2.2 -kotlin_version=1.6.10 -kotlinx_coroutines_version=1.6.0-RC3 +kotlin_version=1.9.0 +kotlinx_coroutines_version=1.7.2 ttoolkit_version=0.1.3 # Mod dependencies diff --git a/src/main/java/de/srendi/advancedperipherals/common/items/MemoryCardItem.java b/src/main/java/de/srendi/advancedperipherals/common/items/MemoryCardItem.java index cb580571b..4b52d5de3 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/items/MemoryCardItem.java +++ b/src/main/java/de/srendi/advancedperipherals/common/items/MemoryCardItem.java @@ -9,6 +9,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -25,7 +26,7 @@ public boolean isEnabled() { } @Override - public void appendHoverText(ItemStack stack, @Nullable Level levelIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(@NotNull ItemStack stack, @Nullable Level levelIn, @NotNull List tooltip, @NotNull TooltipFlag flagIn) { super.appendHoverText(stack, levelIn, tooltip, flagIn); if (stack.getOrCreateTag().contains("owner")) tooltip.add(Component.translatable("item.advancedperipherals.tooltip.memory_card.bound", stack.getOrCreateTag().getString("owner"))); diff --git a/src/main/java/de/srendi/advancedperipherals/common/items/WeakAutomataCore.java b/src/main/java/de/srendi/advancedperipherals/common/items/WeakAutomataCore.java index 12394d92d..33c1a1a8e 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/items/WeakAutomataCore.java +++ b/src/main/java/de/srendi/advancedperipherals/common/items/WeakAutomataCore.java @@ -58,7 +58,7 @@ public WeakAutomataCore(@Nullable ResourceLocation turtleID, @Nullable ResourceL } @Override - public void appendHoverText(ItemStack stack, @Nullable Level worldIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(@NotNull ItemStack stack, @Nullable Level worldIn, @NotNull List tooltip, @NotNull TooltipFlag flagIn) { super.appendHoverText(stack, worldIn, tooltip, flagIn); CompoundTag tag = stack.getOrCreateTag(); CompoundTag consumedData = tag.getCompound(CONSUMER_ENTITY_COMPOUND); diff --git a/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseBlockItem.java b/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseBlockItem.java index 4d76ee0e6..31237b250 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseBlockItem.java +++ b/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseBlockItem.java @@ -1,9 +1,8 @@ package de.srendi.advancedperipherals.common.items.base; import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.client.KeyBindings; -import de.srendi.advancedperipherals.common.util.EnumColor; import de.srendi.advancedperipherals.common.util.TranslationUtil; +import de.srendi.advancedperipherals.common.util.inventory.ItemUtil; import net.minecraft.network.chat.Component; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; @@ -27,15 +26,9 @@ public BaseBlockItem(Block blockIn) { } @Override - public void appendHoverText(ItemStack stack, @Nullable Level levelIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(@NotNull ItemStack stack, @Nullable Level levelIn, @NotNull List tooltip, @NotNull TooltipFlag flagIn) { super.appendHoverText(stack, levelIn, tooltip, flagIn); - if (!KeyBindings.DESCRIPTION_KEYBINDING.isDown()) { - tooltip.add(EnumColor.buildTextComponent(Component.translatable("item.advancedperipherals.tooltip.show_desc", KeyBindings.DESCRIPTION_KEYBINDING.getTranslatedKeyMessage()))); - } else { - tooltip.add(EnumColor.buildTextComponent(getDescription())); - } - if (!isEnabled()) - tooltip.add(EnumColor.buildTextComponent(Component.translatable("item.advancedperipherals.tooltip.disabled"))); + ItemUtil.buildItemTooltip(getDescription(), isEnabled(), tooltip); } public @NotNull Component getDescription() { diff --git a/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseItem.java b/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseItem.java index 0e3a795d5..5c17112ca 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseItem.java +++ b/src/main/java/de/srendi/advancedperipherals/common/items/base/BaseItem.java @@ -1,9 +1,8 @@ package de.srendi.advancedperipherals.common.items.base; import de.srendi.advancedperipherals.AdvancedPeripherals; -import de.srendi.advancedperipherals.client.KeyBindings; -import de.srendi.advancedperipherals.common.util.EnumColor; import de.srendi.advancedperipherals.common.util.TranslationUtil; +import de.srendi.advancedperipherals.common.util.inventory.ItemUtil; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; @@ -44,18 +43,11 @@ public InteractionResultHolder use(Level worldIn, Player playerIn, In } @Override - public void appendHoverText(ItemStack stack, @Nullable Level worldIn, List tooltip, TooltipFlag flagIn) { + public void appendHoverText(@NotNull ItemStack stack, @Nullable Level worldIn, @NotNull List tooltip, @NotNull TooltipFlag flagIn) { super.appendHoverText(stack, worldIn, tooltip, flagIn); - if (!KeyBindings.DESCRIPTION_KEYBINDING.isDown()) { - tooltip.add(EnumColor.buildTextComponent(Component.translatable("item.advancedperipherals.tooltip.show_desc", KeyBindings.DESCRIPTION_KEYBINDING.getTranslatedKeyMessage()))); - } else { - tooltip.add(EnumColor.buildTextComponent(getDescription())); - } - if (!isEnabled()) - tooltip.add(EnumColor.buildTextComponent(Component.translatable("item.advancedperipherals.tooltip.disabled"))); + ItemUtil.buildItemTooltip(getDescription(), isEnabled(), tooltip); } - public @NotNull Component getDescription() { if (description == null) description = TranslationUtil.itemTooltip(getDescriptionId()); return description; diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java b/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java index 665283d73..b9a22726c 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java @@ -2,9 +2,12 @@ import dan200.computercraft.shared.Registry; import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.KeyBindings; +import de.srendi.advancedperipherals.common.util.EnumColor; import de.srendi.advancedperipherals.common.util.StringUtil; import net.minecraft.ResourceLocationException; import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -98,6 +101,16 @@ public static void addComputerItemToTab(ResourceLocation turtleID, ResourceLocat } } + public static void buildItemTooltip(Component description, boolean isEnabled, List tooltip) { + if (!KeyBindings.DESCRIPTION_KEYBINDING.isDown()) { + tooltip.add(EnumColor.buildTextComponent(Component.translatable("item.advancedperipherals.tooltip.show_desc", KeyBindings.DESCRIPTION_KEYBINDING.getTranslatedKeyMessage()))); + } else { + tooltip.add(EnumColor.buildTextComponent(description)); + } + if (!isEnabled) + tooltip.add(EnumColor.buildTextComponent(Component.translatable("item.advancedperipherals.tooltip.disabled"))); + } + public static ResourceLocation getRegistryKey(Item item) { return ForgeRegistries.ITEMS.getKey(item); } diff --git a/src/test/java/de/srendi/advancedperipherals/lib/peripherals/owner/OperationAbilityTest.java b/src/test/java/de/srendi/advancedperipherals/lib/peripherals/owner/OperationAbilityTest.java deleted file mode 100644 index a2781aa68..000000000 --- a/src/test/java/de/srendi/advancedperipherals/lib/peripherals/owner/OperationAbilityTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package de.srendi.advancedperipherals.lib.peripherals.owner; - -public class OperationAbilityTest { - - //Commented out until we port ttoolkit to 1.18 - /*@Test - public void testCooldownLong() { - DummyPeripheralOwner owner = new DummyPeripheralOwner(); - owner.attachOperation(DummyOperations.LONG); - OperationAbility operationAbility = owner.getAbility(PeripheralOwnerAbility.OPERATION); - assertNotNull(operationAbility); - int abilityCooldown = operationAbility.getCurrentCooldown(DummyOperations.LONG); - assertTrue(operationAbility.isOnCooldown(DummyOperations.LONG)); - assertTrue(abilityCooldown > 10_000); - assertTrue(abilityCooldown < 20_001); - } - - @Test - public void testCooldownShort() { - DummyPeripheralOwner owner = new DummyPeripheralOwner(); - assertTrue(LibConfig.initialCooldownSensetiveLevel > DummyOperations.SHORT.cooldown); - owner.attachOperation(DummyOperations.LONG); - OperationAbility operationAbility = owner.getAbility(PeripheralOwnerAbility.OPERATION); - assertNotNull(operationAbility); - int abilityCooldown = operationAbility.getCurrentCooldown(DummyOperations.SHORT); - assertFalse(operationAbility.isOnCooldown(DummyOperations.SHORT)); - assertEquals(0, abilityCooldown); - } - - @Test - public void testCooldownWithoutInitialCooldown() { - DummyPeripheralOwner owner = new DummyPeripheralOwner(); - LibConfig.setTestMode(true); - owner.attachOperation(DummyOperations.LONG); - OperationAbility operationAbility = owner.getAbility(PeripheralOwnerAbility.OPERATION); - assertNotNull(operationAbility); - int abilityCooldown = operationAbility.getCurrentCooldown(DummyOperations.LONG); - assertFalse(operationAbility.isOnCooldown(DummyOperations.LONG)); - assertEquals(0, abilityCooldown); - LibConfig.setTestMode(false); - } - - public enum DummyOperations implements IPeripheralOperation { - LONG(20_000), SHORT(3_000); - - private final int cooldown; - - DummyOperations(int cooldown) { - this.cooldown = cooldown; - } - - @Override - public void addToConfig(ForgeConfigSpec.Builder builder) { - } - - @Override - public int getInitialCooldown() { - return cooldown; - } - - @Override - public int getCooldown(Object context) { - return cooldown; - } - - @Override - public int getCost(Object context) { - return 3; - } - - @Override - public Map computerDescription() { - return new HashMap<>(); - } - }*/ - -} diff --git a/src/test/java/de/srendi/advancedperipherals/test/DummyPeripheralOwner.java b/src/test/java/de/srendi/advancedperipherals/test/DummyPeripheralOwner.java deleted file mode 100644 index 66390a63a..000000000 --- a/src/test/java/de/srendi/advancedperipherals/test/DummyPeripheralOwner.java +++ /dev/null @@ -1,79 +0,0 @@ -package de.srendi.advancedperipherals.test; - -public class DummyPeripheralOwner /*extends BasePeripheralOwner*/ { - - /* private final CompoundTag dataStorage = new CompoundTag(); - - @Override - @Nullable - public String getCustomName() { - return null; - } - - @Override - @Nullable - public Level getLevel() { - return null; - } - - @Override - @NotNull - public BlockPos getPos() { - return new BlockPos(0, 0, 0); - } - - @Override - @NotNull - public Direction getFacing() { - return Direction.NORTH; - } - - @Override - @Nullable - public Player getOwner() { - return null; - } - - @Override - @NotNull - public CompoundTag getDataStorage() { - return dataStorage; - } - - @Override - public void markDataStorageDirty() { - - } - - @Override - public T withPlayer(Function function) { - throw new RuntimeException("Not implemented"); - } - - @Override - public ItemStack getToolInMainHand() { - return ItemStack.EMPTY; - } - - @Override - public ItemStack storeItem(ItemStack stored) { - return stored; - } - - @Override - public void destroyUpgrade() { - - } - - @Override - public boolean isMovementPossible(@NotNull Level level, @NotNull BlockPos pos) { - return false; - } - - @Override - public boolean move(@NotNull Level level, @NotNull BlockPos pos) { - return false; - } - */ - -} diff --git a/src/test/java/de/srendi/advancedperipherals/tests/utiltests/TranslationAndStringTests.java b/src/test/java/de/srendi/advancedperipherals/tests/utiltests/TranslationAndStringTests.java new file mode 100644 index 000000000..e45a24652 --- /dev/null +++ b/src/test/java/de/srendi/advancedperipherals/tests/utiltests/TranslationAndStringTests.java @@ -0,0 +1,23 @@ +package de.srendi.advancedperipherals.tests.utiltests; + +import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.common.util.TranslationUtil; +import net.minecraft.Util; +import net.minecraft.resources.ResourceLocation; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TranslationAndStringTests { + + @Test + void translationTests() { + assertEquals("pocket.advancedperipherals.chatty_pocket", TranslationUtil.pocket("chatty_pocket")); + + assertEquals("turtle.advancedperipherals.husbandry_automata", TranslationUtil.turtle("husbandry_automata")); + + String descriptionId = Util.makeDescriptionId("item", new ResourceLocation(AdvancedPeripherals.MOD_ID, "peripheral_casing")); + assertEquals("item.advancedperipherals.tooltip.peripheral_casing", TranslationUtil.itemTooltip(descriptionId).getString()); + } + +} From 866474fb4ee6b11b2a5979c579da8efcbc514cac Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 23 Feb 2024 22:53:16 +0100 Subject: [PATCH 02/61] Add some testing game tests, next step is trying to run tests on computers with CC's testing api Removed some old stuff --- build.gradle | 43 ++--- gradle.properties | 2 - .../gametest/TestGameTests.java | 17 ++ .../advancedperipherals/gametest/TestMod.java | 17 ++ src/testMod/resources/META-INF/mods.toml | 13 +- .../structures/envdetectortest.nbt | Bin 0 -> 548 bytes src/testMod/server-files/computers/ids.json | 5 - .../structures/automata.weak.snbt | 155 ------------------ .../structures/dummytest.passing.snbt | 11 -- .../structures/peripherals.geoscanner.snbt | 20 --- 10 files changed, 51 insertions(+), 232 deletions(-) create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/envdetectortest.nbt delete mode 100644 src/testMod/server-files/computers/ids.json delete mode 100644 src/testMod/server-files/structures/automata.weak.snbt delete mode 100644 src/testMod/server-files/structures/dummytest.passing.snbt delete mode 100644 src/testMod/server-files/structures/peripherals.geoscanner.snbt diff --git a/build.gradle b/build.gradle index 1ec36b940..c9b57f9e4 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,6 @@ plugins { id 'net.darkhax.curseforgegradle' version '1.1.16' id 'org.jetbrains.changelog' version '1.2.1' id "com.modrinth.minotaur" version "2.+" - id "org.jetbrains.kotlin.jvm" version "1.6.10" id "com.github.breadmoirai.github-release" version "2.5.2" id 'checkstyle' id 'java' @@ -141,12 +140,15 @@ minecraft { } } - testClient { + gameTestClient { workingDirectory project.file('test-files/client') parent runs.client + property 'forge.logging.markers', 'REGISTRIES' + property 'forge.logging.console.level', 'debug' + property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' mods { - aptest { + advancedperipheralstest { source sourceSets.testMod } } @@ -158,21 +160,19 @@ minecraft { } } - testServer { + gameTestServer { workingDirectory project.file('test-files/server') + property 'forge.logging.markers', 'REGISTRIES' + property 'forge.logging.console.level', 'debug' + property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' + parent runs.server mods { - aptest { + advancedperipheralstest { source sourceSets.testMod } } - - lazyToken('minecraft_classpath') { - (configurations.implementationExtra.copyRecursive().resolve()) - .collect { it.absolutePath } - .join(File.pathSeparator) - } } } } @@ -259,6 +259,7 @@ dependencies { compileOnly "org.jetbrains:annotations:${jb_annotations}" minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}" implementation fg.deobf("org.squiddev:cc-tweaked-${minecraft_version}:${cc_version}") + implementation fg.deobf("org.squiddev:cc-tweaked-${minecraft_version}:${cc_version}:api") // Minimal requirements end // Extended requirements @@ -337,8 +338,6 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_version}" testImplementation "org.junit.jupiter:junit-jupiter-params:${junit_version}" testImplementation "org.hamcrest:hamcrest:${hamcrest_version}" - testImplementation "org.jetbrains.kotlin:kotlin-reflect:${kotlin_version}" - testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${kotlinx_coroutines_version}" testModImplementation sourceSets.main.output testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_version}" @@ -378,28 +377,12 @@ task setupServer(type: Copy) { into "test-files/server" } -["Client", "Server"].forEach { name -> - tasks.register("test$name", JavaExec.class).configure { - it.group('In-game tests') - it.description("Runs tests on a temporary Minecraft instance.") - it.dependsOn(setupServer, "prepareRunTest$name", "cleanTest$name", 'compileTestModJava') - - JavaExec exec = tasks.getByName("runTest$name") - exec.copyTo(it) - it.setClasspath(exec.getClasspath()) - it.mainClass = exec.mainClass - it.setArgs(exec.getArgs()) - - it.systemProperty('forge.logging.console.level', 'debug') - it.systemProperty('ttoolkit.run', 'true') - } -} - test { useJUnitPlatform() testLogging { events "skipped", "failed" } + finalizedBy('runGameTestServer') } afterEvaluate { diff --git a/gradle.properties b/gradle.properties index 229d21c67..405301743 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,8 +16,6 @@ jb_annotations=21.0.1 # Test dependencies junit_version=5.9.3 hamcrest_version=2.2 -kotlin_version=1.9.0 -kotlinx_coroutines_version=1.7.2 ttoolkit_version=0.1.3 # Mod dependencies diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java new file mode 100644 index 000000000..11a9bc84e --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java @@ -0,0 +1,17 @@ +package de.srendi.advancedperipherals.gametest; + +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.gametest.PrefixGameTestTemplate; + +@GameTestHolder("advancedperipheralstest") +public class TestGameTests { + + @PrefixGameTestTemplate(false) + @GameTest(templateNamespace = "advancedperipheralstest") + public static void envDetectorTest(GameTestHelper helper) { + helper.succeed(); + } + +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java new file mode 100644 index 000000000..bf3f064dc --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java @@ -0,0 +1,17 @@ +package de.srendi.advancedperipherals.gametest; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +@Mod("advancedperipheralstest") +public class TestMod { + + public TestMod() { + } + + private static void onInitializeClient() { + } +} diff --git a/src/testMod/resources/META-INF/mods.toml b/src/testMod/resources/META-INF/mods.toml index 66aca9170..aa1ca6534 100644 --- a/src/testMod/resources/META-INF/mods.toml +++ b/src/testMod/resources/META-INF/mods.toml @@ -1,16 +1,11 @@ modLoader = "javafml" -loaderVersion = "[30,)" - -issueTrackerURL = "https://github.com/SquidDev-CC/CC-Tweaked/issues" -displayURL = "https://github.com/SquidDev-CC/CC-Tweaked" +loaderVersion = "[43,)" +license = "Apache-2.0 license" +issueTrackerURL = "https://github.com/Seniorendi/AdvancedPeripherals/issues" logoFile = "pack.png" -credits = "Created by Daniel Ratcliffe (@DanTwoHundred)" -authors = "Daniel Ratcliffe, Aaron Mills, SquidDev" -license = "ComputerCraft Public License (https://raw.githubusercontent.com/dan200/ComputerCraft/master/LICENSE)" - [[mods]] -modId = "aptest" +modId = "advancedperipheralstest" version = "1.0.0" displayName = "CC: Tweaked test framework" description = ''' diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/envdetectortest.nbt b/src/testMod/resources/data/advancedperipheralstest/structures/envdetectortest.nbt new file mode 100644 index 0000000000000000000000000000000000000000..c833300f1352bf4ed03a9945c5454414fb3a7334 GIT binary patch literal 548 zcmb2|=3oGW|Gn27^KThQw0|_;_Hxpe-R~|PF1u6sJnpvdDz#kew?UyNRPr{?x-l`g z>c;YXrafDnkN$Lb()e)XXJcxCZ^*>1Z}TU*nAnQ_i3!Y%*>rN2$K}9_H&=Z=8@%TD zgB)jt%7ce$=F5c) zybr8l*vxc>%Rn2*Fn;?yIqz+Uq_KH%w)>eGJ7-2)7pLVtyLN8QPKGnA31SUES1`^1 zGnmpiXQ(DjYlvh@W1S(I5Y`aMnD%wuPPLa|E0?`$=kI?O#Xr$YXxq~Bz3B&BmYj!OEKSNYEZ}Q7>>Bn<_YCmQZezU>MvHatyJ$zepzB|wTAziV0 zO7iE#3v)eB`s~gPopkGwUiIrU@4O{z(jVX2;{7&C_-%!(yL`NI?qQDg|5@x;Et^~8 zna;m!aJ1R2#HSd~b?U(yqv(_>{eCg+eYwZs|ym!C! Z(?qx4x8rg^$;aL}hS?@rV#|3L7yu&j3xEIs literal 0 HcmV?d00001 diff --git a/src/testMod/server-files/computers/ids.json b/src/testMod/server-files/computers/ids.json deleted file mode 100644 index 9c8f668d7..000000000 --- a/src/testMod/server-files/computers/ids.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "computer": 0, - "peripheral.monitor": 1, - "peripheral.printer": 1 -} diff --git a/src/testMod/server-files/structures/automata.weak.snbt b/src/testMod/server-files/structures/automata.weak.snbt deleted file mode 100644 index afbeb645c..000000000 --- a/src/testMod/server-files/structures/automata.weak.snbt +++ /dev/null @@ -1,155 +0,0 @@ -{ - size: [3, 3, 3], - entities: [], - data: [ - { - pos: [0, 0, 0], - state: "minecraft:polished_andesite" - }, - { - pos: [0, 0, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [0, 0, 2], - state: "minecraft:polished_andesite" - }, - { - pos: [1, 0, 0], - state: "minecraft:polished_andesite" - }, - { - pos: [1, 0, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [1, 0, 2], - state: "minecraft:polished_andesite" - }, - { - pos: [2, 0, 0], - state: "minecraft:polished_andesite" - }, - { - pos: [2, 0, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [2, 0, 2], - state: "minecraft:polished_andesite" - }, - { - pos: [0, 1, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [1, 1, 1], - state: "minecraft:cobblestone" - }, - { - pos: [1, 1, 2], - state: "minecraft:stone_bricks" - }, - { - pos: [2, 1, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [0, 2, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [1, 2, 0], - state: "minecraft:polished_andesite" - }, - { - pos: [1, 2, 2], - state: "minecraft:polished_andesite" - }, - { - pos: [2, 2, 1], - state: "minecraft:polished_andesite" - }, - { - pos: [0, 1, 0], - state: "minecraft:air" - }, - { - pos: [0, 1, 2], - state: "minecraft:air" - }, - { - pos: [2, 1, 0], - state: "minecraft:air" - }, - { - pos: [2, 1, 2], - state: "minecraft:air" - }, - { - pos: [0, 2, 0], - state: "minecraft:air" - }, - { - pos: [0, 2, 2], - state: "minecraft:air" - }, - { - pos: [1, 2, 1], - state: "minecraft:air" - }, - { - pos: [2, 2, 0], - state: "minecraft:air" - }, - { - pos: [2, 2, 2], - state: "minecraft:air" - }, - { - nbt: { - Owner: { - UpperId: 4039158846114182220L, - LowerId: -6876936588741668278L, - Name: "Dev" - }, - Fuel: 51197, - RightUpgrade: "advancedperipherals:weak_automata", - Slot: 0, - Items: [ - { - Slot: 0b, - id: "minecraft:netherite_pickaxe", - Count: 1b, - tag: { - Damage: 0 - } - }, - { - Slot: 1b, - id: "minecraft:cow_spawn_egg", - Count: 1b - } - ], - id: "computercraft:turtle_advanced", - RightUpgradeNbt: { - FUEL_CONSUMING_RATE: 1, - rotationCharge: 0 - }, - Label: "automata.weak", - ComputerId: 0, - On: 1b - }, - pos: [1, 1, 0], - state: "computercraft:turtle_advanced{facing:south}" - } - ], - palette: [ - "minecraft:polished_andesite", - "minecraft:cobblestone", - "minecraft:stone_bricks", - "minecraft:air", - "computercraft:turtle_advanced{facing:south}" - ], - DataVersion: 2730 -} diff --git a/src/testMod/server-files/structures/dummytest.passing.snbt b/src/testMod/server-files/structures/dummytest.passing.snbt deleted file mode 100644 index c53a423ca..000000000 --- a/src/testMod/server-files/structures/dummytest.passing.snbt +++ /dev/null @@ -1,11 +0,0 @@ -{ - DataVersion: 2730, - size: [1, 1, 1], - data: [ - {pos: [0, 0, 0], state: "minecraft:cobblestone"}, - ], - entities: [], - palette: [ - "minecraft:cobblestone" - ] -} \ No newline at end of file diff --git a/src/testMod/server-files/structures/peripherals.geoscanner.snbt b/src/testMod/server-files/structures/peripherals.geoscanner.snbt deleted file mode 100644 index 3eeb076da..000000000 --- a/src/testMod/server-files/structures/peripherals.geoscanner.snbt +++ /dev/null @@ -1,20 +0,0 @@ -{ - DataVersion: 2730, - size: [2, 2, 2], - data: [ - {pos: [0, 0, 0], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, Label: "peripherals.geoscanner", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [1, 0, 0], state: "advancedperipherals:geo_scanner"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 0, 1], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 0, 1], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - ], - entities: [], - palette: [ - "computercraft:computer_advanced{facing:north,state:blinking}", - "advancedperipherals:geo_scanner", - "minecraft:air" - ] -} \ No newline at end of file From cfc667edb23d39031d6418cb3cee364e05810f82 Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 23 Feb 2024 23:25:00 +0100 Subject: [PATCH 03/61] Remove unused imports --- .../java/de/srendi/advancedperipherals/gametest/TestMod.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java index bf3f064dc..f106664e0 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java @@ -1,10 +1,6 @@ package de.srendi.advancedperipherals.gametest; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @Mod("advancedperipheralstest") public class TestMod { From 1e3ef5a2149888c010bd4019dbe73c73433c5ff3 Mon Sep 17 00:00:00 2001 From: Srendi Date: Sat, 24 Feb 2024 18:49:05 +0100 Subject: [PATCH 04/61] Add the CC testing framework utilities --- build.gradle | 5 + .../gametest/TestGameTests.java | 17 --- .../advancedperipherals/gametest/TestMod.java | 13 -- .../gametest/api/ComputerState.java | 48 ++++++ .../gametest/api/GameTestHolder.java | 24 +++ .../gametest/core/CCTestCommand.java | 132 ++++++++++++++++ .../gametest/core/ClientHooks.java | 89 +++++++++++ .../gametest/core/Copier.java | 62 ++++++++ .../gametest/core/TestAPI.java | 91 +++++++++++ .../gametest/core/TestHooks.java | 59 ++++++++ .../gametest/core/TestMod.java | 142 ++++++++++++++++++ .../mixin/gamtest/GameTestHelperAccessor.java | 23 +++ .../mixin/gamtest/GameTestInfoAccessor.java | 17 +++ .../gamtest/GameTestSequenceAccessor.java | 18 +++ .../mixin/gamtest/GameTestSequenceMixin.java | 58 +++++++ .../mixin/gamtest/TestCommandAccessor.java | 21 +++ .../advancedperipheralstest.mixins.json | 16 ++ 17 files changed, 805 insertions(+), 30 deletions(-) delete mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java delete mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java create mode 100644 src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java create mode 100644 src/testMod/resources/advancedperipheralstest.mixins.json diff --git a/build.gradle b/build.gradle index c9b57f9e4..0c0f6b888 100644 --- a/build.gradle +++ b/build.gradle @@ -146,6 +146,9 @@ minecraft { property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' + property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + + args "--mixin.config=advancedperipheralstest.mixins.json" mods { advancedperipheralstest { @@ -165,7 +168,9 @@ minecraft { property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' + property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + args "--mixin.config=advancedperipheralstest.mixins.json" parent runs.server mods { diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java deleted file mode 100644 index 11a9bc84e..000000000 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.srendi.advancedperipherals.gametest; - -import net.minecraft.gametest.framework.GameTest; -import net.minecraft.gametest.framework.GameTestHelper; -import net.minecraftforge.gametest.GameTestHolder; -import net.minecraftforge.gametest.PrefixGameTestTemplate; - -@GameTestHolder("advancedperipheralstest") -public class TestGameTests { - - @PrefixGameTestTemplate(false) - @GameTest(templateNamespace = "advancedperipheralstest") - public static void envDetectorTest(GameTestHelper helper) { - helper.succeed(); - } - -} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java deleted file mode 100644 index f106664e0..000000000 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestMod.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.srendi.advancedperipherals.gametest; - -import net.minecraftforge.fml.common.Mod; - -@Mod("advancedperipheralstest") -public class TestMod { - - public TestMod() { - } - - private static void onInitializeClient() { - } -} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java new file mode 100644 index 000000000..cafe3839c --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java @@ -0,0 +1,48 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.api; + +import de.srendi.advancedperipherals.gametest.core.TestAPI; +import net.minecraft.gametest.framework.GameTestAssertException; +import net.minecraft.gametest.framework.GameTestSequence; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Assertion state of a computer. + * + * @see TestAPI For the Lua interface for this. + * @see TestExtensionsKt#thenComputerOk(GameTestSequence, String, String) + */ +public class ComputerState +{ + public static final String DONE = "DONE"; + + protected static final Map lookup = new ConcurrentHashMap<>(); + + protected final Set markers = new HashSet<>(); + protected String error; + + public boolean isDone( @Nonnull String marker ) + { + return markers.contains( marker ); + } + + public void check( @Nonnull String marker ) + { + if( !markers.contains( marker ) ) throw new IllegalStateException( "Not yet at " + marker ); + if( error != null ) throw new GameTestAssertException( error ); + } + + public static ComputerState get( String label ) + { + return lookup.get( label ); + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java new file mode 100644 index 000000000..0e51d88df --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java @@ -0,0 +1,24 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.api; + +import net.minecraft.gametest.framework.GameTest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks classes containing {@linkplain GameTest game tests}. + *

+ * This is used by Forge to automatically load and test classes. + */ +@Target( ElementType.TYPE ) +@Retention( RetentionPolicy.RUNTIME ) +public @interface GameTestHolder +{ +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java new file mode 100644 index 000000000..24b40c610 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java @@ -0,0 +1,132 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.core; + +import com.mojang.brigadier.CommandDispatcher; +import dan200.computercraft.ComputerCraft; +import de.srendi.advancedperipherals.mixin.gamtest.TestCommandAccessor; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTestRegistry; +import net.minecraft.gametest.framework.StructureUtils; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.level.block.entity.StructureBlockEntity; +import net.minecraft.world.level.storage.LevelResource; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; + +import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.choice; +import static net.minecraft.commands.Commands.literal; + +/** + * Helper commands for importing/exporting the computer directory. + */ +class CCTestCommand +{ + public static final LevelResource LOCATION = new LevelResource( ComputerCraft.MOD_ID ); + + public static void register( CommandDispatcher dispatcher ) + { + dispatcher.register( choice( "cctest" ) + .then( literal( "import" ).executes( context -> { + importFiles( context.getSource().getServer() ); + return 0; + } ) ) + .then( literal( "export" ).executes( context -> { + exportFiles( context.getSource().getServer() ); + + for( TestFunction function : GameTestRegistry.getAllTestFunctions() ) + { + TestCommandAccessor.callExportTestStructure( context.getSource(), function.getStructureName() ); + } + return 0; + } ) ) + .then( literal( "regen-structures" ).executes( context -> { + for( TestFunction function : GameTestRegistry.getAllTestFunctions() ) + { + dispatcher.execute( "test import " + function.getTestName(), context.getSource() ); + TestCommandAccessor.callExportTestStructure( context.getSource(), function.getStructureName() ); + } + return 0; + } ) ) + + .then( literal( "marker" ).executes( context -> { + ServerPlayer player = context.getSource().getPlayerOrException(); + BlockPos pos = StructureUtils.findNearestStructureBlock( player.blockPosition(), 15, player.getLevel() ); + if( pos == null ) return error( context.getSource(), "No nearby test" ); + + StructureBlockEntity structureBlock = (StructureBlockEntity) player.getLevel().getBlockEntity( pos ); + TestFunction info = GameTestRegistry.getTestFunction( structureBlock.getStructurePath() ); + + // Kill the existing armor stand + player + .getLevel().getEntities( EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals( info.getTestName() ) ) + .forEach( Entity::kill ); + + // And create a new one + CompoundTag nbt = new CompoundTag(); + nbt.putBoolean( "Marker", true ); + nbt.putBoolean( "Invisible", true ); + ArmorStand armorStand = EntityType.ARMOR_STAND.create( player.getLevel() ); + armorStand.readAdditionalSaveData( nbt ); + armorStand.copyPosition( player ); + armorStand.setCustomName( Component.literal( info.getTestName() ) ); + player.getLevel().addFreshEntity( armorStand ); + return 0; + } ) ) + ); + } + + public static void importFiles( MinecraftServer server ) + { + try + { + Copier.replicate( getSourceComputerPath(), getWorldComputerPath( server ) ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + + static void exportFiles( MinecraftServer server ) + { + try + { + Copier.replicate( getWorldComputerPath( server ), getSourceComputerPath() ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + + private static Path getWorldComputerPath( MinecraftServer server ) + { + return server.getWorldPath( LOCATION ).resolve( "computer" ).resolve( "0" ); + } + + private static Path getSourceComputerPath() + { + return TestHooks.sourceDir.resolve( "computer" ); + } + + private static int error( CommandSourceStack source, String message ) + { + source.sendFailure( Component.literal( message ).withStyle( ChatFormatting.RED ) ); + return 0; + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java new file mode 100644 index 000000000..418ef3cdc --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java @@ -0,0 +1,89 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.core; + +import net.minecraft.client.CloudStatus; +import net.minecraft.client.Minecraft; +import net.minecraft.client.ParticleStatus; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.tutorial.TutorialSteps; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ScreenEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +@Mod.EventBusSubscriber( modid = "cctest", value = Dist.CLIENT ) +public final class ClientHooks +{ + private static final Logger LOG = LogManager.getLogger( TestHooks.class ); + + private static boolean triggered = false; + + private ClientHooks() + { + } + + @SubscribeEvent + public static void onGuiInit( ScreenEvent.Init event ) + { + if( triggered || !(event.getScreen() instanceof TitleScreen) ) return; + triggered = true; + + ClientHooks.openWorld(); + } + + private static void openWorld() + { + Minecraft minecraft = Minecraft.getInstance(); + + // Clear some options before we get any further. + minecraft.options.autoJump().set( false ); + minecraft.options.cloudStatus().set( CloudStatus.OFF ); + minecraft.options.particles().set( ParticleStatus.MINIMAL ); + minecraft.options.tutorialStep = TutorialSteps.NONE; + minecraft.options.renderDistance().set( 6 ); + minecraft.options.gamma().set( 1.0 ); + + /* + if( minecraft.getLevelSource().levelExists( "test" ) ) + { + LOG.info( "World exists, loading it" ); + Minecraft.getInstance().loadLevel( "test" ); + } + else + { + LOG.info( "World does not exist, creating it for the first time" ); + + RegistryAccess registries = RegistryAccess.builtinCopy(); + + Registry dimensions = registries.registryOrThrow( Registry.DIMENSION_TYPE_REGISTRY ); + var biomes = registries.registryOrThrow( Registry.BIOME_REGISTRY ); + var structures = registries.registryOrThrow( Registry.STRUCTURE_SET_REGISTRY ); + + FlatLevelGeneratorSettings flatSettings = FlatLevelGeneratorSettings.getDefault( biomes, structures ) + .withLayers( + Collections.singletonList( new FlatLayerInfo( 4, Blocks.WHITE_CONCRETE ) ), + Optional.empty() + ); + flatSettings.setBiome( biomes.getHolderOrThrow( Biomes.DESERT ) ); + + WorldGenSettings generator = new WorldGenSettings( 0, false, false, withOverworld( + dimensions, + DimensionType.defaultDimensions( registries, 0 ), + new FlatLevelSource( structures, flatSettings ) + ) ); + + LevelSettings settings = new LevelSettings( + "test", GameType.CREATIVE, false, Difficulty.PEACEFUL, true, + new GameRules(), DataPackConfig.DEFAULT + ); + Minecraft.getInstance().createLevel( "test", settings, registries, generator ); + } + */ + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java new file mode 100644 index 000000000..f171d8b51 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java @@ -0,0 +1,62 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.core; + +import com.google.common.io.MoreFiles; +import com.google.common.io.RecursiveDeleteOption; + +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.function.Predicate; + +final class Copier extends SimpleFileVisitor +{ + private final Path sourceDir; + private final Path targetDir; + private final Predicate predicate; + + private Copier( Path sourceDir, Path targetDir, Predicate predicate ) + { + this.sourceDir = sourceDir; + this.targetDir = targetDir; + this.predicate = predicate; + } + + @Override + public FileVisitResult visitFile( Path file, BasicFileAttributes attributes ) throws IOException + { + if( predicate.test( file ) ) Files.copy( file, targetDir.resolve( sourceDir.relativize( file ) ) ); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attributes ) throws IOException + { + Path newDir = targetDir.resolve( sourceDir.relativize( dir ) ); + Files.createDirectories( newDir ); + return FileVisitResult.CONTINUE; + } + + public static void copy( Path from, Path to ) throws IOException + { + Files.walkFileTree( from, new Copier( from, to, p -> true ) ); + } + + public static void replicate( Path from, Path to ) throws IOException + { + replicate( from, to, p -> true ); + } + + public static void replicate( Path from, Path to, Predicate check ) throws IOException + { + if( Files.exists( to ) ) MoreFiles.deleteRecursively( to, RecursiveDeleteOption.ALLOW_INSECURE ); + Files.walkFileTree( from, new Copier( from, to, check ) ); + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java new file mode 100644 index 000000000..f3e0761e3 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java @@ -0,0 +1,91 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.core; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.IComputerSystem; +import dan200.computercraft.api.lua.ILuaAPI; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import de.srendi.advancedperipherals.gametest.api.ComputerState; +import net.minecraft.gametest.framework.GameTestSequence; + +import java.util.Optional; + +/** + * API exposed to computers to help write tests. + *

+ * Note, we extend this API within startup file of computers (see {@code cctest.lua}). + * + * @see TestExtensionsKt#thenComputerOk(GameTestSequence, String, String) To check tests on the computer have passed. + */ +public class TestAPI extends ComputerState implements ILuaAPI +{ + private final IComputerSystem system; + private String label; + + TestAPI( IComputerSystem system ) + { + this.system = system; + } + + @Override + public void startup() + { + if( label == null ) label = system.getLabel(); + if( label == null ) + { + label = "#" + system.getID(); + ComputerCraft.log.warn( "Computer {} has no label", label ); + } + + ComputerCraft.log.info( "Computer '{}' has turned on.", label ); + markers.clear(); + error = null; + lookup.put( label, this ); + } + + @Override + public void shutdown() + { + ComputerCraft.log.info( "Computer '{}' has shut down.", label ); + if( lookup.get( label ) == this ) lookup.remove( label ); + } + + @Override + public String[] getNames() + { + return new String[] { "test" }; + } + + @LuaFunction + public final void fail( String message ) throws LuaException + { + ComputerCraft.log.error( "Computer '{}' failed with {}", label, message ); + if( markers.contains( ComputerState.DONE ) ) throw new LuaException( "Cannot call fail/ok multiple times." ); + markers.add( ComputerState.DONE ); + error = message; + throw new LuaException( message ); + } + + @LuaFunction + public final void ok( Optional marker ) throws LuaException + { + String actualMarker = marker.orElse( ComputerState.DONE ); + if( markers.contains( ComputerState.DONE ) || markers.contains( actualMarker ) ) + { + throw new LuaException( "Cannot call fail/ok multiple times." ); + } + + markers.add( actualMarker ); + } + + @LuaFunction + public final void log( String message ) + { + ComputerCraft.log.info( "[Computer '{}'] {}", label, message ); + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java new file mode 100644 index 000000000..16d566967 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java @@ -0,0 +1,59 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.core; + +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.computer.core.ServerContext; +import net.minecraft.core.BlockPos; +import net.minecraft.gametest.framework.GameTestRunner; +import net.minecraft.gametest.framework.GameTestTicker; +import net.minecraft.gametest.framework.StructureUtils; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.Level; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.nio.file.Paths; + +public class TestHooks +{ + public static final Logger LOGGER = LoggerFactory.getLogger( TestHooks.class ); + + public static final Path sourceDir = Paths.get( System.getProperty( "advancedperipheralstest.sources" ) ).normalize().toAbsolutePath(); + + public static void init() + { + //ServerContext.luaMachine = ManagedComputers.INSTANCE; + ComputerCraftAPI.registerAPIFactory( TestAPI::new ); + StructureUtils.testStructuresDir = sourceDir.resolve( "structures" ).toString(); + } + + public static void onServerStarted( MinecraftServer server ) + { + GameRules rules = server.getGameRules(); + rules.getRule( GameRules.RULE_DAYLIGHT ).set( false, server ); + + ServerLevel world = server.getLevel( Level.OVERWORLD ); + if( world != null ) world.setDayTime( 12000 ); + + LOGGER.info( "Cleaning up after last run" ); + GameTestRunner.clearAllTests( server.overworld(), new BlockPos( 0, -60, 0 ), GameTestTicker.SINGLETON, 200 ); + + // Delete server context and add one with a mutable machine factory. This allows us to set the factory for + // specific test batches without having to reset all computers. + for( var computer : ServerContext.get( server ).registry().getComputers() ) + { + var label = computer.getLabel() == null ? "#" + computer.getID() : computer.getLabel(); + LOGGER.warn( "Unexpected computer {}", label ); + } + + LOGGER.info( "Importing files" ); + CCTestCommand.importFiles( server ); + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java new file mode 100644 index 000000000..9d8d5f4b3 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java @@ -0,0 +1,142 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.gametest.core; + +import de.srendi.advancedperipherals.gametest.api.GameTestHolder; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestRegistry; +import net.minecraft.gametest.framework.StructureUtils; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.RegisterClientCommandsEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.event.RegisterGameTestsEvent; +import net.minecraftforge.event.server.ServerStartedEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.forgespi.language.ModFileScanData; +import net.minecraftforge.gametest.PrefixGameTestTemplate; +import org.objectweb.asm.Type; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Locale; +import java.util.function.Consumer; + +@Mod( "advancedperipheralstest" ) +public class TestMod +{ + public TestMod() + { + TestHooks.init(); + + var bus = MinecraftForge.EVENT_BUS; + bus.addListener( EventPriority.LOW, ( ServerStartedEvent e ) -> TestHooks.onServerStarted( e.getServer() ) ); + bus.addListener( ( RegisterCommandsEvent e ) -> CCTestCommand.register( e.getDispatcher() ) ); + + var modBus = FMLJavaModLoadingContext.get().getModEventBus(); + modBus.addListener( ( RegisterGameTestsEvent event ) -> { + var holder = Type.getType( GameTestHolder.class ); + ModList.get().getAllScanData().stream() + .map( ModFileScanData::getAnnotations ) + .flatMap( Collection::stream ) + .filter( a -> holder.equals( a.annotationType() ) ) + .forEach( x -> registerClass( x.clazz().getClassName(), event::register ) ); + } ); + } + + + private static Class loadClass( String name ) + { + try + { + return Class.forName( name, true, TestMod.class.getClassLoader() ); + } + catch( ReflectiveOperationException e ) + { + throw new RuntimeException( e ); + } + } + + private static void registerClass( String className, Consumer fallback ) + { + var klass = loadClass( className ); + for( var method : klass.getDeclaredMethods() ) + { + var testInfo = method.getAnnotation( GameTest.class ); + if( testInfo == null ) + { + fallback.accept( method ); + continue; + } + + GameTestRegistry.getAllTestFunctions().add( turnMethodIntoTestFunction( method, testInfo ) ); + GameTestRegistry.getAllTestClassNames().add( className ); + } + } + + /** + * Custom implementation of {@link GameTestRegistry#turnMethodIntoTestFunction(Method)} which makes + * {@link GameTest#template()} behave the same as Fabric, namely in that it points to a {@link ResourceLocation}, + * rather than a test-class-specific structure. + *

+ * This effectively acts as a global version of {@link PrefixGameTestTemplate}, just one which doesn't require Forge + * to be present. + * + * @param method The method to register. + * @param testInfo The test info. + * @return The constructed test function. + */ + private static TestFunction turnMethodIntoTestFunction( Method method, GameTest testInfo ) + { + var className = method.getDeclaringClass().getSimpleName().toLowerCase( Locale.ROOT ); + var testName = className + "." + method.getName().toLowerCase( Locale.ROOT ); + return new TestFunction( + testInfo.batch(), + testName, + testInfo.template().isEmpty() ? testName : testInfo.template(), + StructureUtils.getRotationForRotationSteps( testInfo.rotationSteps() ), testInfo.timeoutTicks(), testInfo.setupTicks(), + testInfo.required(), testInfo.requiredSuccesses(), testInfo.attempts(), + turnMethodIntoConsumer( method ) + ); + } + + private static Consumer turnMethodIntoConsumer( Method method ) + { + return value -> { + try + { + Object instance = null; + if( !Modifier.isStatic( method.getModifiers() ) ) + { + instance = method.getDeclaringClass().getConstructor().newInstance(); + } + + method.invoke( instance, value ); + } + catch( InvocationTargetException e ) + { + if( e.getCause() instanceof RuntimeException ) + { + throw (RuntimeException) e.getCause(); + } + else + { + throw new RuntimeException( e.getCause() ); + } + } + catch( ReflectiveOperationException e ) + { + throw new RuntimeException( e ); + } + }; + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java new file mode 100644 index 000000000..553925f7e --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java @@ -0,0 +1,23 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.mixin.gamtest; + +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.GameTestInfo; +import net.minecraft.world.phys.AABB; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin( GameTestHelper.class ) +public interface GameTestHelperAccessor +{ + @Invoker + AABB callGetBounds(); + + @Accessor + GameTestInfo getTestInfo(); +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java new file mode 100644 index 000000000..cf559e72f --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java @@ -0,0 +1,17 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.mixin.gamtest; + +import net.minecraft.gametest.framework.GameTestInfo; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin( GameTestInfo.class ) +public interface GameTestInfoAccessor +{ + @Invoker( "getTick" ) + long computercraft$getTick(); +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java new file mode 100644 index 000000000..29964ca5f --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java @@ -0,0 +1,18 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.mixin.gamtest; + +import net.minecraft.gametest.framework.GameTestInfo; +import net.minecraft.gametest.framework.GameTestSequence; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin( GameTestSequence.class ) +public interface GameTestSequenceAccessor +{ + @Accessor + GameTestInfo getParent(); +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java new file mode 100644 index 000000000..619b94ec8 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java @@ -0,0 +1,58 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.mixin.gamtest; + +import de.srendi.advancedperipherals.gametest.core.TestHooks; +import net.minecraft.gametest.framework.GameTestAssertException; +import net.minecraft.gametest.framework.GameTestInfo; +import net.minecraft.gametest.framework.GameTestSequence; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin( GameTestSequence.class ) +class GameTestSequenceMixin +{ + @Shadow + @Final + public GameTestInfo parent; + + /** + * Override {@link GameTestSequence#tickAndContinue(long)} to catch non-{@link GameTestAssertException} failures. + * + * @param ticks The current tick. + * @author Jonathan Coates + * @reason There's no sense doing this in a more compatible way for game tests. + */ + @Overwrite + public void tickAndContinue( long ticks ) + { + try + { + tick( ticks ); + } + catch( GameTestAssertException ignored ) + { + // Mimic the original behaviour. + } + catch( AssertionError e ) + { + parent.fail( e ); + } + catch( Exception e ) + { + // Fail the test, rather than crashing the server. + TestHooks.LOGGER.error( "{} threw unexpected exception", parent.getTestName(), e ); + parent.fail( e ); + } + } + + @Shadow + private void tick( long tick ) + { + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java new file mode 100644 index 000000000..6b057e31a --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java @@ -0,0 +1,21 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package de.srendi.advancedperipherals.mixin.gamtest; + +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.gametest.framework.TestCommand; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin( TestCommand.class ) +public interface TestCommandAccessor +{ + @Invoker + static int callExportTestStructure( CommandSourceStack source, String structure ) + { + return 0; + } +} diff --git a/src/testMod/resources/advancedperipheralstest.mixins.json b/src/testMod/resources/advancedperipheralstest.mixins.json new file mode 100644 index 000000000..b02dc239e --- /dev/null +++ b/src/testMod/resources/advancedperipheralstest.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "package": "de.srendi.advancedperipherals.mixin.gamtest", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ + "GameTestHelperAccessor", + "GameTestInfoAccessor", + "GameTestSequenceAccessor", + "GameTestSequenceMixin", + "TestCommandAccessor" + ] +} From 8f638055a0ac3fd9509469e4b08446376859c20a Mon Sep 17 00:00:00 2001 From: Srendi Date: Thu, 2 May 2024 23:22:19 +0200 Subject: [PATCH 05/61] Implemented(Copied) the needed classes for the computer game tests from the CC repository and adapted it to our needs --- build.gradle | 38 +- gradle.properties | 5 +- settings.gradle | 2 +- .../test/core/ArbitraryByteBuffer.java | 196 +++++++++ .../test/core/ByteBufferMatcher.java | 75 ++++ .../computercraft/test/core/CallCounter.java | 34 ++ .../test/core/ContramapMatcher.java | 45 ++ .../test/core/CustomMatchers.java | 31 ++ .../test/core/apis/BasicApiEnvironment.java | 161 ++++++++ .../test/core/computer/BasicEnvironment.java | 168 ++++++++ .../test/core/filesystem/MemoryMount.java | 148 +++++++ .../test/core/terminal/TerminalMatchers.java | 54 +++ .../computercraft/test/core/Assertions.kt | 63 +++ .../core/computer/KotlinComputerManager.kt | 189 +++++++++ .../test/core/computer/KotlinLuaMachine.kt | 55 +++ .../test/core/computer/LuaTaskContext.kt | 102 +++++ .../test/core/computer/LuaTaskRunner.kt | 64 +++ .../dan200/computercraft/export/Exporter.java | 158 +++++++ .../computercraft/export/ImageRenderer.java | 80 ++++ .../dan200/computercraft/export/JsonDump.java | 66 +++ .../gametest/api/ComputerState.java | 4 +- .../gametest/api/GameTestHolder.java | 2 +- .../gametest/core/CCTestCommand.java | 4 +- .../gametest/core/ClientHooks.java | 2 +- .../computercraft}/gametest/core/Copier.java | 2 +- .../computercraft}/gametest/core/TestAPI.java | 5 +- .../gametest/core/TestHooks.java | 7 +- .../computercraft/gametest/core/TestMod.java | 124 ++++++ .../gametest}/GameTestHelperAccessor.java | 2 +- .../mixin/gametest}/GameTestInfoAccessor.java | 2 +- .../gametest}/GameTestSequenceAccessor.java | 2 +- .../gametest}/GameTestSequenceMixin.java | 6 +- .../mixin/gametest}/TestCommandAccessor.java | 2 +- .../gametest/core/TestMod.java | 142 ------- .../TestGameTests.java | 19 + .../computercraft/gametest/Computer_Test.kt | 72 ++++ .../computercraft/gametest/CraftOs_Test.kt | 22 + .../computercraft/gametest/Disk_Drive_Test.kt | 55 +++ .../computercraft/gametest/Loot_Test.kt | 37 ++ .../computercraft/gametest/Modem_Test.kt | 102 +++++ .../computercraft/gametest/Monitor_Test.kt | 50 +++ .../computercraft/gametest/Recipe_Test.kt | 65 +++ .../computercraft/gametest/Turtle_Test.kt | 384 ++++++++++++++++++ .../gametest/api/TestExtensions.kt | 248 +++++++++++ .../gametest/core/ManagedComputers.kt | 137 +++++++ src/testMod/resources/META-INF/mods.toml | 32 +- .../advancedperipheralstest.mixins.json | 2 +- .../computer/startup.lua | 19 + ..._test.sends_basic_rednet_messages.echo.lua | 8 + ..._test.sends_basic_rednet_messages.main.lua | 10 + .../computer_test.computer_peripheral.snbt | 138 +++++++ .../computer_test.no_through_signal.snbt | 141 +++++++ ...mputer_test.no_through_signal_reverse.snbt | 141 +++++++ .../computer_test.set_and_destroy.snbt | 138 +++++++ ...ftos_test.sends_basic_rednet_messages.snbt | 139 +++++++ .../structures/default.snbt | 136 +++++++ .../disk_drive_test.adds_removes_mount.snbt | 138 +++++++ .../disk_drive_test.audio_disk.snbt | 40 ++ .../disk_drive_test.ejects_disk.snbt | 139 +++++++ .../modem_test.gains_peripherals.snbt | 145 +++++++ .../modem_test.have_peripherals.snbt | 146 +++++++ .../modem_test.transmits_messages.snbt | 140 +++++++ .../monitor_test.ensures_valid_on_place.snbt | 136 +++++++ .../monitor_test.looks_acceptable.snbt | 146 +++++++ .../monitor_test.looks_acceptable_dark.snbt | 145 +++++++ .../printouttest.in_frame_at_night.snbt | 140 +++++++ .../structures/turtle_test.attack_entity.snbt | 140 +++++++ .../turtle_test.attack_entity_destroy.snbt | 141 +++++++ .../turtle_test.cleaned_with_cauldrons.snbt | 40 ++ .../turtle_test.drop_into_chest.snbt | 138 +++++++ .../turtle_test.drop_into_entity.snbt | 140 +++++++ .../structures/turtle_test.gather_lava.snbt | 139 +++++++ .../structures/turtle_test.hoe_dirt.snbt | 40 ++ .../turtle_test.item_detail_provider.snbt | 39 ++ .../structures/turtle_test.move_obstruct.snbt | 138 +++++++ .../structures/turtle_test.move_replace.snbt | 139 +++++++ .../structures/turtle_test.move_water.snbt | 148 +++++++ .../structures/turtle_test.place_lava.snbt | 138 +++++++ .../structures/turtle_test.place_monitor.snbt | 142 +++++++ .../turtle_test.place_waterlogged.snbt | 139 +++++++ .../structures/turtle_test.refuel_basic.snbt | 137 +++++++ .../turtle_test.refuel_container.snbt | 137 +++++++ ...turtle_test.resists_entity_explosions.snbt | 140 +++++++ .../turtle_test.resists_explosions.snbt | 139 +++++++ .../structures/turtle_test.shears_sheep.snbt | 140 +++++++ ...tle_test.unequip_refreshes_peripheral.snbt | 138 +++++++ .../turtle_test.use_compostors.snbt | 138 +++++++ .../loot_tables/treasure_disk.json | 20 + .../computercraft/lua/rom/autorun/cctest.lua | 25 ++ src/testMod/resources/pack.mcmeta | 8 +- 90 files changed, 7948 insertions(+), 185 deletions(-) create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java create mode 100644 src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java create mode 100644 src/testFixtures/kotlin/dan200/computercraft/test/core/Assertions.kt create mode 100644 src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt create mode 100644 src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinLuaMachine.kt create mode 100644 src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskContext.kt create mode 100644 src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskRunner.kt create mode 100644 src/testMod/java/dan200/computercraft/export/Exporter.java create mode 100644 src/testMod/java/dan200/computercraft/export/ImageRenderer.java create mode 100644 src/testMod/java/dan200/computercraft/export/JsonDump.java rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/api/ComputerState.java (92%) rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/api/GameTestHolder.java (92%) rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/core/CCTestCommand.java (97%) rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/core/ClientHooks.java (98%) rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/core/Copier.java (97%) rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/core/TestAPI.java (94%) rename src/testMod/java/{de/srendi/advancedperipherals => dan200/computercraft}/gametest/core/TestHooks.java (91%) create mode 100644 src/testMod/java/dan200/computercraft/gametest/core/TestMod.java rename src/testMod/java/{de/srendi/advancedperipherals/mixin/gamtest => dan200/computercraft/mixin/gametest}/GameTestHelperAccessor.java (92%) rename src/testMod/java/{de/srendi/advancedperipherals/mixin/gamtest => dan200/computercraft/mixin/gametest}/GameTestInfoAccessor.java (89%) rename src/testMod/java/{de/srendi/advancedperipherals/mixin/gamtest => dan200/computercraft/mixin/gametest}/GameTestSequenceAccessor.java (90%) rename src/testMod/java/{de/srendi/advancedperipherals/mixin/gamtest => dan200/computercraft/mixin/gametest}/GameTestSequenceMixin.java (91%) rename src/testMod/java/{de/srendi/advancedperipherals/mixin/gamtest => dan200/computercraft/mixin/gametest}/TestCommandAccessor.java (91%) delete mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java create mode 100644 src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/startup.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/default.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.adds_removes_mount.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/printouttest.in_frame_at_night.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity_destroy.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.cleaned_with_cauldrons.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_chest.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_entity.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.gather_lava.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.hoe_dirt.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.item_detail_provider.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_obstruct.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_replace.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_water.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_lava.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_monitor.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_waterlogged.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_basic.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_container.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_entity_explosions.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_explosions.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.shears_sheep.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.unequip_refreshes_peripheral.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.use_compostors.snbt create mode 100644 src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json create mode 100644 src/testMod/resources/data/computercraft/lua/rom/autorun/cctest.lua diff --git a/build.gradle b/build.gradle index 201d7912d..bf4df40bc 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { id 'net.darkhax.curseforgegradle' version '1.1.16' id 'org.jetbrains.changelog' version '1.2.1' id "com.modrinth.minotaur" version "2.+" - id "org.jetbrains.kotlin.jvm" version "1.6.10" + id "org.jetbrains.kotlin.jvm" version "1.9.23" id 'net.minecraftforge.gradle' version '[6.0.18,6.2)' id 'org.parchmentmc.librarian.forgegradle' version '1.+' id 'org.spongepowered.mixin' version '0.7.+' @@ -56,9 +56,26 @@ sourceSets { main.resources { srcDir 'src/generated/resources' } - testMod {} + testMod { + java.srcDir 'src/testMod/java' + kotlin.srcDir 'src/testMod/kotlin' + resources.srcDir 'src/testMod/resources' + compileClasspath += main.compileClasspath + test.compileClasspath + runtimeClasspath += main.runtimeClasspath + test.runtimeClasspath + } + testFixtures { + java.srcDir 'src/testFixtures/java' + kotlin.srcDir 'src/testFixtures/kotlin' + resources.srcDir 'src/testFixtures/resources' + } +} + +java.registerFeature("testFixtures") { + usingSourceSet(sourceSets.testFixtures) + disablePublication() } + minecraft { mappings channel: "${mappings_channel}", version: "${mappings_version}" @@ -139,6 +156,7 @@ minecraft { mods { advancedperipheralstest { source sourceSets.testMod + source sourceSets.testFixtures } } @@ -162,6 +180,7 @@ minecraft { mods { advancedperipheralstest { source sourceSets.testMod + source sourceSets.testFixtures } } } @@ -254,8 +273,11 @@ repositories { configurations { implementationExtra + testImplementation.extendsFrom(implementation) testModImplementation.extendsFrom(implementation) testModImplementation.extendsFrom(testImplementation) + testFixturesImplementation.extendsFrom(implementation) + testFixturesImplementation.extendsFrom(testImplementation) } dependencies { @@ -330,9 +352,6 @@ dependencies { compileOnly fg.deobf("com.simibubi.create:create-${minecraft_version}:${create_version}:all") runtimeOnly fg.deobf("com.simibubi.create:create-${minecraft_version}:${create_version}:all") - //Removed until fully ported - //testImplementation fg.deobf("site.siredvin.ttoolkit:ttoolkit-${minecraft_version}:${ttoolkit_version}") - //Powah compileOnly fg.deobf("curse.maven:powah-633483:${powah_version}") runtimeOnly fg.deobf("curse.maven:powah-633483:${powah_version}") @@ -344,10 +363,12 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter-api:${junit_version}" testImplementation "org.junit.jupiter:junit-jupiter-params:${junit_version}" + testImplementation "org.junit.jupiter:junit-jupiter-engine:${junit_version}" + testImplementation "net.jqwik:jqwik:${jqwikVersion}" testImplementation "org.hamcrest:hamcrest:${hamcrest_version}" testModImplementation sourceSets.main.output + testModImplementation sourceSets.testFixtures.output - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit_version}" // Testing stuff // JEI implementation fg.deobf("mezz.jei:jei-${jei_version}") @@ -375,6 +396,11 @@ changelog { compileTestModJava { dependsOn(compileJava) + dependsOn(compileKotlin) + dependsOn(compileTestJava) + dependsOn(compileTestKotlin) + dependsOn(compileTestFixturesJava) + dependsOn(compileTestFixturesKotlin) } task setupServer(type: Copy) { diff --git a/gradle.properties b/gradle.properties index d03e53a5b..18bec706c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.logging.level=info # Minecraft related mod_id=advancedperipherals minecraft_version=1.19.2 -forge_version=43.3.8 +forge_version=43.3.13 loader_version=43 mod_version=0.7.36r release_type=release @@ -14,9 +14,10 @@ mappings_version=2022.11.27-1.19.2 jb_annotations=21.0.1 # Test dependencies -junit_version=5.9.3 +junit_version=5.10.2 hamcrest_version=2.2 ttoolkit_version=0.1.3 +jqwikVersion=1.8.4 # Mod dependencies cc_version=1.101.3 diff --git a/settings.gradle b/settings.gradle index 6b39aa618..e95fe7b62 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,5 +16,5 @@ pluginManagement { } plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0' } \ No newline at end of file diff --git a/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java b/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java new file mode 100644 index 000000000..ea5585e3b --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java @@ -0,0 +1,196 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core; + +import net.jqwik.api.*; +import net.jqwik.api.arbitraries.SizableArbitrary; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; +import java.util.Spliterators; +import java.util.function.Consumer; +import java.util.function.ToIntFunction; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * Generate arbitrary byte buffers with irrelevant (but random) contents. + *

+ * This is more efficient than using {@link Arbitraries#bytes()} and {@link Arbitrary#array(Class)}, as it does not + * try to shrink the contents, only the size. + */ +public final class ArbitraryByteBuffer implements SizableArbitrary +{ + private static final ArbitraryByteBuffer DEFAULT = new ArbitraryByteBuffer( 0, null, null ); + + private int minSize = 0; + private final @Nullable Integer maxSize; + private final @Nullable RandomDistribution distribution; + + private ArbitraryByteBuffer( int minSize, @Nullable Integer maxSize, @Nullable RandomDistribution distribution ) + { + this.minSize = minSize; + this.maxSize = maxSize; + this.distribution = distribution; + } + + public static ArbitraryByteBuffer bytes() + { + return DEFAULT; + } + + @Nonnull + @Override + public SizableArbitrary ofMinSize( int minSize ) + { + return new ArbitraryByteBuffer( minSize, maxSize, distribution ); + } + + @Nonnull + @Override + public SizableArbitrary ofMaxSize( int maxSize ) + { + return new ArbitraryByteBuffer( minSize, maxSize, distribution ); + } + + @Nonnull + @Override + public SizableArbitrary withSizeDistribution( @Nonnull RandomDistribution distribution ) + { + return new ArbitraryByteBuffer( minSize, maxSize, distribution ); + } + + @Nonnull + @Override + public RandomGenerator generator( int genSize ) + { + BigInteger min = BigInteger.valueOf( minSize ); + ToIntFunction generator; + if( distribution == null ) + { + generator = sizeGeneratorWithCutoff( minSize, getMaxSize(), genSize ); + } + else + { + RandomDistribution.RandomNumericGenerator gen = distribution.createGenerator( genSize, min, BigInteger.valueOf( getMaxSize() ), min ); + generator = r -> gen.next( r ).intValueExact(); + } + return r -> { + int size = generator.applyAsInt( r ); + return new ShrinkableBuffer( allocateRandom( size, r ), minSize ); + }; + } + + @Nonnull + @Override + public EdgeCases edgeCases( int maxEdgeCases ) + { + return EdgeCases.fromSuppliers( Arrays.asList( + () -> new ShrinkableBuffer( allocateRandom( minSize, new Random() ), minSize ), + () -> new ShrinkableBuffer( allocateRandom( getMaxSize(), new Random() ), minSize ) + ) ); + } + + private int getMaxSize() + { + return maxSize == null ? Math.max( minSize * 2, 255 ) : maxSize; + } + + private static ToIntFunction sizeGeneratorWithCutoff( int minSize, int maxSize, int genSize ) + { + // If we've a large range, we either pick between generating small (<10) or large lists. + int range = maxSize - minSize; + int offset = (int) Math.max( Math.round( Math.sqrt( genSize ) ), 10 ); + int cutoff = range <= offset ? maxSize : Math.min( offset + minSize, maxSize ); + + if( cutoff >= maxSize ) return random -> nextInt( random, minSize, maxSize ); + + // Choose size below cutoff with probability of 0.1. + double maxSizeProbability = Math.min( 0.02, 1.0 / (genSize / 10.0) ); + double cutoffProbability = 0.1; + return random -> { + if( random.nextDouble() <= maxSizeProbability ) + { + return maxSize; + } + else if( random.nextDouble() <= cutoffProbability + maxSizeProbability ) + { + return nextInt( random, cutoff + 1, maxSize ); + } + else + { + return nextInt( random, minSize, cutoff ); + } + }; + } + + private static int nextInt( Random random, int minSize, int maxSize ) + { + return random.nextInt( maxSize - minSize + 1 ) + minSize; + } + + private static ByteBuffer allocateRandom( int size, Random random ) + { + ByteBuffer buffer = ByteBuffer.allocate( size ); + + for( int i = 0; i < size; i++ ) buffer.put( i, (byte) random.nextInt() ); + return buffer.asReadOnlyBuffer(); + } + + private static final class ShrinkableBuffer implements Shrinkable + { + private final ByteBuffer value; + private final int minSize; + + private ShrinkableBuffer( ByteBuffer value, int minSize ) + { + this.value = value; + this.minSize = minSize; + } + + @Nonnull + @Override + public ByteBuffer value() + { + return value; + } + + @Nonnull + @Override + public Stream> shrink() + { + return StreamSupport.stream( new Spliterators.AbstractSpliterator>( 3, 0 ) + { + int size = value.remaining(); + + @Override + public boolean tryAdvance( Consumer> action ) + { + if( size <= minSize ) return false; + + int half = (size / 2) - (minSize / 2); + size = half == 0 ? minSize : size - half; + + ByteBuffer slice = value.duplicate(); + slice.limit( size ); + action.accept( new ShrinkableBuffer( slice.slice(), minSize ) ); + return true; + } + }, false ); + } + + @Nonnull + @Override + public ShrinkingDistance distance() + { + return ShrinkingDistance.of( value.remaining() - minSize ); + } + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java b/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java new file mode 100644 index 000000000..c0f801b4c --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java @@ -0,0 +1,75 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.nio.ByteBuffer; + +public final class ByteBufferMatcher extends TypeSafeMatcher +{ + private final ByteBuffer expected; + + private ByteBufferMatcher( ByteBuffer expected ) + { + this.expected = expected; + } + + @Override + protected boolean matchesSafely( ByteBuffer actual ) + { + return expected.equals( actual ); + } + + @Override + public void describeTo( Description description ) + { + description.appendValue( expected ); + } + + @Override + protected void describeMismatchSafely( ByteBuffer actual, Description mismatchDescription ) + { + if( expected.remaining() != actual.remaining() ) + { + mismatchDescription + .appendValue( actual ).appendText( " has " ).appendValue( actual.remaining() ).appendText( " bytes remaining" ); + return; + } + + int remaining = expected.remaining(); + int expectedPos = expected.position(); + int actualPos = actual.position(); + for( int i = 0; i < remaining; i++ ) + { + if( expected.get( expectedPos + i ) == actual.get( actualPos + i ) ) continue; + + int offset = Math.max( i - 5, 0 ); + int length = Math.min( i + 5, remaining - 1 ) - offset + 1; + + byte[] expectedBytes = new byte[length]; + expected.duplicate().position( expectedPos + offset ); + expected.get( expectedBytes ); + + byte[] actualBytes = new byte[length]; + actual.duplicate().position( actualPos + offset ); + actual.get( actualBytes ); + + mismatchDescription + .appendText( "failed at " ).appendValue( i ).appendText( System.lineSeparator() ) + .appendText( "expected " ).appendValue( expectedBytes ).appendText( System.lineSeparator() ) + .appendText( "was " ).appendValue( actual ); + return; + } + } + + public static Matcher bufferEqual( ByteBuffer buffer ) + { + return new ByteBufferMatcher( buffer ); + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java b/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java new file mode 100644 index 000000000..5916f865b --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java @@ -0,0 +1,34 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CallCounter implements Runnable +{ + private int timesCalled = 0; + + @Override + public void run() + { + timesCalled++; + } + + public void assertCalledTimes( int expectedTimesCalled ) + { + assertEquals( expectedTimesCalled, timesCalled, "Callback was not called the correct number of times" ); + } + + public void assertNotCalled() + { + assertEquals( 0, timesCalled, "Should never have been called." ); + } + + public void reset() + { + this.timesCalled = 0; + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java b/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java new file mode 100644 index 000000000..4a982d558 --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java @@ -0,0 +1,45 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core; + +import org.hamcrest.FeatureMatcher; +import org.hamcrest.Matcher; + +import java.util.function.Function; + +/** + * Given some function from {@code T} to {@code U}, converts a {@code Matcher} to {@code Matcher}. This is useful + * when you want to match on a particular field (or some other projection) as part of a larger matcher. + * + * @param The type of the object to be matched. + * @param The type of the projection/field to be matched. + */ +public final class ContramapMatcher extends FeatureMatcher +{ + private final Function convert; + + public ContramapMatcher( String desc, Function convert, Matcher matcher ) + { + super( matcher, desc, desc ); + this.convert = convert; + } + + @Override + protected U featureValueOf( T actual ) + { + return convert.apply( actual ); + } + + public static Matcher contramap( Matcher matcher, String desc, Function convert ) + { + return new ContramapMatcher<>( desc, convert, matcher ); + } + + public static Matcher contramap( Matcher matcher, Function convert ) + { + return new ContramapMatcher<>( "-f(_)->", convert, matcher ); + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java b/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java new file mode 100644 index 000000000..e321ff855 --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java @@ -0,0 +1,31 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core; + +import org.hamcrest.Matcher; + +import java.util.List; +import java.util.function.Function; + +import static org.hamcrest.Matchers.contains; + +public class CustomMatchers +{ + /** + * Assert two lists are equal according to some matcher. + *

+ * This method is simple, but helps avoid some issues with generics we'd see otherwise. + * + * @param items The items the matched list should be equal to. + * @param matcher Generate a matcher for a single item in the list. + * @param The type to compare against. + * @return A matcher which compares against a list of items. + */ + public static Matcher> containsWith( List items, Function> matcher ) + { + return contains( items.stream().map( matcher ).toList() ); + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java b/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java new file mode 100644 index 000000000..28ecb964d --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java @@ -0,0 +1,161 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core.apis; + +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IWorkMonitor; +import dan200.computercraft.core.apis.IAPIEnvironment; +import dan200.computercraft.core.computer.ComputerEnvironment; +import dan200.computercraft.core.computer.ComputerSide; +import dan200.computercraft.core.computer.GlobalEnvironment; +import dan200.computercraft.core.filesystem.FileSystem; +import dan200.computercraft.core.metrics.Metric; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.test.core.computer.BasicEnvironment; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public abstract class BasicApiEnvironment implements IAPIEnvironment +{ + private final BasicEnvironment environment; + private @Nullable String label; + + public BasicApiEnvironment( BasicEnvironment environment ) + { + this.environment = environment; + } + + @Override + public int getComputerID() + { + return 0; + } + + @Nonnull + @Override + public ComputerEnvironment getComputerEnvironment() + { + return environment; + } + + @Nonnull + @Override + public GlobalEnvironment getGlobalEnvironment() + { + return environment; + } + + @Nonnull + @Override + public IWorkMonitor getMainThreadMonitor() + { + throw new IllegalStateException( "Main thread monitor not available" ); + } + + @Nonnull + @Override + public Terminal getTerminal() + { + throw new IllegalStateException( "Terminal not available" ); + } + + @Override + public FileSystem getFileSystem() + { + throw new IllegalStateException( "Filesystem not available" ); + } + + @Override + public void shutdown() + { + } + + @Override + public void reboot() + { + } + + @Override + public void setOutput( ComputerSide side, int output ) + { + } + + @Override + public int getOutput( ComputerSide side ) + { + return 0; + } + + @Override + public int getInput( ComputerSide side ) + { + return 0; + } + + @Override + public void setBundledOutput( ComputerSide side, int output ) + { + } + + @Override + public int getBundledOutput( ComputerSide side ) + { + return 0; + } + + @Override + public int getBundledInput( ComputerSide side ) + { + return 0; + } + + @Override + public void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener ) + { + } + + @Nullable + @Override + public IPeripheral getPeripheral( ComputerSide side ) + { + return null; + } + + @Nullable + @Override + public String getLabel() + { + return label; + } + + @Override + public void setLabel( @Nullable String label ) + { + this.label = label; + } + + @Override + public int startTimer( long ticks ) + { + throw new IllegalStateException( "Cannot start timers" ); + } + + @Override + public void cancelTimer( int id ) + { + } + + @Override + public void observe( @Nonnull Metric.Event summary, long value ) + { + } + + @Override + public void observe( @Nonnull Metric.Counter counter ) + { + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java b/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java new file mode 100644 index 000000000..8d48343a9 --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java @@ -0,0 +1,168 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core.computer; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.core.computer.ComputerEnvironment; +import dan200.computercraft.core.computer.GlobalEnvironment; +import dan200.computercraft.core.filesystem.FileMount; +import dan200.computercraft.core.filesystem.JarMount; +import dan200.computercraft.core.metrics.Metric; +import dan200.computercraft.core.metrics.MetricsObserver; +import dan200.computercraft.test.core.filesystem.MemoryMount; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * A basic implementation of {@link ComputerEnvironment} and {@link GlobalEnvironment}, suitable for a context which + * will only run a single computer. + */ +public class BasicEnvironment implements ComputerEnvironment, GlobalEnvironment, MetricsObserver +{ + private final IWritableMount mount; + + public BasicEnvironment() + { + this( new MemoryMount() ); + } + + public BasicEnvironment( IWritableMount mount ) + { + this.mount = mount; + } + + @Override + public IWritableMount createRootMount() + { + return mount; + } + + @Override + public int getDay() + { + return 0; + } + + @Override + public double getTimeOfDay() + { + return 0; + } + + @Override + public MetricsObserver getMetrics() + { + return this; + } + + @Nonnull + @Override + public String getHostString() + { + return "ComputerCraft 1.0 (Test environment)"; + } + + @Nonnull + @Override + public String getUserAgent() + { + return "ComputerCraft/1.0"; + } + + @Override + public IMount createResourceMount( String domain, String subPath ) + { + return createMount( ComputerCraft.class, "data/" + domain + "/" + subPath, "main" ); + } + + @Override + public InputStream createResourceFile( String domain, String subPath ) + { + return ComputerCraft.class.getClassLoader().getResourceAsStream( "data/" + domain + "/" + subPath ); + } + + public static IMount createMount( Class klass, String path, String fallback ) + { + File file = getContainingFile( klass ); + + if( file.isFile() ) + { + try + { + return new JarMount( file, path ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + } + else + { + File wholeFile = new File( file, path ); + + // If we don't exist, walk up the tree looking for resource folders + File baseFile = file; + while( baseFile != null && !wholeFile.exists() ) + { + baseFile = baseFile.getParentFile(); + wholeFile = new File( baseFile, "src/" + fallback + "/resources/" + path ); + } + + if( !wholeFile.exists() ) throw new IllegalStateException( "Cannot find ROM mount at " + file ); + + return new FileMount( wholeFile, 0 ); + } + } + + + private static File getContainingFile( Class klass ) + { + String path = klass.getProtectionDomain().getCodeSource().getLocation().getPath(); + int bangIndex = path.indexOf( "!" ); + + // Plain old file, so step up from dan200.computercraft. + if( bangIndex < 0 ) return new File( path ); + + path = path.substring( 0, bangIndex ); + URL url; + try + { + url = new URL( path ); + } + catch( MalformedURLException e ) + { + throw new IllegalStateException( e ); + } + + try + { + return new File( url.toURI() ); + } + catch( URISyntaxException e ) + { + return new File( url.getPath() ); + } + } + + @Override + public void observe( Metric.Counter counter ) + { + } + + @Override + public void observe( Metric.Event event, long value ) + { + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java b/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java new file mode 100644 index 000000000..8219d75db --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java @@ -0,0 +1,148 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core.filesystem; + +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.core.apis.handles.ArrayByteChannel; + +import javax.annotation.Nonnull; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.util.*; + +/** + * In-memory file mounts. + */ +public class MemoryMount implements IWritableMount +{ + private final Map files = new HashMap<>(); + private final Set directories = new HashSet<>(); + + public MemoryMount() + { + directories.add( "" ); + } + + + @Override + public void makeDirectory( @Nonnull String path ) + { + File file = new File( path ); + while( file != null ) + { + directories.add( file.getPath() ); + file = file.getParentFile(); + } + } + + @Override + public void delete( @Nonnull String path ) + { + if( files.containsKey( path ) ) + { + files.remove( path ); + } + else + { + directories.remove( path ); + for( String file : files.keySet().toArray( new String[0] ) ) + { + if( file.startsWith( path ) ) + { + files.remove( file ); + } + } + + File parent = new File( path ).getParentFile(); + if( parent != null ) delete( parent.getPath() ); + } + } + + @Nonnull + @Override + public WritableByteChannel openForWrite( @Nonnull final String path ) + { + return Channels.newChannel( new ByteArrayOutputStream() + { + @Override + public void close() throws IOException + { + super.close(); + files.put( path, toByteArray() ); + } + } ); + } + + @Nonnull + @Override + public WritableByteChannel openForAppend( @Nonnull final String path ) throws IOException + { + ByteArrayOutputStream stream = new ByteArrayOutputStream() + { + @Override + public void close() throws IOException + { + super.close(); + files.put( path, toByteArray() ); + } + }; + + byte[] current = files.get( path ); + if( current != null ) stream.write( current ); + + return Channels.newChannel( stream ); + } + + @Override + public long getRemainingSpace() + { + return 1000000L; + } + + @Override + public boolean exists( @Nonnull String path ) + { + return files.containsKey( path ) || directories.contains( path ); + } + + @Override + public boolean isDirectory( @Nonnull String path ) + { + return directories.contains( path ); + } + + @Override + public void list( @Nonnull String path, @Nonnull List files ) + { + for( String file : this.files.keySet() ) + { + if( file.startsWith( path ) ) files.add( file.substring( path.length() + 1 ) ); + } + } + + @Override + public long getSize( @Nonnull String path ) + { + throw new RuntimeException( "Not implemented" ); + } + + @Nonnull + @Override + public ReadableByteChannel openForRead( @Nonnull String path ) + { + return new ArrayByteChannel( files.get( path ) ); + } + + public MemoryMount addFile( String file, String contents ) + { + files.put( file, contents.getBytes() ); + return this; + } +} diff --git a/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java b/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java new file mode 100644 index 000000000..248883339 --- /dev/null +++ b/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java @@ -0,0 +1,54 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core.terminal; + +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.test.core.ContramapMatcher; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +import java.util.Arrays; + +public class TerminalMatchers +{ + public static Matcher textColourMatches( String[] x ) + { + return linesMatch( "text colour", Terminal::getTextColourLine, x ); + } + + public static Matcher backgroundColourMatches( String[] x ) + { + return linesMatch( "background colour", Terminal::getBackgroundColourLine, x ); + } + + public static Matcher textMatches( String[] x ) + { + return linesMatch( "text", Terminal::getLine, x ); + } + + @SuppressWarnings( "unchecked" ) + public static Matcher linesMatch( String kind, LineProvider getLine, String[] lines ) + { + return linesMatchWith( kind, getLine, Arrays.stream( lines ).map( Matchers::equalTo ).toArray( Matcher[]::new ) ); + } + + public static Matcher linesMatchWith( String kind, LineProvider getLine, Matcher[] lines ) + { + return ContramapMatcher.contramap( Matchers.array( lines ), kind, terminal -> { + String[] termLines = new String[terminal.getHeight()]; + for( int i = 0; i < termLines.length; i++ ) termLines[i] = getLine.getLine( terminal, i ).toString(); + return termLines; + } ); + } + + @FunctionalInterface + public interface LineProvider + { + TextBuffer getLine( Terminal terminal, int line ); + } + +} diff --git a/src/testFixtures/kotlin/dan200/computercraft/test/core/Assertions.kt b/src/testFixtures/kotlin/dan200/computercraft/test/core/Assertions.kt new file mode 100644 index 000000000..e83e80381 --- /dev/null +++ b/src/testFixtures/kotlin/dan200/computercraft/test/core/Assertions.kt @@ -0,0 +1,63 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core + +import org.hamcrest.BaseMatcher +import org.hamcrest.Description +import org.hamcrest.Matcher +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.collection.IsArray +import org.junit.jupiter.api.Assertions + +/** Postfix version of [Assertions.assertArrayEquals] */ +fun Array?.assertArrayEquals(vararg expected: Any?, message: String? = null) { + assertThat( + message ?: "", + this, + IsArrayVerbose(expected.map { FuzzyEqualTo(it) }.toTypedArray()), + ) +} + +/** + * Extension of [IsArray] which always prints the array, not just when the items are mismatched. + */ +internal class IsArrayVerbose(private val elementMatchers: Array>) : IsArray(elementMatchers) { + override fun describeMismatchSafely(actual: Array, description: Description) { + description.appendText("array was ").appendValue(actual) + if (actual.size != elementMatchers.size) { + description.appendText(" with length ").appendValue(actual.size) + return + } + + for (i in actual.indices) { + if (!elementMatchers[i].matches(actual[i])) { + description.appendText("with element ").appendValue(i).appendText(" ") + elementMatchers[i].describeMismatch(actual[i], description) + return + } + } + } +} + +/** + * An equality matcher which is slightly more relaxed on comparing some values. + */ +internal class FuzzyEqualTo(private val expected: Any?) : BaseMatcher() { + override fun describeTo(description: Description) { + description.appendValue(expected) + } + + override fun matches(actual: Any?): Boolean { + if (actual == null) return false + + if (actual is Number && expected is Number && actual.javaClass != expected.javaClass) { + // Allow equating integers and floats. + return actual.toDouble() == expected.toDouble() + } + + return actual == expected + } +} diff --git a/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt new file mode 100644 index 000000000..4805cb48f --- /dev/null +++ b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt @@ -0,0 +1,189 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.test.core.computer + +import dan200.computercraft.api.lua.ILuaAPI +import dan200.computercraft.core.ComputerContext +import dan200.computercraft.core.computer.Computer +import dan200.computercraft.core.computer.ComputerThread +import dan200.computercraft.core.computer.TimeoutState +import dan200.computercraft.core.computer.mainthread.NoWorkMainThreadScheduler +import dan200.computercraft.core.lua.MachineEnvironment +import dan200.computercraft.core.lua.MachineResult +import dan200.computercraft.core.terminal.Terminal +import java.util.* +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.Lock +import java.util.concurrent.locks.ReentrantLock + +typealias FakeComputerTask = (state: TimeoutState) -> MachineResult + +/** + * Creates "fake" computers, which just run user-defined tasks rather than Lua code. + */ +class KotlinComputerManager : AutoCloseable { + + private val machines: MutableMap> = HashMap() + private val context = ComputerContext(BasicEnvironment(), ComputerThread(1), NoWorkMainThreadScheduler()) { DummyLuaMachine(it) } + private val errorLock: Lock = ReentrantLock() + private val hasError = errorLock.newCondition() + + @Volatile + private var error: Throwable? = null + override fun close() { + try { + context.ensureClosed(1, TimeUnit.SECONDS) + } catch (e: InterruptedException) { + throw IllegalStateException("Runtime thread was interrupted", e) + } + } + + fun context(): ComputerContext { + return context + } + + /** + * Create a new computer which pulls from our task queue. + * + * @return The computer. This will not be started yet, you must call [Computer.turnOn] and + * [Computer.tick] to do so. + */ + fun create(): Computer { + val queue: Queue = ConcurrentLinkedQueue() + val computer = Computer(context, BasicEnvironment(), Terminal(51, 19, true), 0) + computer.addApi(QueuePassingAPI(queue)) // Inject an extra API to pass the queue to the machine. + machines[computer] = queue + return computer + } + + /** + * Create and start a new computer which loops forever. + */ + fun createLoopingComputer() { + val computer = create() + enqueueForever(computer) { + Thread.sleep(100) + MachineResult.OK + } + computer.turnOn() + computer.tick() + } + + /** + * Enqueue a task on a computer. + * + * @param computer The computer to enqueue the work on. + * @param task The task to run. + */ + fun enqueue(computer: Computer, task: FakeComputerTask) { + machines[computer]!!.offer(task) + } + + /** + * Enqueue a repeated task on a computer. This is automatically requeued when the task finishes, meaning the task + * queue is never empty. + * + * @param computer The computer to enqueue the work on. + * @param task The task to run. + */ + private fun enqueueForever(computer: Computer, task: FakeComputerTask) { + machines[computer]!!.offer { + val result = task(it) + enqueueForever(computer, task) + computer.queueEvent("some_event", null) + result + } + } + + /** + * Sleep for a given period, immediately propagating any exceptions thrown by a computer. + * + * @param delay The duration to sleep for. + * @param unit The time unit the duration is measured in. + * @throws Exception An exception thrown by a running computer. + */ + @Throws(Exception::class) + fun sleep(delay: Long, unit: TimeUnit?) { + errorLock.lock() + try { + rethrowIfNeeded() + if (hasError.await(delay, unit)) rethrowIfNeeded() + } finally { + errorLock.unlock() + } + } + + /** + * Start a computer and wait for it to finish. + * + * @param computer The computer to wait for. + * @throws Exception An exception thrown by a running computer. + */ + @Throws(Exception::class) + fun startAndWait(computer: Computer) { + computer.turnOn() + computer.tick() + do { + sleep(100, TimeUnit.MILLISECONDS) + } while (context.computerScheduler().hasPendingWork() || computer.isOn) + + rethrowIfNeeded() + } + + @Throws(Exception::class) + private fun rethrowIfNeeded() { + val error = error ?: return + throw error + } + + private class QueuePassingAPI constructor(val tasks: Queue) : ILuaAPI { + override fun getNames(): Array = arrayOf() + } + + private inner class DummyLuaMachine(private val environment: MachineEnvironment) : KotlinLuaMachine(environment) { + private var tasks: Queue? = null + override fun addAPI(api: ILuaAPI) { + super.addAPI(api) + if (api is QueuePassingAPI) tasks = api.tasks + } + + override fun getTask(): (suspend KotlinLuaMachine.() -> Unit)? { + try { + val tasks = this.tasks ?: throw NullPointerException("Not received tasks yet") + val task = tasks.remove() + return { + try { + task(environment.timeout) + } catch (e: Throwable) { + reportError(e) + } + } + } catch (e: Throwable) { + reportError(e) + return null + } + } + + override fun close() {} + + private fun reportError(e: Throwable) { + errorLock.lock() + try { + if (error == null) { + error = e + hasError.signal() + } else { + error!!.addSuppressed(e) + } + } finally { + errorLock.unlock() + } + + if (e is Exception || e is AssertionError) return else throw e + } + } +} diff --git a/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinLuaMachine.kt b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinLuaMachine.kt new file mode 100644 index 000000000..3e94dea31 --- /dev/null +++ b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinLuaMachine.kt @@ -0,0 +1,55 @@ +package dan200.computercraft.test.core.computer + +import dan200.computercraft.api.lua.ILuaAPI +import dan200.computercraft.api.lua.ILuaContext +import dan200.computercraft.core.lua.ILuaMachine +import dan200.computercraft.core.lua.MachineEnvironment +import dan200.computercraft.core.lua.MachineResult +import kotlinx.coroutines.* +import java.io.InputStream +import kotlin.coroutines.CoroutineContext + +/** + * An [ILuaMachine] which runs Kotlin functions instead. + */ +abstract class KotlinLuaMachine(environment: MachineEnvironment) : ILuaMachine, AbstractLuaTaskContext() { + override val context: ILuaContext = environment.context + + override fun addAPI(api: ILuaAPI) = addApi(api) + + override fun loadBios(bios: InputStream): MachineResult = MachineResult.OK + + override fun handleEvent(eventName: String?, arguments: Array?): MachineResult { + if (hasEventListeners) { + queueEvent(eventName, arguments) + } else { + val task = getTask() + if (task != null) CoroutineScope(NeverDispatcher() + CoroutineName("Computer")).launch { task() } + } + + return MachineResult.OK + } + + override fun printExecutionState(out: StringBuilder) {} + + /** + * Get the next task to execute on this computer. + */ + protected abstract fun getTask(): (suspend KotlinLuaMachine.() -> Unit)? + + /** + * A [CoroutineDispatcher] which only allows resuming from the computer thread. In practice, this means the only + * way to yield is with [pullEvent]. + */ + private class NeverDispatcher : CoroutineDispatcher() { + private val expectedGroup = Thread.currentThread().threadGroup + + override fun dispatch(context: CoroutineContext, block: Runnable) { + if (Thread.currentThread().threadGroup != expectedGroup) { + throw UnsupportedOperationException("Cannot perform arbitrary yields") + } + + block.run() + } + } +} diff --git a/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskContext.kt b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskContext.kt new file mode 100644 index 000000000..066045b87 --- /dev/null +++ b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskContext.kt @@ -0,0 +1,102 @@ +package dan200.computercraft.test.core.computer + +import dan200.computercraft.api.lua.ILuaAPI +import dan200.computercraft.api.lua.ILuaContext +import dan200.computercraft.api.lua.MethodResult +import dan200.computercraft.api.lua.ObjectArguments +import dan200.computercraft.core.apis.OSAPI +import dan200.computercraft.core.apis.PeripheralAPI +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.time.Duration + +/** + * The context for tasks which consume Lua objects. + * + * This provides helpers for converting CC's callback-based code into a more direct style based on Kotlin coroutines. + */ +interface LuaTaskContext { + /** The current Lua context, to be passed to method calls. */ + val context: ILuaContext + + /** Get a registered API. */ + fun getApi(api: Class): T + + /** Pull a Lua event */ + suspend fun pullEvent(event: String? = null): Array + + /** Resolve a [MethodResult] until completion, returning the resulting values. */ + suspend fun MethodResult.await(): Array? { + var result = this + while (true) { + val callback = result.callback + val values = result.result + + if (callback == null) return values + + val filter = if (values == null) null else values[0] as String? + result = callback.resume(pullEvent(filter)) + } + } + + /** Call a peripheral method. */ + suspend fun LuaTaskContext.callPeripheral(name: String, method: String, vararg args: Any?): Array? = + getApi().call(context, ObjectArguments(name, method, *args)).await() + + /** + * Sleep for the given duration. This uses the internal computer clock, so won't be accurate. + */ + suspend fun LuaTaskContext.sleep(duration: Duration) { + val timer = getApi().startTimer(duration.inWholeMilliseconds / 1000.0) + while (true) { + val event = pullEvent("timer") + if (event[0] == "timer" && event[1] is Number && (event[1] as Number).toInt() == timer) { + return + } + } + } +} + +/** Get a registered API. */ +inline fun LuaTaskContext.getApi(): T = getApi(T::class.java) + +abstract class AbstractLuaTaskContext : LuaTaskContext, AutoCloseable { + private val pullEvents = mutableListOf() + private val apis = mutableMapOf, ILuaAPI>() + + protected fun addApi(api: ILuaAPI) { + apis[api.javaClass] = api + } + + protected val hasEventListeners + get() = pullEvents.isNotEmpty() + + protected fun queueEvent(eventName: String?, arguments: Array?) { + val fullEvent: Array = when { + eventName == null && arguments == null -> arrayOf() + eventName != null && arguments == null -> arrayOf(eventName) + eventName == null && arguments != null -> arguments + else -> arrayOf(eventName, *arguments!!) + } + for (i in pullEvents.size - 1 downTo 0) { + val puller = pullEvents[i] + if (puller.name == null || puller.name == eventName || eventName == "terminate") { + pullEvents.removeAt(i) + puller.cont.resumeWith(Result.success(fullEvent)) + } + } + } + + override fun close() { + for (pullEvent in pullEvents) pullEvent.cont.cancel() + pullEvents.clear() + } + + final override fun getApi(api: Class): T = + api.cast(apis[api] ?: throw IllegalStateException("No API of type ${api.name}")) + + final override suspend fun pullEvent(event: String?): Array = + suspendCancellableCoroutine { cont -> pullEvents.add(PullEvent(event, cont)) } + + private class PullEvent(val name: String?, val cont: CancellableContinuation>) +} diff --git a/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskRunner.kt b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskRunner.kt new file mode 100644 index 000000000..4ac65d1cb --- /dev/null +++ b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/LuaTaskRunner.kt @@ -0,0 +1,64 @@ +package dan200.computercraft.test.core.computer + +import dan200.computercraft.api.lua.ILuaAPI +import dan200.computercraft.api.lua.ILuaContext +import dan200.computercraft.api.lua.LuaException +import dan200.computercraft.core.apis.IAPIEnvironment +import dan200.computercraft.test.core.apis.BasicApiEnvironment +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +class LuaTaskRunner : AbstractLuaTaskContext() { + private val eventStream: Channel = Channel(Channel.UNLIMITED) + private val apis = mutableListOf() + + val environment: IAPIEnvironment = object : BasicApiEnvironment(BasicEnvironment()) { + override fun queueEvent(event: String?, vararg args: Any?) { + if (eventStream.trySend(Event(event, args)).isFailure) { + throw IllegalStateException("Queue is full") + } + } + + override fun shutdown() { + super.shutdown() + eventStream.close() + } + } + override val context = + ILuaContext { throw LuaException("Cannot queue main thread task") } + + fun addApi(api: T): T { + super.addApi(api) + apis.add(api) + api.startup() + return api + } + + override fun close() { + environment.shutdown() + } + + private suspend fun run() { + for (event in eventStream) { + queueEvent(event.name, event.args) + } + } + + private class Event(val name: String?, val args: Array) + + companion object { + fun runTest(timeout: Duration = 5.seconds, fn: suspend LuaTaskRunner.() -> Unit) { + runBlocking { + withTimeout(timeout) { + val runner = LuaTaskRunner() + launch { runner.run() } + runner.use { fn(runner) } + } + } + } + } +} diff --git a/src/testMod/java/dan200/computercraft/export/Exporter.java b/src/testMod/java/dan200/computercraft/export/Exporter.java new file mode 100644 index 000000000..398c1fadc --- /dev/null +++ b/src/testMod/java/dan200/computercraft/export/Exporter.java @@ -0,0 +1,158 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.export; + +import com.google.common.io.MoreFiles; +import com.google.common.io.RecursiveDeleteOption; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import dan200.computercraft.ComputerCraft; +import net.minecraft.client.Minecraft; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.*; +import net.minecraftforge.registries.ForgeRegistries; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; + +/** + * Provides a {@literal /ccexport } command which exports icons and recipes for all ComputerCraft items. + */ +public class Exporter +{ + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + public static void register( CommandDispatcher dispatcher ) + { + dispatcher.register( + LiteralArgumentBuilder.literal( "ccexport" ) + .then( RequiredArgumentBuilder.argument( "path", StringArgumentType.string() ) + .executes( c -> { + run( c.getArgument( "name", String.class ) ); + return 0; + } ) ) ); + } + + private static void run( String path ) + { + Path output = new File( path ).getAbsoluteFile().toPath(); + if( !Files.isDirectory( output ) ) + { + Minecraft.getInstance().gui.getChat().addMessage( Component.literal( "Output path does not exist" ) ); + return; + } + + RenderSystem.assertOnRenderThread(); + try( ImageRenderer renderer = new ImageRenderer() ) + { + export( output, renderer ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + + Minecraft.getInstance().gui.getChat().addMessage( Component.literal( "Export finished!" ) ); + } + + private static void export( Path root, ImageRenderer renderer ) throws IOException + { + JsonDump dump = new JsonDump(); + + Set items = new HashSet<>(); + + // First find all CC items + for( Item item : ForgeRegistries.ITEMS ) + { + if( ForgeRegistries.ITEMS.getKey( item ).getNamespace().equals( ComputerCraft.MOD_ID ) ) items.add( item ); + } + + // Now find all CC recipes. + for( CraftingRecipe recipe : Minecraft.getInstance().level.getRecipeManager().getAllRecipesFor( RecipeType.CRAFTING ) ) + { + ItemStack result = recipe.getResultItem(); + if( !ForgeRegistries.ITEMS.getKey( result.getItem() ).getNamespace().equals( ComputerCraft.MOD_ID ) ) + { + continue; + } + if( result.hasTag() ) + { + ComputerCraft.log.warn( "Skipping recipe {} as it has NBT", recipe.getId() ); + continue; + } + + if( recipe instanceof ShapedRecipe shaped ) + { + JsonDump.Recipe converted = new JsonDump.Recipe( result ); + + for( int x = 0; x < shaped.getWidth(); x++ ) + { + for( int y = 0; y < shaped.getHeight(); y++ ) + { + Ingredient ingredient = shaped.getIngredients().get( x + y * shaped.getWidth() ); + if( ingredient.isEmpty() ) continue; + + converted.setInput( x + y * 3, ingredient, items ); + } + } + + dump.recipes.put( recipe.getId().toString(), converted ); + } + else if( recipe instanceof ShapelessRecipe shapeless ) + { + JsonDump.Recipe converted = new JsonDump.Recipe( result ); + + NonNullList ingredients = shapeless.getIngredients(); + for( int i = 0; i < ingredients.size(); i++ ) + { + converted.setInput( i, ingredients.get( i ), items ); + } + + dump.recipes.put( recipe.getId().toString(), converted ); + } + else + { + ComputerCraft.log.info( "Don't know how to handle recipe {}", recipe ); + } + } + + Path itemDir = root.resolve( "items" ); + if( Files.exists( itemDir ) ) MoreFiles.deleteRecursively( itemDir, RecursiveDeleteOption.ALLOW_INSECURE ); + + renderer.setupState(); + for( Item item : items ) + { + ItemStack stack = new ItemStack( item ); + ResourceLocation location = ForgeRegistries.ITEMS.getKey( item ); + + dump.itemNames.put( location.toString(), stack.getHoverName().getString() ); + renderer.captureRender( itemDir.resolve( location.getNamespace() ).resolve( location.getPath() + ".png" ), + () -> Minecraft.getInstance().getItemRenderer().renderAndDecorateFakeItem( stack, 0, 0 ) + ); + } + renderer.clearState(); + + try( Writer writer = Files.newBufferedWriter( root.resolve( "index.json" ) ) ) + { + GSON.toJson( dump, writer ); + } + } +} diff --git a/src/testMod/java/dan200/computercraft/export/ImageRenderer.java b/src/testMod/java/dan200/computercraft/export/ImageRenderer.java new file mode 100644 index 000000000..7d4c2955f --- /dev/null +++ b/src/testMod/java/dan200/computercraft/export/ImageRenderer.java @@ -0,0 +1,80 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.export; + +import com.mojang.blaze3d.pipeline.TextureTarget; +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.math.Matrix4f; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.FogRenderer; +import org.lwjgl.opengl.GL12; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +/** + * Utilities for saving OpenGL output to an image rather than displaying it on the screen. + */ +public class ImageRenderer implements AutoCloseable +{ + public static final int WIDTH = 64; + public static final int HEIGHT = 64; + + private final TextureTarget framebuffer = new TextureTarget( WIDTH, HEIGHT, true, Minecraft.ON_OSX ); + private final NativeImage image = new NativeImage( WIDTH, HEIGHT, Minecraft.ON_OSX ); + + private Matrix4f projectionMatrix; + + public ImageRenderer() + { + framebuffer.setClearColor( 0, 0, 0, 0 ); + framebuffer.clear( Minecraft.ON_OSX ); + } + + public void setupState() + { + projectionMatrix = RenderSystem.getProjectionMatrix(); + RenderSystem.setProjectionMatrix( Matrix4f.orthographic( 0, 16, 0, 16, 1000, 3000 ) ); + + var transform = RenderSystem.getModelViewStack(); + transform.setIdentity(); + transform.translate( 0.0f, 0.0f, -2000.0f ); + + FogRenderer.setupNoFog(); + } + + public void clearState() + { + RenderSystem.setProjectionMatrix( projectionMatrix ); + RenderSystem.getModelViewStack().popPose(); + } + + public void captureRender( Path output, Runnable render ) throws IOException + { + Files.createDirectories( output.getParent() ); + + framebuffer.bindWrite( true ); + RenderSystem.clear( GL12.GL_COLOR_BUFFER_BIT | GL12.GL_DEPTH_BUFFER_BIT, Minecraft.ON_OSX ); + render.run(); + framebuffer.unbindWrite(); + + framebuffer.bindRead(); + image.downloadTexture( 0, false ); + image.flipY(); + framebuffer.unbindRead(); + + image.writeToFile( output ); + } + + @Override + public void close() + { + image.close(); + framebuffer.destroyBuffers(); + } +} diff --git a/src/testMod/java/dan200/computercraft/export/JsonDump.java b/src/testMod/java/dan200/computercraft/export/JsonDump.java new file mode 100644 index 000000000..bc26f145d --- /dev/null +++ b/src/testMod/java/dan200/computercraft/export/JsonDump.java @@ -0,0 +1,66 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.export; + +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.*; + +public class JsonDump +{ + public Map itemNames = new TreeMap<>(); + public Map recipes = new TreeMap<>(); + + public static class Recipe + { + public final String[][] inputs = new String[9][]; + public String output; + public int count; + + public Recipe( ItemStack output ) + { + this.output = ForgeRegistries.ITEMS.getKey( output.getItem() ).toString(); + count = output.getCount(); + } + + public void setInput( int pos, Ingredient ingredient, Set trackedItems ) + { + if( ingredient.isEmpty() ) return; + + ItemStack[] items = ingredient.getItems(); + + // First try to simplify some tags to something easier. + for( ItemStack stack : items ) + { + Item item = stack.getItem(); + if( !canonicalItem.contains( item ) ) continue; + + trackedItems.add( item ); + inputs[pos] = new String[] { ForgeRegistries.ITEMS.getKey( item ).toString() }; + return; + } + + String[] itemIds = new String[items.length]; + for( int i = 0; i < items.length; i++ ) + { + Item item = items[i].getItem(); + trackedItems.add( item ); + itemIds[i] = ForgeRegistries.ITEMS.getKey( item ).toString(); + } + Arrays.sort( itemIds ); + + inputs[pos] = itemIds; + } + + private static final Set canonicalItem = new HashSet<>( Arrays.asList( + Items.GLASS_PANE, Items.STONE, Items.CHEST + ) ); + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java b/src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java similarity index 92% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java rename to src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java index cafe3839c..d4b82a347 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/api/ComputerState.java +++ b/src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java @@ -3,9 +3,9 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.api; +package dan200.computercraft.gametest.api; -import de.srendi.advancedperipherals.gametest.core.TestAPI; +import dan200.computercraft.gametest.core.TestAPI; import net.minecraft.gametest.framework.GameTestAssertException; import net.minecraft.gametest.framework.GameTestSequence; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java b/src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java similarity index 92% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java rename to src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java index 0e51d88df..be4684cb6 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/api/GameTestHolder.java +++ b/src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.api; +package dan200.computercraft.gametest.api; import net.minecraft.gametest.framework.GameTest; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java b/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java similarity index 97% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java rename to src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java index 24b40c610..de82eafe1 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/CCTestCommand.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java @@ -3,11 +3,11 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.core; +package dan200.computercraft.gametest.core; import com.mojang.brigadier.CommandDispatcher; import dan200.computercraft.ComputerCraft; -import de.srendi.advancedperipherals.mixin.gamtest.TestCommandAccessor; +import dan200.computercraft.mixin.gametest.TestCommandAccessor; import net.minecraft.ChatFormatting; import net.minecraft.commands.CommandSourceStack; import net.minecraft.core.BlockPos; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java b/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java similarity index 98% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java rename to src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java index 418ef3cdc..78638ad66 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/ClientHooks.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.core; +package dan200.computercraft.gametest.core; import net.minecraft.client.CloudStatus; import net.minecraft.client.Minecraft; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java b/src/testMod/java/dan200/computercraft/gametest/core/Copier.java similarity index 97% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java rename to src/testMod/java/dan200/computercraft/gametest/core/Copier.java index f171d8b51..df198af9d 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/Copier.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/Copier.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.core; +package dan200.computercraft.gametest.core; import com.google.common.io.MoreFiles; import com.google.common.io.RecursiveDeleteOption; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java similarity index 94% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java rename to src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java index f3e0761e3..c939f6900 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestAPI.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java @@ -3,14 +3,15 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.core; +package dan200.computercraft.gametest.core; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.IComputerSystem; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; -import de.srendi.advancedperipherals.gametest.api.ComputerState; +import dan200.computercraft.gametest.api.ComputerState; +import dan200.computercraft.gametest.api.TestExtensionsKt; import net.minecraft.gametest.framework.GameTestSequence; import java.util.Optional; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java b/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java similarity index 91% rename from src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java rename to src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java index 16d566967..45d8f69f3 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestHooks.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java @@ -3,9 +3,10 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.gametest.core; +package dan200.computercraft.gametest.core; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.gametest.api.Times; import dan200.computercraft.shared.computer.core.ServerContext; import net.minecraft.core.BlockPos; import net.minecraft.gametest.framework.GameTestRunner; @@ -29,7 +30,7 @@ public class TestHooks public static void init() { - //ServerContext.luaMachine = ManagedComputers.INSTANCE; + ServerContext.luaMachine = ManagedComputers.INSTANCE; ComputerCraftAPI.registerAPIFactory( TestAPI::new ); StructureUtils.testStructuresDir = sourceDir.resolve( "structures" ).toString(); } @@ -40,7 +41,7 @@ public static void onServerStarted( MinecraftServer server ) rules.getRule( GameRules.RULE_DAYLIGHT ).set( false, server ); ServerLevel world = server.getLevel( Level.OVERWORLD ); - if( world != null ) world.setDayTime( 12000 ); + if( world != null ) world.setDayTime( Times.NOON ); LOGGER.info( "Cleaning up after last run" ); GameTestRunner.clearAllTests( server.overworld(), new BlockPos( 0, -60, 0 ), GameTestTicker.SINGLETON, 200 ); diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java new file mode 100644 index 000000000..8cd8c760d --- /dev/null +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java @@ -0,0 +1,124 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.core; + +import dan200.computercraft.export.Exporter; +import dan200.computercraft.gametest.api.GameTestHolder; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestRegistry; +import net.minecraft.gametest.framework.StructureUtils; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.client.event.RegisterClientCommandsEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.RegisterCommandsEvent; +import net.minecraftforge.event.RegisterGameTestsEvent; +import net.minecraftforge.event.server.ServerStartedEvent; +import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.forgespi.language.ModFileScanData; +import net.minecraftforge.gametest.PrefixGameTestTemplate; +import org.objectweb.asm.Type; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Locale; +import java.util.function.Consumer; + +@Mod("advancedperipheralstest") +public class TestMod { + public TestMod() { + TestHooks.init(); + + var bus = MinecraftForge.EVENT_BUS; + bus.addListener(EventPriority.LOW, (ServerStartedEvent e) -> TestHooks.onServerStarted(e.getServer())); + bus.addListener((RegisterCommandsEvent e) -> CCTestCommand.register(e.getDispatcher())); + bus.addListener((RegisterClientCommandsEvent e) -> Exporter.register(e.getDispatcher())); + + var modBus = FMLJavaModLoadingContext.get().getModEventBus(); + modBus.addListener((RegisterGameTestsEvent event) -> { + var holder = Type.getType(GameTestHolder.class); + ModList.get().getAllScanData().stream() + .map(ModFileScanData::getAnnotations) + .flatMap(Collection::stream) + .filter(a -> holder.equals(a.annotationType())) + .forEach(x -> registerClass(x.clazz().getClassName(), event::register)); + }); + } + + + private static Class loadClass(String name) { + try { + return Class.forName(name, true, TestMod.class.getClassLoader()); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + private static void registerClass(String className, Consumer fallback) { + var klass = loadClass(className); + for (var method : klass.getDeclaredMethods()) { + var testInfo = method.getAnnotation(GameTest.class); + if (testInfo == null) { + fallback.accept(method); + continue; + } + + GameTestRegistry.getAllTestFunctions().add(turnMethodIntoTestFunction(method, testInfo)); + GameTestRegistry.getAllTestClassNames().add(className); + } + } + + /** + * Custom implementation of {@link GameTestRegistry#turnMethodIntoTestFunction(Method)} which makes + * {@link GameTest#template()} behave the same as Fabric, namely in that it points to a {@link ResourceLocation}, + * rather than a test-class-specific structure. + *

+ * This effectively acts as a global version of {@link PrefixGameTestTemplate}, just one which doesn't require Forge + * to be present. + * + * @param method The method to register. + * @param testInfo The test info. + * @return The constructed test function. + */ + private static TestFunction turnMethodIntoTestFunction(Method method, GameTest testInfo) { + var className = method.getDeclaringClass().getSimpleName().toLowerCase(Locale.ROOT); + var testName = className + "." + method.getName().toLowerCase(Locale.ROOT); + return new TestFunction( + testInfo.batch(), + testName, + testInfo.template().isEmpty() ? testName : testInfo.template(), + StructureUtils.getRotationForRotationSteps(testInfo.rotationSteps()), testInfo.timeoutTicks(), testInfo.setupTicks(), + testInfo.required(), testInfo.requiredSuccesses(), testInfo.attempts(), + turnMethodIntoConsumer(method) + ); + } + + private static Consumer turnMethodIntoConsumer(Method method) { + return value -> { + try { + Object instance = null; + if (!Modifier.isStatic(method.getModifiers())) { + instance = method.getDeclaringClass().getConstructor().newInstance(); + } + + method.invoke(instance, value); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } else { + throw new RuntimeException(e.getCause()); + } + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + }; + } +} diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java similarity index 92% rename from src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java rename to src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java index 553925f7e..8e66a929f 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestHelperAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.mixin.gamtest; +package dan200.computercraft.mixin.gametest; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.gametest.framework.GameTestInfo; diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java similarity index 89% rename from src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java rename to src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java index cf559e72f..b7e2a1846 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestInfoAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.mixin.gamtest; +package dan200.computercraft.mixin.gametest; import net.minecraft.gametest.framework.GameTestInfo; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java similarity index 90% rename from src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java rename to src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java index 29964ca5f..9e9dad1ab 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.mixin.gamtest; +package dan200.computercraft.mixin.gametest; import net.minecraft.gametest.framework.GameTestInfo; import net.minecraft.gametest.framework.GameTestSequence; diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java similarity index 91% rename from src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java rename to src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java index 619b94ec8..efc7293c7 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/GameTestSequenceMixin.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java @@ -3,9 +3,9 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.mixin.gamtest; +package dan200.computercraft.mixin.gametest; -import de.srendi.advancedperipherals.gametest.core.TestHooks; +import dan200.computercraft.gametest.core.TestHooks; import net.minecraft.gametest.framework.GameTestAssertException; import net.minecraft.gametest.framework.GameTestInfo; import net.minecraft.gametest.framework.GameTestSequence; @@ -19,7 +19,7 @@ class GameTestSequenceMixin { @Shadow @Final - public GameTestInfo parent; + GameTestInfo parent; /** * Override {@link GameTestSequence#tickAndContinue(long)} to catch non-{@link GameTestAssertException} failures. diff --git a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java similarity index 91% rename from src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java rename to src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java index 6b057e31a..70ce8ee55 100644 --- a/src/testMod/java/de/srendi/advancedperipherals/mixin/gamtest/TestCommandAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java @@ -3,7 +3,7 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package de.srendi.advancedperipherals.mixin.gamtest; +package dan200.computercraft.mixin.gametest; import net.minecraft.commands.CommandSourceStack; import net.minecraft.gametest.framework.TestCommand; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java deleted file mode 100644 index 9d8d5f4b3..000000000 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/core/TestMod.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package de.srendi.advancedperipherals.gametest.core; - -import de.srendi.advancedperipherals.gametest.api.GameTestHolder; -import net.minecraft.gametest.framework.GameTest; -import net.minecraft.gametest.framework.GameTestRegistry; -import net.minecraft.gametest.framework.StructureUtils; -import net.minecraft.gametest.framework.TestFunction; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.client.event.RegisterClientCommandsEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.RegisterCommandsEvent; -import net.minecraftforge.event.RegisterGameTestsEvent; -import net.minecraftforge.event.server.ServerStartedEvent; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.forgespi.language.ModFileScanData; -import net.minecraftforge.gametest.PrefixGameTestTemplate; -import org.objectweb.asm.Type; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Locale; -import java.util.function.Consumer; - -@Mod( "advancedperipheralstest" ) -public class TestMod -{ - public TestMod() - { - TestHooks.init(); - - var bus = MinecraftForge.EVENT_BUS; - bus.addListener( EventPriority.LOW, ( ServerStartedEvent e ) -> TestHooks.onServerStarted( e.getServer() ) ); - bus.addListener( ( RegisterCommandsEvent e ) -> CCTestCommand.register( e.getDispatcher() ) ); - - var modBus = FMLJavaModLoadingContext.get().getModEventBus(); - modBus.addListener( ( RegisterGameTestsEvent event ) -> { - var holder = Type.getType( GameTestHolder.class ); - ModList.get().getAllScanData().stream() - .map( ModFileScanData::getAnnotations ) - .flatMap( Collection::stream ) - .filter( a -> holder.equals( a.annotationType() ) ) - .forEach( x -> registerClass( x.clazz().getClassName(), event::register ) ); - } ); - } - - - private static Class loadClass( String name ) - { - try - { - return Class.forName( name, true, TestMod.class.getClassLoader() ); - } - catch( ReflectiveOperationException e ) - { - throw new RuntimeException( e ); - } - } - - private static void registerClass( String className, Consumer fallback ) - { - var klass = loadClass( className ); - for( var method : klass.getDeclaredMethods() ) - { - var testInfo = method.getAnnotation( GameTest.class ); - if( testInfo == null ) - { - fallback.accept( method ); - continue; - } - - GameTestRegistry.getAllTestFunctions().add( turnMethodIntoTestFunction( method, testInfo ) ); - GameTestRegistry.getAllTestClassNames().add( className ); - } - } - - /** - * Custom implementation of {@link GameTestRegistry#turnMethodIntoTestFunction(Method)} which makes - * {@link GameTest#template()} behave the same as Fabric, namely in that it points to a {@link ResourceLocation}, - * rather than a test-class-specific structure. - *

- * This effectively acts as a global version of {@link PrefixGameTestTemplate}, just one which doesn't require Forge - * to be present. - * - * @param method The method to register. - * @param testInfo The test info. - * @return The constructed test function. - */ - private static TestFunction turnMethodIntoTestFunction( Method method, GameTest testInfo ) - { - var className = method.getDeclaringClass().getSimpleName().toLowerCase( Locale.ROOT ); - var testName = className + "." + method.getName().toLowerCase( Locale.ROOT ); - return new TestFunction( - testInfo.batch(), - testName, - testInfo.template().isEmpty() ? testName : testInfo.template(), - StructureUtils.getRotationForRotationSteps( testInfo.rotationSteps() ), testInfo.timeoutTicks(), testInfo.setupTicks(), - testInfo.required(), testInfo.requiredSuccesses(), testInfo.attempts(), - turnMethodIntoConsumer( method ) - ); - } - - private static Consumer turnMethodIntoConsumer( Method method ) - { - return value -> { - try - { - Object instance = null; - if( !Modifier.isStatic( method.getModifiers() ) ) - { - instance = method.getDeclaringClass().getConstructor().newInstance(); - } - - method.invoke( instance, value ); - } - catch( InvocationTargetException e ) - { - if( e.getCause() instanceof RuntimeException ) - { - throw (RuntimeException) e.getCause(); - } - else - { - throw new RuntimeException( e.getCause() ); - } - } - catch( ReflectiveOperationException e ) - { - throw new RuntimeException( e ); - } - }; - } -} diff --git a/src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java b/src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java new file mode 100644 index 000000000..209e996e5 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java @@ -0,0 +1,19 @@ +package de.srendi.advancedperipheralstest; + +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.gametest.PrefixGameTestTemplate; +import org.junit.jupiter.api.Assertions; + + +@GameTestHolder("advancedperipheralstest") +public class TestGameTests { + + @PrefixGameTestTemplate(false) + @GameTest(templateNamespace = "advancedperipheralstest") + public static void envDetectorTest(GameTestHelper helper) { + Assertions.assertEquals("Cock", "Cock"); + } + +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt new file mode 100644 index 000000000..8eec0fabf --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt @@ -0,0 +1,72 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.core.apis.RedstoneAPI +import dan200.computercraft.core.computer.ComputerSide +import dan200.computercraft.gametest.api.* +import dan200.computercraft.test.core.computer.getApi +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.LeverBlock +import net.minecraft.world.level.block.RedstoneLampBlock + +@GameTestHolder +class Computer_Test { + /** + * Ensures redstone signals do not travel through computers. + * + * @see [#548](https://github.com/cc-tweaked/CC-Tweaked/issues/548) + */ + @GameTest + fun No_through_signal(context: GameTestHelper) = context.sequence { + val lamp = BlockPos(2, 2, 4) + val lever = BlockPos(2, 2, 0) + thenExecute { + context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should not be lit") + context.modifyBlock(lever) { x -> x.setValue(LeverBlock.POWERED, true) } + } + thenIdle(3) + thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should still not be lit") } + } + + /** + * Similar to the above, but with a repeater before the computer + */ + @GameTest + fun No_through_signal_reverse(context: GameTestHelper) = context.sequence { + val lamp = BlockPos(2, 2, 4) + val lever = BlockPos(2, 2, 0) + thenExecute { + context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should not be lit") + context.modifyBlock(lever) { x -> x.setValue(LeverBlock.POWERED, true) } + } + thenIdle(3) + thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should still not be lit") } + } + + @GameTest + fun Set_and_destroy(context: GameTestHelper) = context.sequence { + val lamp = BlockPos(2, 2, 3) + + thenOnComputer { getApi().setOutput(ComputerSide.BACK, true) } + thenIdle(3) + thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, true, "Lamp should be lit") } + thenExecute { context.setBlock(BlockPos(2, 2, 2), Blocks.AIR) } + thenIdle(4) + thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should not be lit") } + } + + @GameTest + fun Computer_peripheral(context: GameTestHelper) = context.sequence { + thenExecute { + context.assertPeripheral(BlockPos(3, 2, 2), type = "computer") + context.assertPeripheral(BlockPos(1, 2, 2), type = "turtle") + } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt new file mode 100644 index 000000000..0ec7e3427 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt @@ -0,0 +1,22 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.Timeouts +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenComputerOk +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper + +@GameTestHolder +class CraftOs_Test { + /** + * Sends a rednet message to another a computer and back again. + */ + @GameTest(timeoutTicks = Timeouts.COMPUTER_TIMEOUT) + fun Sends_basic_rednet_messages(context: GameTestHelper) = context.sequence { thenComputerOk("main") } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt new file mode 100644 index 000000000..a45cf0772 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt @@ -0,0 +1,55 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.core.apis.FSAPI +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenOnComputer +import dan200.computercraft.test.core.assertArrayEquals +import dan200.computercraft.test.core.computer.getApi +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.world.item.Items +import org.junit.jupiter.api.Assertions.assertEquals + +@GameTestHolder +class Disk_Drive_Test { + /** + * Ensure audio disks exist and we can play them. + * + * @see [#688](https://github.com/cc-tweaked/CC-Tweaked/issues/688) + */ + @GameTest + fun Audio_disk(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + callPeripheral("right", "hasAudio") + .assertArrayEquals(true, message = "Disk has audio") + + callPeripheral("right", "getAudioTitle") + .assertArrayEquals("C418 - 13", message = "Correct audio title") + } + } + + @GameTest + fun Ejects_disk(helper: GameTestHelper) = helper.sequence { + val stackAt = BlockPos(2, 2, 2) + thenOnComputer { callPeripheral("right", "ejectDisk") } + thenWaitUntil { helper.assertItemEntityPresent(Items.MUSIC_DISC_13, stackAt, 0.0) } + } + + @GameTest + fun Adds_removes_mount(helper: GameTestHelper) = helper.sequence { + thenIdle(2) + thenOnComputer { + getApi().getDrive("disk").assertArrayEquals("right") + callPeripheral("right", "ejectDisk") + } + thenIdle(2) + thenOnComputer { assertEquals(null, getApi().getDrive("disk")) } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt new file mode 100644 index 000000000..dd5b52121 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt @@ -0,0 +1,37 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.Structures +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.shared.Registry +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.entity.ChestBlockEntity +import net.minecraft.world.level.storage.loot.BuiltInLootTables + +@GameTestHolder +class Loot_Test { + /** + * Test that the loot tables will spawn in treasure disks. + */ + @GameTest(template = Structures.DEFAULT) + fun Chest_contains_disk(context: GameTestHelper) = context.sequence { + thenExecute { + val pos = BlockPos(2, 2, 2) + + context.setBlock(pos, Blocks.CHEST) + val chest = context.getBlockEntity(pos) as ChestBlockEntity + chest.setLootTable(BuiltInLootTables.SIMPLE_DUNGEON, 123) + chest.unpackLootTable(null) + + context.assertContainerContains(pos, Registry.ModItems.TREASURE_DISK.get()) + } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt new file mode 100644 index 000000000..a4b454ba3 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt @@ -0,0 +1,102 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.api.lua.ObjectArguments +import dan200.computercraft.core.apis.PeripheralAPI +import dan200.computercraft.core.computer.ComputerSide +import dan200.computercraft.gametest.api.* +import dan200.computercraft.shared.peripheral.modem.wired.BlockCable +import dan200.computercraft.test.core.assertArrayEquals +import dan200.computercraft.test.core.computer.LuaTaskContext +import dan200.computercraft.test.core.computer.getApi +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper +import org.junit.jupiter.api.Assertions.assertEquals +import kotlin.time.Duration.Companion.milliseconds + +@GameTestHolder +class Modem_Test { + @GameTest + fun Have_peripherals(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + assertEquals(listOf("monitor_0", "printer_0", "right"), getPeripheralNames(), "Starts with peripherals") + } + } + + @GameTest + fun Gains_peripherals(helper: GameTestHelper) = helper.sequence { + val position = BlockPos(2, 2, 2) + thenOnComputer { + assertEquals(listOf("back"), getPeripheralNames(), "Starts with peripherals") + } + thenExecute { + helper.setBlock( + position, + BlockCable.correctConnections( + helper.level, + helper.absolutePos(position), + dan200.computercraft.shared.Registry.ModBlocks.CABLE.get().defaultBlockState().setValue(BlockCable.CABLE, true), + ), + ) + } + thenIdle(1) + thenOnComputer { + assertEquals(listOf("back", "monitor_1", "printer_1"), getPeripheralNames(), "Gains new peripherals") + } + } + + /** + * Sends a modem message to another computer on the same network + */ + @GameTest + fun Transmits_messages(context: GameTestHelper) = context.sequence { + thenStartComputer("send") { + val modem = findPeripheral("modem") ?: throw IllegalStateException("Cannot find modem") + while (true) { + callPeripheral(modem, "transmit", 12, 34, "Hello") + sleep(50.milliseconds) + } + } + thenOnComputer("receive") { + val modem = findPeripheral("modem") ?: throw IllegalStateException("Cannot find modem") + callPeripheral(modem, "open", 12) + + pullEvent("modem_message") + .assertArrayEquals("modem_message", "left", 12, 34, "Hello", 4, message = "Modem message") + } + } +} + +private fun LuaTaskContext.findPeripheral(type: String): String? { + val peripheral = getApi() + for (side in ComputerSide.NAMES) { + val hasType = peripheral.hasType(side, type) + if (hasType != null && hasType[0] == true) return side + } + + return null +} + +private suspend fun LuaTaskContext.getPeripheralNames(): List { + val peripheral = getApi() + val peripherals = mutableListOf() + for (side in ComputerSide.NAMES) { + if (!peripheral.isPresent(side)) continue + peripherals.add(side) + + val hasType = peripheral.hasType(side, "modem") + if (hasType == null || hasType[0] != true) continue + + val names = peripheral.call(context, ObjectArguments(side, "getNamesRemote")).await() ?: continue + @Suppress("UNCHECKED_CAST") + peripherals.addAll(names[0] as Collection) + } + + peripherals.sort() + return peripherals +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt new file mode 100644 index 000000000..e34ba16d3 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt @@ -0,0 +1,50 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.getBlockEntity +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.setBlock +import dan200.computercraft.shared.Registry +import net.minecraft.commands.arguments.blocks.BlockInput +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.nbt.CompoundTag +import net.minecraft.world.level.block.Blocks +import java.util.* + +@GameTestHolder +class Monitor_Test { + @GameTest + fun Ensures_valid_on_place(context: GameTestHelper) = context.sequence { + val pos = BlockPos(2, 2, 2) + + thenExecute { + val tag = CompoundTag() + tag.putInt("Width", 2) + tag.putInt("Height", 2) + + val toSet = BlockInput( + Registry.ModBlocks.MONITOR_ADVANCED.get().defaultBlockState(), + Collections.emptySet(), + tag, + ) + + context.setBlock(pos, Blocks.AIR.defaultBlockState()) + context.setBlock(pos, toSet) + } + thenIdle(2) + thenExecute { + val tile = context.getBlockEntity(pos, Registry.ModBlockEntities.MONITOR_ADVANCED.get()) + + if (tile.width != 1 || tile.height != 1) { + context.fail("Tile has width and height of ${tile.width}x${tile.height}, but should be 1x1", pos) + } + } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt new file mode 100644 index 000000000..9e9fc868c --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt @@ -0,0 +1,65 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.Structures +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.shared.Registry +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestAssertException +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.nbt.CompoundTag +import net.minecraft.world.entity.player.Player +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.inventory.CraftingContainer +import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.item.crafting.CraftingRecipe +import net.minecraft.world.item.crafting.RecipeType +import org.junit.jupiter.api.Assertions.assertEquals +import java.util.* + +@GameTestHolder +class Recipe_Test { + /** + * Test that crafting results contain NBT data. + * + * Mostly useful for Fabric, where we need a mixin for this. + */ + @GameTest(template = Structures.DEFAULT) + fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence { + thenExecute { + val container = CraftingContainer(DummyMenu, 3, 3) + container.setItem(0, ItemStack(Items.SKELETON_SKULL)) + container.setItem(1, ItemStack(Registry.ModItems.COMPUTER_ADVANCED.get())) + + val recipe: Optional = context.level.server.recipeManager + .getRecipeFor(RecipeType.CRAFTING, container, context.level) + if (!recipe.isPresent) throw GameTestAssertException("No recipe matches") + + val result = recipe.get().assemble(container) + + val owner = CompoundTag() + owner.putString("Name", "dan200") + owner.putString("Id", "f3c8d69b-0776-4512-8434-d1b2165909eb") + val tag = CompoundTag() + tag.put("SkullOwner", owner) + + + if (tag.equals(result.tag)) { + context.succeed(); + } + context.fail("Expected NBT tags to be the same") + } + } + + object DummyMenu : AbstractContainerMenu(MenuType.GENERIC_9x1, 0) { + override fun quickMoveStack(player: Player, slot: Int): ItemStack = ItemStack.EMPTY + override fun stillValid(p0: Player): Boolean = true + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt new file mode 100644 index 000000000..0548fbd46 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt @@ -0,0 +1,384 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest + +import dan200.computercraft.api.detail.BasicItemDetailProvider +import dan200.computercraft.api.detail.VanillaDetailRegistries +import dan200.computercraft.api.lua.ObjectArguments +import dan200.computercraft.core.apis.PeripheralAPI +import dan200.computercraft.gametest.api.* +import dan200.computercraft.shared.Registry +import dan200.computercraft.shared.media.items.ItemPrintout +import dan200.computercraft.shared.peripheral.monitor.BlockMonitor +import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState +import dan200.computercraft.shared.turtle.apis.TurtleAPI +import dan200.computercraft.shared.util.WaterloggableHelpers +import dan200.computercraft.test.core.assertArrayEquals +import dan200.computercraft.test.core.computer.LuaTaskContext +import dan200.computercraft.test.core.computer.getApi +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.item.PrimedTnt +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.FenceBlock +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.array +import org.hamcrest.Matchers.instanceOf +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotEquals +import java.util.* + +@GameTestHolder +class Turtle_Test { + @GameTest + fun Unequip_refreshes_peripheral(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + getApi().getType("right").assertArrayEquals("modem", message = "Starts with a modem") + turtle.equipRight().await() + getApi().getType("right").assertArrayEquals("drive", message = "Unequipping gives a drive") + } + } + + /** + * Checks turtles can sheer sheep (and drop items) + * + * @see [#537](https://github.com/cc-tweaked/CC-Tweaked/issues/537) + */ + @GameTest + fun Shears_sheep(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.placeDown(ObjectArguments()).await() + .assertArrayEquals(true, message = "Shears the sheep") + + assertEquals("minecraft:white_wool", getTurtleItemDetail(2)["name"]) + } + } + + /** + * Checks turtles can place lava. + * + * @see [#518](https://github.com/cc-tweaked/CC-Tweaked/issues/518) + */ + @GameTest + fun Place_lava(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.placeDown(ObjectArguments()).await() + .assertArrayEquals(true, message = "Placed lava") + } + thenExecute { helper.assertBlockPresent(Blocks.LAVA, BlockPos(2, 2, 2)) } + } + + /** + * Checks turtles can place when waterlogged. + * + * @see [#385](https://github.com/cc-tweaked/CC-Tweaked/issues/385) + */ + @GameTest + fun Place_waterlogged(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.place(ObjectArguments()).await() + .assertArrayEquals(true, message = "Placed oak fence") + } + thenExecute { + helper.assertBlockIs(BlockPos(2, 2, 2), { it.block == Blocks.OAK_FENCE && it.getValue(FenceBlock.WATERLOGGED) }) + } + } + + /** + * Checks turtles can pick up lava + * + * @see [#297](https://github.com/cc-tweaked/CC-Tweaked/issues/297) + */ + @GameTest + fun Gather_lava(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.placeDown(ObjectArguments()).await() + .assertArrayEquals(true, message = "Picked up lava") + + assertEquals("minecraft:lava_bucket", getTurtleItemDetail()["name"]) + } + thenExecute { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) } + } + + /** + * Checks turtles can hoe dirt. + * + * @see [#258](https://github.com/cc-tweaked/CC-Tweaked/issues/258) + */ + @GameTest + fun Hoe_dirt(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.dig(Optional.empty()).await() + .assertArrayEquals(true, message = "Dug with hoe") + } + thenExecute { helper.assertBlockPresent(Blocks.FARMLAND, BlockPos(1, 2, 1)) } + } + + /** + * Checks turtles can place monitors + * + * @see [#691](https://github.com/cc-tweaked/CC-Tweaked/issues/691) + */ + @GameTest + fun Place_monitor(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.place(ObjectArguments()).await() + .assertArrayEquals(true, message = "Block was placed") + } + thenIdle(1) + thenExecute { helper.assertBlockHas(BlockPos(1, 2, 3), BlockMonitor.STATE, MonitorEdgeState.LR) } + } + + /** + * Checks turtles can place into compostors. These are non-typical inventories, so + * worth testing. + */ + @GameTest + fun Use_compostors(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + turtle.dropDown(Optional.empty()).await() + .assertArrayEquals(true, message = "Item was dropped") + assertEquals(63, turtle.getItemCount(Optional.of(1)), "Only dropped one item") + } + } + + /** + * Checks turtles can be cleaned in cauldrons. + */ + @GameTest + fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence { + thenOnComputer { + val details = getTurtleItemDetail(1, true) + turtle.place(ObjectArguments()).await() + .assertArrayEquals(true, message = "Used item on cauldron") + val newDetails = getTurtleItemDetail(1, true) + + assertEquals("computercraft:turtle_normal", newDetails["name"], "Still a turtle") + assertNotEquals(details["nbt"], newDetails["nbt"], "Colour should have changed") + } + } + + /** + * Checks turtles can use IDetailProviders by getting details for a printed page. + */ + @GameTest + fun Item_detail_provider(helper: GameTestHelper) = helper.sequence { + // Register a dummy provider for printout items + thenExecute { + VanillaDetailRegistries.ITEM_STACK.addProvider( + object : + BasicItemDetailProvider("printout", ItemPrintout::class.java) { + override fun provideDetails(data: MutableMap, stack: ItemStack, item: ItemPrintout) { + data["type"] = item.type.toString().lowercase() + } + }, + ) + } + thenOnComputer { + val details = getTurtleItemDetail(detailed = true) + assertEquals(mapOf("type" to "page"), details["printout"]) { + "Printout information is returned (whole map is $details)" + } + } + } + + /** + * Advanced turtles resist all explosions but normal ones don't. + */ + @GameTest + fun Resists_explosions(helper: GameTestHelper) = helper.sequence { + thenExecute { + val pos = helper.absolutePos(BlockPos(2, 2, 2)) + val tnt = PrimedTnt(helper.level, pos.x + 0.5, pos.y + 1.0, pos.z + 0.5, null) + tnt.fuse = 1 + helper.level.addFreshEntity(tnt) + } + thenWaitUntil { helper.assertEntityNotPresent(EntityType.TNT) } + thenExecute { + helper.assertBlockPresent(Registry.ModBlocks.TURTLE_ADVANCED.get(), BlockPos(2, 2, 2)) + helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 1)) + } + } + + /** + * Turtles resist mob explosions + */ + @GameTest + fun Resists_entity_explosions(helper: GameTestHelper) = helper.sequence { + thenExecute { helper.getEntity(EntityType.CREEPER).ignite() } + thenWaitUntil { helper.assertEntityNotPresent(EntityType.CREEPER) } + thenExecute { + helper.assertBlockPresent(Registry.ModBlocks.TURTLE_ADVANCED.get(), BlockPos(2, 2, 2)) + helper.assertBlockPresent(Registry.ModBlocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 1)) + } + } + + /** + * Test calling `turtle.drop` into an inventory. + */ + @GameTest + fun Drop_into_chest(helper: GameTestHelper) = helper.sequence { + val turtlePos = BlockPos(2, 2, 2) + val chest = BlockPos(2, 2, 3) + + thenOnComputer { + turtle.drop(Optional.of(32)).await() + .assertArrayEquals(true, message = "Could not drop items") + } + thenExecute { + helper.assertContainerExactly(turtlePos, listOf(ItemStack(Blocks.DIRT, 32), ItemStack.EMPTY, ItemStack(Blocks.DIRT, 32))) + helper.assertContainerExactly(chest, listOf(ItemStack(Blocks.DIRT, 48))) + } + } + + /** + * Test calling `turtle.drop` into an entity with an inventory + */ + @GameTest + fun Drop_into_entity(helper: GameTestHelper) = helper.sequence { + // When running /test runthis, the previous items pop from the chest. Remove them first! + thenExecute { for (it in helper.getEntities(EntityType.ITEM)) it.discard() } + + thenOnComputer { + turtle.drop(Optional.of(32)).await() + .assertArrayEquals(true, message = "Could not drop items") + } + thenExecute { + helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Blocks.DIRT, 32))) + helper.assertContainerExactly(helper.getEntity(EntityType.CHEST_MINECART), listOf(ItemStack(Blocks.DIRT, 48))) + helper.assertEntityNotPresent(EntityType.ITEM) + } + } + + /** + * Test calling `turtle.refuel` on solid fuels (coal, blaze powder) + */ + @GameTest + fun Refuel_basic(helper: GameTestHelper) = helper.sequence { + val turtlePos = BlockPos(2, 2, 2) + + // Test refueling from slot 1 with no limit. + thenOnComputer { + assertEquals(0, turtle.fuelLevel) + turtle.refuel(Optional.empty()).await().assertArrayEquals(true) + assertEquals(160, turtle.fuelLevel) + } + thenExecute { + helper.assertContainerExactly(turtlePos, listOf(ItemStack.EMPTY, ItemStack(Items.BLAZE_ROD, 2))) + } + + // Test refueling from slot 2 with a limit. + thenOnComputer { + turtle.select(2) + turtle.refuel(Optional.of(1)).await().assertArrayEquals(true) + assertEquals(280, turtle.fuelLevel) + } + thenExecute { + helper.assertContainerExactly(turtlePos, listOf(ItemStack.EMPTY, ItemStack(Items.BLAZE_ROD, 1))) + } + } + + /** + * Test calling `turtle.refuel` with a bucket of lava + */ + @GameTest + fun Refuel_container(helper: GameTestHelper) = helper.sequence { + val turtlePos = BlockPos(2, 2, 2) + + // Test refueling from slot 1 with no limit. + thenOnComputer { + assertEquals(0, turtle.fuelLevel) + turtle.refuel(Optional.empty()).await().assertArrayEquals(true) + assertEquals(1000, turtle.fuelLevel) + } + thenExecute { + helper.assertContainerExactly(turtlePos, listOf(ItemStack(Items.BUCKET))) + } + } + + /** + * Test turtles are not obstructed by plants and instead replace them. + */ + @GameTest + fun Move_replace(helper: GameTestHelper) = helper.sequence { + thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") } + thenExecute { helper.assertBlockPresent(Registry.ModBlocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 3)) } + } + + /** + * Test turtles become waterlogged when moving through liquid. + */ + @GameTest + fun Move_water(helper: GameTestHelper) = helper.sequence { + thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") } + thenExecute { + // Assert we're waterlogged. + helper.assertBlockHas(BlockPos(2, 2, 2), WaterloggableHelpers.WATERLOGGED, true) + } + thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") } + thenExecute { + // Assert we're no longer waterlogged and we've left a source block. + helper.assertBlockIs(BlockPos(2, 2, 2), { it.block == Blocks.WATER && it.fluidState.isSource }) + helper.assertBlockHas(BlockPos(2, 2, 3), WaterloggableHelpers.WATERLOGGED, false) + } + } + + /** + * Test turtles can't move through solid blocks. + */ + @GameTest + fun Move_obstruct(helper: GameTestHelper) = helper.sequence { + thenOnComputer { turtle.forward().await().assertArrayEquals(false, "Movement obstructed") } + thenExecute { + helper.assertBlockPresent(Registry.ModBlocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 2)) + helper.assertBlockPresent(Blocks.DIRT, BlockPos(2, 2, 3)) + } + } + + /** + * Test a turtle can attack an entity and capture its drops. + */ + @GameTest + fun Attack_entity(helper: GameTestHelper) = helper.sequence { + val turtlePos = BlockPos(2, 2, 2) + thenOnComputer { + turtle.attack(Optional.empty()).await().assertArrayEquals(true, message = "Attacked entity") + } + thenExecute { + helper.assertEntityNotPresent(EntityType.SHEEP) + val count = helper.getBlockEntity(turtlePos, Registry.ModBlockEntities.TURTLE_NORMAL.get()).countItem(Items.WHITE_WOOL) + if (count == 0) helper.fail("Expected turtle to have white wool", turtlePos) + } + } + + /** + * Test a turtle can be destroyed while performing an action. + * + * @see [#585](https://github.com/cc-tweaked/CC-Tweaked/issues/585) + */ + @GameTest + fun Attack_entity_destroy(helper: GameTestHelper) = helper.sequence { + thenStartComputer { turtle.attack(Optional.empty()) } + thenWaitUntil { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) } + } + + // TODO: Ghost peripherals? + // TODO: Turtle sucking from items +} + +private val LuaTaskContext.turtle get() = getApi() + +private suspend fun LuaTaskContext.getTurtleItemDetail(slot: Int = 1, detailed: Boolean = false): Map { + val item = turtle.getItemDetail(context, Optional.of(slot), Optional.of(detailed)).await() + assertThat("Returns details", item, array(instanceOf(Map::class.java))) + + @Suppress("UNCHECKED_CAST") + return item!![0] as Map +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt new file mode 100644 index 000000000..ef3227d80 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt @@ -0,0 +1,248 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.api + +import dan200.computercraft.gametest.core.ManagedComputers +import dan200.computercraft.mixin.gametest.GameTestHelperAccessor +import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor +import dan200.computercraft.shared.Peripherals +import dan200.computercraft.test.core.computer.LuaTaskContext +import net.minecraft.commands.arguments.blocks.BlockInput +import net.minecraft.core.BlockPos +import net.minecraft.core.Direction +import net.minecraft.gametest.framework.* +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.Container +import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.EntityType +import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.entity.BlockEntityType +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.level.block.state.properties.Property +import net.minecraftforge.registries.ForgeRegistries + +/** + * Globally usable structures. + * + * @see GameTest.template + */ +object Structures { + /** The "default" structure, a 5x5 area with a polished Andesite floor */ + const val DEFAULT = "default" +} + +/** Pre-set in-game times */ +object Times { + const val NOON: Long = 6000 +} + +/** + * Custom timeouts for various test types. + * + * @see GameTest.timeoutTicks + */ +object Timeouts { + private const val SECOND: Int = 20 + + const val COMPUTER_TIMEOUT: Int = SECOND * 15 +} + +/** + * Equivalent to [GameTestSequence.thenExecute], but which won't run the next steps if the parent fails. + */ +fun GameTestSequence.thenExecuteFailFast(task: Runnable): GameTestSequence = + thenExecute(task).thenWaitUntil { + val failure = (this as GameTestSequenceAccessor).parent.error + if (failure != null) throw failure + } + +/** + * Wait until a computer has finished running and check it is OK. + */ +fun GameTestSequence.thenComputerOk(name: String? = null, marker: String = ComputerState.DONE): GameTestSequence { + val label = (this as GameTestSequenceAccessor).parent.testName + (if (name == null) "" else ".$name") + + thenWaitUntil { + val computer = ComputerState.get(label) + if (computer == null || !computer.isDone(marker)) throw GameTestAssertException("Computer '$label' has not reached $marker yet.") + } + thenExecuteFailFast { ComputerState.get(label)!!.check(marker) } + return this +} + +/** + * Run a task on a computer but don't wait for it to finish. + */ +fun GameTestSequence.thenStartComputer(name: String? = null, action: suspend LuaTaskContext.() -> Unit): GameTestSequence { + val test = (this as GameTestSequenceAccessor).parent + val label = test.testName + (if (name == null) "" else ".$name") + return thenExecuteFailFast { ManagedComputers.enqueue(test, label, action) } +} + +/** + * Run a task on a computer and wait for it to finish. + */ +fun GameTestSequence.thenOnComputer(name: String? = null, action: suspend LuaTaskContext.() -> Unit): GameTestSequence { + val test = (this as GameTestSequenceAccessor).parent + val label = test.testName + (if (name == null) "" else ".$name") + var monitor: ManagedComputers.Monitor? = null + thenExecuteFailFast { monitor = ManagedComputers.enqueue(test, label, action) } + thenWaitUntil { if (!monitor!!.isFinished) throw GameTestAssertException("Computer '$label' has not finished yet.") } + thenExecuteFailFast { monitor!!.check() } + return this +} + +/** + * Create a new game test sequence + */ +fun GameTestHelper.sequence(run: GameTestSequence.() -> Unit) { + val sequence = startSequence() + run(sequence) + sequence.thenSucceed() +} + +/** + * A custom instance of [GameTestAssertPosException] which allows for longer error messages. + */ +private class VerboseGameTestAssertPosException(message: String, absolutePos: BlockPos, relativePos: BlockPos, tick: Long) : + GameTestAssertPosException(message, absolutePos, relativePos, tick) { + override fun getMessageToShowAtBlock(): String = message!!.lineSequence().first() +} + +/** + * Fail this test. Unlike [GameTestHelper.fail], this trims the in-game error message to the first line. + */ +private fun GameTestHelper.failVerbose(message: String, pos: BlockPos): Nothing { + throw VerboseGameTestAssertPosException(message, absolutePos(pos), pos, tick) +} + +/** Fail with an optional context message. */ +private fun GameTestHelper.fail(message: String?, detail: String, pos: BlockPos): Nothing { + failVerbose(if (message.isNullOrEmpty()) detail else "$message: $detail", pos) +} + +/** + * A version of [GameTestHelper.assertBlockState] which also includes the current block state. + */ +fun GameTestHelper.assertBlockIs(pos: BlockPos, predicate: (BlockState) -> Boolean, message: String = "") { + val state = getBlockState(pos) + if (!predicate(state)) fail(message, state.toString(), pos) +} + +/** + * A version of [GameTestHelper.assertBlockProperty] which includes the current block state in the error message. + */ +fun > GameTestHelper.assertBlockHas(pos: BlockPos, property: Property, value: T, message: String = "") { + val state = getBlockState(pos) + if (!state.hasProperty(property)) { + val id = ForgeRegistries.BLOCKS.getKey(state.block) + fail(message, "block $id does not have property ${property.name}", pos) + } else if (state.getValue(property) != value) { + fail(message, "${property.name} is ${state.getValue(property)}, expected $value", pos) + } +} + +/** + * Assert a container contains exactly these items and no more. + * + * @param pos The position of the container. + * @param items The list of items this container must contain. This should be equal to the expected contents of the + * first `n` slots - the remaining are required to be empty. + */ +fun GameTestHelper.assertContainerExactly(pos: BlockPos, items: List) = + when (val container = getBlockEntity(pos) ?: failVerbose("Expected a container at $pos, found nothing", pos)) { + is Container -> assertContainerExactlyImpl(pos, container, items) + else -> failVerbose("Expected a container at $pos, found ${getName(container.type)}", pos) + } + +/** + * Assert an container contains exactly these items and no more. + * + * @param entity The entity containing these items. + * @param items The list of items this container must contain. This should be equal to the expected contents of the + * first `n` slots - the remaining are required to be empty. + */ +fun GameTestHelper.assertContainerExactly(entity: T, items: List) where T : Entity, T : Container = + assertContainerExactlyImpl(entity.blockPosition(), entity, items) + +private fun GameTestHelper.assertContainerExactlyImpl(pos: BlockPos, container: Container, items: List) { + val slot = (0 until container.containerSize).indexOfFirst { slot -> + val expected = if (slot >= items.size) ItemStack.EMPTY else items[slot] + !ItemStack.matches(container.getItem(slot), expected) + } + + if (slot >= 0) { + failVerbose( + """ + Items do not match (first mismatch at slot $slot). + Expected: $items + Container: ${(0 until container.containerSize).map { container.getItem(it) }.dropLastWhile { it.isEmpty }} + """.trimIndent(), + pos, + ) + } +} + +fun GameTestHelper.assertPeripheral(pos: BlockPos, direction: Direction = Direction.UP, type: String) { + val peripheral = Peripherals.getPeripheral(level, absolutePos(pos), direction) {} + when { + peripheral == null -> fail("No peripheral at position", pos) + peripheral.type != type -> fail("Peripheral is of type ${peripheral.type}, expected $type", pos) + } +} + +fun GameTestHelper.assertNoPeripheral(pos: BlockPos, direction: Direction = Direction.UP) { + val peripheral = Peripherals.getPeripheral(level, absolutePos(pos), direction) {} + if (peripheral != null) fail("Expected no peripheral, got a ${peripheral.type}", pos) +} + +private fun getName(type: BlockEntityType<*>): ResourceLocation = ForgeRegistries.BLOCK_ENTITY_TYPES.getKey(type)!! + +/** + * Get a [BlockEntity] of a specific type. + */ +fun GameTestHelper.getBlockEntity(pos: BlockPos, type: BlockEntityType): T { + val tile = getBlockEntity(pos) + @Suppress("UNCHECKED_CAST") + return when { + tile == null -> failVerbose("Expected ${getName(type)}, but no tile was there", pos) + tile.type != type -> failVerbose("Expected ${getName(type)} but got ${getName(tile.type)}", pos) + else -> tile as T + } +} + +/** + * Get all entities of a specific type within the test structure. + */ +fun GameTestHelper.getEntities(type: EntityType): List { + val info = (this as GameTestHelperAccessor).testInfo + return level.getEntities(type, info.structureBounds!!) { it.isAlive } +} + +/** + * Get an [Entity] inside the game structure, requiring there to be a single one. + */ +fun GameTestHelper.getEntity(type: EntityType): T { + val entities = getEntities(type) + when (entities.size) { + 0 -> throw GameTestAssertException("No $type entities") + 1 -> return entities[0] + else -> throw GameTestAssertException("Multiple $type entities (${entities.size} in bounding box)") + } +} + +/** + * Set a block within the test structure. + */ +fun GameTestHelper.setBlock(pos: BlockPos, state: BlockInput) = state.place(level, absolutePos(pos), 3) + +/** + * Modify a block state within the test. + */ +fun GameTestHelper.modifyBlock(pos: BlockPos, modify: (BlockState) -> BlockState) { + setBlock(pos, modify(getBlockState(pos))) +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt new file mode 100644 index 000000000..624c98ea7 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt @@ -0,0 +1,137 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.core + +import dan200.computercraft.api.lua.ILuaAPI +import dan200.computercraft.core.apis.OSAPI +import dan200.computercraft.core.lua.CobaltLuaMachine +import dan200.computercraft.core.lua.ILuaMachine +import dan200.computercraft.core.lua.MachineEnvironment +import dan200.computercraft.core.lua.MachineResult +import dan200.computercraft.gametest.api.thenOnComputer +import dan200.computercraft.mixin.gametest.GameTestInfoAccessor +import dan200.computercraft.shared.computer.core.ServerContext +import dan200.computercraft.test.core.computer.KotlinLuaMachine +import dan200.computercraft.test.core.computer.LuaTaskContext +import net.minecraft.gametest.framework.GameTestAssertException +import net.minecraft.gametest.framework.GameTestAssertPosException +import net.minecraft.gametest.framework.GameTestInfo +import net.minecraft.gametest.framework.GameTestSequence +import org.apache.logging.log4j.LogManager +import java.io.InputStream +import java.util.* +import java.util.concurrent.ConcurrentLinkedDeque +import java.util.concurrent.atomic.AtomicReference + +/** + * Provides a custom [ILuaMachine] which allows computers to run Kotlin or Lua code, depending on their ID. + * + * This allows writing game tests which consume Lua APIs, without having the overhead of starting a new computer for + * each test. + * + * @see GameTestSequence.thenOnComputer + */ +object ManagedComputers : ILuaMachine.Factory { + private val LOGGER = LogManager.getLogger(ManagedComputers::class.java) + private val computers: MutableMap Unit>> = mutableMapOf() + + internal fun enqueue(test: GameTestInfo, label: String, task: suspend LuaTaskContext.() -> Unit): Monitor { + val monitor = Monitor(test, label) + computers.computeIfAbsent(label) { ConcurrentLinkedDeque() }.add { + try { + LOGGER.info("Running $label") + task() + monitor.result.set(Result.success(Unit)) + } catch (e: Throwable) { + if (e !is AssertionError) LOGGER.error("Computer $label failed", e) + monitor.result.set(Result.failure(e)) + throw e + } finally { + LOGGER.info("Finished $label") + } + } + + ServerContext.get(test.level.server).registry().computers + .firstOrNull { it.label == label }?.queueEvent("test_wakeup") + + return monitor + } + + override fun create(environment: MachineEnvironment): ILuaMachine = DelegateMachine(environment) + + private class DelegateMachine(private val environment: MachineEnvironment) : ILuaMachine { + private val apis = mutableListOf() + private var delegate: ILuaMachine? = null + + override fun addAPI(api: ILuaAPI) { + val delegate = this.delegate + if (delegate != null) return delegate.addAPI(api) + + apis.add(api) + + if (api is OSAPI) { + val newMachine = if (api.computerID != 1) { + CobaltLuaMachine(environment) + } else if (api.computerLabel != null) { + KotlinMachine(environment, api.computerLabel[0] as String) + } else { + LOGGER.error("Kotlin Lua machine must have a label") + CobaltLuaMachine(environment) + } + + this.delegate = newMachine + for (api in apis) newMachine.addAPI(api) + } + } + + override fun loadBios(bios: InputStream): MachineResult { + val delegate = this.delegate ?: return MachineResult.error("Computer not created") + return delegate.loadBios(bios) + } + + override fun handleEvent(eventName: String?, arguments: Array?): MachineResult { + val delegate = this.delegate ?: return MachineResult.error("Computer not created") + return delegate.handleEvent(eventName, arguments) + } + + override fun printExecutionState(out: StringBuilder) { + delegate?.printExecutionState(out) + } + + override fun close() { + delegate?.close() + } + } + + private class KotlinMachine(environment: MachineEnvironment, private val label: String) : KotlinLuaMachine(environment) { + override fun getTask(): (suspend KotlinLuaMachine.() -> Unit)? = computers[label]?.poll() + } + + class Monitor(private val test: GameTestInfo, private val label: String) { + internal val result = AtomicReference>() + + val isFinished + get() = result.get() != null + + fun check() { + val result = result.get() ?: fail("Computer $label did not finish") + val error = result.exceptionOrNull() + if (error != null) fail(error.message ?: error.toString()) + } + + private fun fail(message: String): Nothing { + val computer = + ServerContext.get(test.level.server).registry().computers.firstOrNull { it.label == label } + if (computer == null) { + throw GameTestAssertException(message) + } else { + val pos = computer.position + val relativePos = pos.subtract(test.structureBlockPos) + throw GameTestAssertPosException(message, pos, relativePos, (test as GameTestInfoAccessor).`computercraft$getTick`()) + } + } + } +} diff --git a/src/testMod/resources/META-INF/mods.toml b/src/testMod/resources/META-INF/mods.toml index aa1ca6534..f4095a7d5 100644 --- a/src/testMod/resources/META-INF/mods.toml +++ b/src/testMod/resources/META-INF/mods.toml @@ -1,13 +1,25 @@ -modLoader = "javafml" -loaderVersion = "[43,)" -license = "Apache-2.0 license" -issueTrackerURL = "https://github.com/Seniorendi/AdvancedPeripherals/issues" -logoFile = "pack.png" +modLoader="javafml" +loaderVersion="[30,)" + +issueTrackerURL="https://github.com/cc-tweaked/CC-Tweaked/issues" +displayURL="https://github.com/cc-tweaked/CC-Tweaked" +logoFile="pack.png" + +credits="Created by Daniel Ratcliffe (@DanTwoHundred)" +authors="Daniel Ratcliffe, Aaron Mills, SquidDev" +license="ComputerCraft Public License (https://raw.githubusercontent.com/dan200/ComputerCraft/master/LICENSE)" [[mods]] -modId = "advancedperipheralstest" -version = "1.0.0" -displayName = "CC: Tweaked test framework" -description = ''' -A test framework for ensuring AP works correctly. Copied from CC:T code +modId="advancedperipheralstest" +version="1.0.0" +displayName="CC: Tweaked test framework" +description=''' +A test framework for ensuring CC: Tweaked works correctly. ''' + +[[dependencies.cctest]] +modId="computercraft" +mandatory=true +versionRange="[1.0,)" +ordering="AFTER" +side="BOTH" diff --git a/src/testMod/resources/advancedperipheralstest.mixins.json b/src/testMod/resources/advancedperipheralstest.mixins.json index b02dc239e..76ac77997 100644 --- a/src/testMod/resources/advancedperipheralstest.mixins.json +++ b/src/testMod/resources/advancedperipheralstest.mixins.json @@ -1,6 +1,6 @@ { "required": true, - "package": "de.srendi.advancedperipherals.mixin.gamtest", + "package": "dan200.computercraft.mixin.gametest", "minVersion": "0.8", "compatibilityLevel": "JAVA_17", "injectors": { diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/startup.lua b/src/testMod/resources/data/advancedperipheralstest/computer/startup.lua new file mode 100644 index 000000000..b67ad6af7 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/startup.lua @@ -0,0 +1,19 @@ +local label = os.getComputerLabel() +if label == nil then return test.fail("Label a computer to use it.") end + +local fn, err = loadfile("tests/" .. label .. ".lua", nil, _ENV) +if not fn then return test.fail(err) end + +local source = "@" .. label .. ".lua" +debug.sethook(function() + local i = debug.getinfo(2, "lS") + if i.source == source and i.currentline then + test.log("At line " .. i.currentline) + end +end, "l") + +local ok, err = pcall(fn) +if not ok then return test.fail(err) end + +print("Run " .. label) +test.ok() diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua new file mode 100644 index 000000000..c7f3a2056 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua @@ -0,0 +1,8 @@ +os.getComputerID = function() return 1 end +os.computerID = os.getComputerID + +rednet.open("top") +while true do + local id, msg, protocol = rednet.receive() + rednet.send(id, msg, protocol) +end diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua new file mode 100644 index 000000000..6cc619802 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua @@ -0,0 +1,10 @@ +rednet.open("top") + +local id, msg +repeat + rednet.send(1, "Test msg") -- Keep sending, as other computer may not have started yet. + + id, msg = rednet.receive(nil, 1) +until id == 1 + +test.eq("Test msg", msg) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt new file mode 100644 index 000000000..9a22ee331 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "computercraft:turtle_advanced{facing:south,waterlogged:false}", nbt: {Fuel: 0, Items: [], On: 0b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_advanced"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "computercraft:computer_advanced{facing:north,state:off}", nbt: {On: 0b, id: "computercraft:computer_advanced"}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:turtle_advanced{facing:south,waterlogged:false}", + "computercraft:computer_advanced{facing:north,state:off}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt new file mode 100644 index 000000000..58c570746 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt @@ -0,0 +1,141 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:lever{face:floor,facing:south,powered:false}"}, + {pos: [2, 1, 1], state: "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, Label: "computer_test.no_through_signal", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:redstone_wire{east:none,north:side,power:0,south:none,west:none}"}, + {pos: [2, 1, 4], state: "minecraft:redstone_lamp{lit:false}"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:redstone_lamp{lit:false}", + "computercraft:computer_advanced{facing:north,state:blinking}", + "minecraft:air", + "minecraft:lever{face:floor,facing:south,powered:false}", + "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}", + "minecraft:redstone_wire{east:none,north:side,power:0,south:none,west:none}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt new file mode 100644 index 000000000..592ccefaa --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt @@ -0,0 +1,141 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:lever{face:floor,facing:south,powered:false}"}, + {pos: [2, 1, 1], state: "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:off}", nbt: {ComputerId: 0, Label: "computer_test.no_through_signal_rev", On: 0b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}"}, + {pos: [2, 1, 4], state: "minecraft:redstone_lamp{lit:false}"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:redstone_lamp{lit:false}", + "minecraft:air", + "minecraft:lever{face:floor,facing:south,powered:false}", + "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}", + "minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}", + "computercraft:computer_advanced{facing:north,state:off}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt new file mode 100644 index 000000000..c9dcb29c8 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:on}", nbt: {ComputerId: 1, Label: "computer_test.set_and_destroy", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:redstone_lamp{lit:false}"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:redstone_lamp{lit:false}", + "minecraft:air", + "computercraft:computer_advanced{facing:north,state:on}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt new file mode 100644 index 000000000..40c0c4854 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "computercraft:computer_advanced{facing:north,state:on}", nbt: {ComputerId: 0, Label: "craftos_test.sends_basic_rednet_messages.echo", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, Label: "craftos_test.sends_basic_rednet_messages.main", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "computercraft:wireless_modem_normal{facing:down,on:true,waterlogged:false}", nbt: {id: "computercraft:wireless_modem_normal"}}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "computercraft:wireless_modem_normal{facing:down,on:true,waterlogged:false}", nbt: {id: "computercraft:wireless_modem_normal"}}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:computer_advanced{facing:north,state:on}", + "computercraft:computer_advanced{facing:north,state:blinking}", + "computercraft:wireless_modem_normal{facing:down,on:true,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/default.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/default.snbt new file mode 100644 index 000000000..6bbbe27a5 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/default.snbt @@ -0,0 +1,136 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.adds_removes_mount.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.adds_removes_mount.snbt new file mode 100644 index 000000000..a495031e6 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.adds_removes_mount.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "computercraft:disk_drive{facing:north,state:full}", nbt: {Item: {Count: 1b, id: "computercraft:disk", tag: {Color: 1118481, DiskId: 0}}, id: "computercraft:disk_drive"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "disk_drive_test.adds_removes_mount", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:disk_drive{facing:north,state:full}", + "computercraft:computer_advanced{facing:north,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt new file mode 100644 index 000000000..95da26f01 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt @@ -0,0 +1,40 @@ +{ + DataVersion: 2730, + size: [3, 3, 3], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "computercraft:disk_drive{facing:north,state:full}", nbt: {Item: {Count: 1b, id: "minecraft:music_disc_13"}, id: "computercraft:disk_drive"}}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "disk_drive_test.audio_disk", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:disk_drive{facing:north,state:full}", + "computercraft:computer_advanced{facing:north,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt new file mode 100644 index 000000000..d3576a9c4 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "computercraft:disk_drive{facing:south,state:full}", nbt: {Item: {Count: 1b, id: "minecraft:music_disc_13"}, id: "computercraft:disk_drive"}}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "disk_drive_test.ejects_disk", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [3, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 2, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 2, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:white_stained_glass"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:white_stained_glass"}, + {pos: [3, 2, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 2, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_stained_glass", + "minecraft:air", + "computercraft:disk_drive{facing:south,state:full}", + "computercraft:computer_advanced{facing:north,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt new file mode 100644 index 000000000..63e670a58 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt @@ -0,0 +1,145 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "computercraft:printer{bottom:false,facing:north,top:false}", nbt: {Items: [], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}}, + {pos: [0, 1, 1], state: "computercraft:cable{cable:true,down:false,east:true,modem:north_on,north:true,south:false,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 1b, PeripheralId: 1, PeripheralType: "printer", id: "computercraft:cable"}}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", nbt: {Height: 1, Width: 1, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [1, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [1, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [1, 1, 4], state: "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 1b, PeripheralId: 1, PeripheralType: "monitor", id: "computercraft:cable"}}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.gains_peripherals", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [4, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:north_off,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:printer{bottom:false,facing:north,top:false}", + "computercraft:cable{cable:true,down:false,east:true,modem:north_on,north:true,south:false,up:false,waterlogged:false,west:false}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", + "computercraft:cable{cable:true,down:false,east:false,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", + "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", + "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:false}", + "computercraft:computer_advanced{facing:north,state:blinking}", + "computercraft:cable{cable:true,down:false,east:false,modem:north_off,north:true,south:false,up:false,waterlogged:false,west:true}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt new file mode 100644 index 000000000..c16283a27 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt @@ -0,0 +1,146 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "computercraft:printer{bottom:false,facing:north,top:false}", nbt: {Items: [], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}}, + {pos: [0, 1, 1], state: "computercraft:cable{cable:true,down:false,east:false,modem:north_on,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 1b, PeripheralId: 0, PeripheralType: "printer", id: "computercraft:cable"}}, + {pos: [0, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:false,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", nbt: {Height: 1, Width: 1, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [1, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [1, 1, 4], state: "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 1b, PeripheralId: 0, PeripheralType: "monitor", id: "computercraft:cable"}}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.have_peripherals", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:printer{bottom:false,facing:north,top:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:north_on,north:true,south:true,up:false,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:false,up:false,waterlogged:false,west:false}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", + "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", + "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", + "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:true}", + "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:false,up:false,waterlogged:false,west:true}", + "computercraft:computer_advanced{facing:north,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt new file mode 100644 index 000000000..79ed20b01 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.transmits_messages.receive", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:true,up:false,waterlogged:false,west:false}", nbt: {PeripheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [2, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeripheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [2, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:west_off,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeripheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.transmits_messages.send", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:computer_advanced{facing:north,state:blinking}", + "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:true,up:false,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:west_off,north:true,south:false,up:false,waterlogged:false,west:true}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt new file mode 100644 index 000000000..ff0a97bf1 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt @@ -0,0 +1,136 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt new file mode 100644 index 000000000..f8c60dc15 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt @@ -0,0 +1,146 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:white_concrete"}, + {pos: [0, 1, 1], state: "minecraft:shroomlight"}, + {pos: [0, 1, 2], state: "minecraft:white_concrete"}, + {pos: [0, 1, 3], state: "minecraft:white_concrete"}, + {pos: [0, 1, 4], state: "minecraft:white_concrete"}, + {pos: [1, 1, 0], state: "minecraft:white_concrete"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [1, 1, 4], state: "minecraft:white_concrete"}, + {pos: [2, 1, 0], state: "minecraft:white_concrete"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [2, 1, 4], state: "minecraft:white_concrete"}, + {pos: [3, 1, 0], state: "minecraft:white_concrete"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [3, 1, 4], state: "minecraft:white_concrete"}, + {pos: [4, 1, 0], state: "minecraft:white_concrete"}, + {pos: [4, 1, 1], state: "minecraft:shroomlight"}, + {pos: [4, 1, 2], state: "minecraft:white_concrete"}, + {pos: [4, 1, 3], state: "minecraft:white_concrete"}, + {pos: [4, 1, 4], state: "minecraft:white_concrete"}, + {pos: [0, 2, 0], state: "minecraft:white_concrete"}, + {pos: [0, 2, 1], state: "minecraft:white_concrete"}, + {pos: [0, 2, 2], state: "minecraft:white_concrete"}, + {pos: [0, 2, 3], state: "minecraft:white_concrete"}, + {pos: [0, 2, 4], state: "minecraft:white_concrete"}, + {pos: [1, 2, 0], state: "minecraft:white_concrete"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 1, id: "computercraft:monitor_advanced"}}, + {pos: [1, 2, 4], state: "minecraft:white_concrete"}, + {pos: [2, 2, 0], state: "minecraft:white_concrete"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 1, id: "computercraft:monitor_advanced"}}, + {pos: [2, 2, 4], state: "minecraft:white_concrete"}, + {pos: [3, 2, 0], state: "minecraft:white_concrete"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 1, id: "computercraft:monitor_advanced"}}, + {pos: [3, 2, 4], state: "minecraft:white_concrete"}, + {pos: [4, 2, 0], state: "minecraft:white_concrete"}, + {pos: [4, 2, 1], state: "minecraft:white_concrete"}, + {pos: [4, 2, 2], state: "minecraft:white_concrete"}, + {pos: [4, 2, 3], state: "minecraft:white_concrete"}, + {pos: [4, 2, 4], state: "minecraft:white_concrete"}, + {pos: [0, 3, 0], state: "minecraft:white_concrete"}, + {pos: [0, 3, 1], state: "minecraft:white_concrete"}, + {pos: [0, 3, 2], state: "minecraft:white_concrete"}, + {pos: [0, 3, 3], state: "minecraft:white_concrete"}, + {pos: [0, 3, 4], state: "minecraft:white_concrete"}, + {pos: [1, 3, 0], state: "minecraft:white_concrete"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:white_concrete"}, + {pos: [2, 3, 0], state: "minecraft:white_concrete"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:white_concrete"}, + {pos: [3, 3, 0], state: "minecraft:white_concrete"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:white_concrete"}, + {pos: [4, 3, 0], state: "minecraft:white_concrete"}, + {pos: [4, 3, 1], state: "minecraft:white_concrete"}, + {pos: [4, 3, 2], state: "minecraft:white_concrete"}, + {pos: [4, 3, 3], state: "minecraft:white_concrete"}, + {pos: [4, 3, 4], state: "minecraft:white_concrete"}, + {pos: [0, 4, 0], state: "minecraft:white_concrete"}, + {pos: [0, 4, 1], state: "minecraft:white_concrete"}, + {pos: [0, 4, 2], state: "minecraft:white_concrete"}, + {pos: [0, 4, 3], state: "minecraft:white_concrete"}, + {pos: [0, 4, 4], state: "minecraft:white_concrete"}, + {pos: [1, 4, 0], state: "minecraft:white_concrete"}, + {pos: [1, 4, 1], state: "minecraft:white_concrete"}, + {pos: [1, 4, 2], state: "minecraft:white_concrete"}, + {pos: [1, 4, 3], state: "minecraft:shroomlight"}, + {pos: [1, 4, 4], state: "minecraft:white_concrete"}, + {pos: [2, 4, 0], state: "minecraft:white_concrete"}, + {pos: [2, 4, 1], state: "minecraft:white_concrete"}, + {pos: [2, 4, 2], state: "minecraft:white_concrete"}, + {pos: [2, 4, 3], state: "minecraft:white_concrete"}, + {pos: [2, 4, 4], state: "minecraft:white_concrete"}, + {pos: [3, 4, 0], state: "minecraft:white_concrete"}, + {pos: [3, 4, 1], state: "minecraft:white_concrete"}, + {pos: [3, 4, 2], state: "minecraft:white_concrete"}, + {pos: [3, 4, 3], state: "minecraft:shroomlight"}, + {pos: [3, 4, 4], state: "minecraft:white_concrete"}, + {pos: [4, 4, 0], state: "minecraft:white_concrete"}, + {pos: [4, 4, 1], state: "minecraft:white_concrete"}, + {pos: [4, 4, 2], state: "minecraft:white_concrete"}, + {pos: [4, 4, 3], state: "minecraft:white_concrete"}, + {pos: [4, 4, 4], state: "minecraft:white_concrete"} + ], + entities: [ + {blockPos: [2, 1, 1], pos: [2.392713937302208d, 1.0d, 1.300000011920929d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.699999988079071d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanUpdate: 1b, CustomName: '{"text":"monitor_test.looks_acceptable"}', DeathTime: 0s, DisabledSlots: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invisible: 1b, Invulnerable: 0b, Marker: 1b, Motion: [0.0d, 0.0d, 0.0d], NoBasePlate: 0b, OnGround: 0b, PortalCooldown: 0, Pos: [21.392713937302208d, 6.0d, 35.30000001192093d], Pose: {}, Rotation: [0.15043798f, 15.347454f], ShowArms: 0b, Small: 0b, UUID: [I; 474729512, 2108312608, -1494837479, 630038770], id: "minecraft:armor_stand"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_concrete", + "minecraft:shroomlight", + "minecraft:air", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt new file mode 100644 index 000000000..1bbce9d32 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt @@ -0,0 +1,145 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:white_concrete"}, + {pos: [0, 1, 1], state: "minecraft:white_concrete"}, + {pos: [0, 1, 2], state: "minecraft:white_concrete"}, + {pos: [0, 1, 3], state: "minecraft:white_concrete"}, + {pos: [0, 1, 4], state: "minecraft:white_concrete"}, + {pos: [1, 1, 0], state: "minecraft:white_concrete"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [1, 1, 4], state: "minecraft:white_concrete"}, + {pos: [2, 1, 0], state: "minecraft:white_concrete"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [2, 1, 4], state: "minecraft:white_concrete"}, + {pos: [3, 1, 0], state: "minecraft:white_concrete"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [3, 1, 4], state: "minecraft:white_concrete"}, + {pos: [4, 1, 0], state: "minecraft:white_concrete"}, + {pos: [4, 1, 1], state: "minecraft:white_concrete"}, + {pos: [4, 1, 2], state: "minecraft:white_concrete"}, + {pos: [4, 1, 3], state: "minecraft:white_concrete"}, + {pos: [4, 1, 4], state: "minecraft:white_concrete"}, + {pos: [0, 2, 0], state: "minecraft:white_concrete"}, + {pos: [0, 2, 1], state: "minecraft:white_concrete"}, + {pos: [0, 2, 2], state: "minecraft:white_concrete"}, + {pos: [0, 2, 3], state: "minecraft:white_concrete"}, + {pos: [0, 2, 4], state: "minecraft:white_concrete"}, + {pos: [1, 2, 0], state: "minecraft:white_concrete"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 1, id: "computercraft:monitor_advanced"}}, + {pos: [1, 2, 4], state: "minecraft:white_concrete"}, + {pos: [2, 2, 0], state: "minecraft:white_concrete"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 1, id: "computercraft:monitor_advanced"}}, + {pos: [2, 2, 4], state: "minecraft:white_concrete"}, + {pos: [3, 2, 0], state: "minecraft:white_concrete"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 1, id: "computercraft:monitor_advanced"}}, + {pos: [3, 2, 4], state: "minecraft:white_concrete"}, + {pos: [4, 2, 0], state: "minecraft:white_concrete"}, + {pos: [4, 2, 1], state: "minecraft:white_concrete"}, + {pos: [4, 2, 2], state: "minecraft:white_concrete"}, + {pos: [4, 2, 3], state: "minecraft:white_concrete"}, + {pos: [4, 2, 4], state: "minecraft:white_concrete"}, + {pos: [0, 3, 0], state: "minecraft:white_concrete"}, + {pos: [0, 3, 1], state: "minecraft:white_concrete"}, + {pos: [0, 3, 2], state: "minecraft:white_concrete"}, + {pos: [0, 3, 3], state: "minecraft:white_concrete"}, + {pos: [0, 3, 4], state: "minecraft:white_concrete"}, + {pos: [1, 3, 0], state: "minecraft:white_concrete"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:white_concrete"}, + {pos: [2, 3, 0], state: "minecraft:white_concrete"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:white_concrete"}, + {pos: [3, 3, 0], state: "minecraft:white_concrete"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:white_concrete"}, + {pos: [4, 3, 0], state: "minecraft:white_concrete"}, + {pos: [4, 3, 1], state: "minecraft:white_concrete"}, + {pos: [4, 3, 2], state: "minecraft:white_concrete"}, + {pos: [4, 3, 3], state: "minecraft:white_concrete"}, + {pos: [4, 3, 4], state: "minecraft:white_concrete"}, + {pos: [0, 4, 0], state: "minecraft:white_concrete"}, + {pos: [0, 4, 1], state: "minecraft:white_concrete"}, + {pos: [0, 4, 2], state: "minecraft:white_concrete"}, + {pos: [0, 4, 3], state: "minecraft:white_concrete"}, + {pos: [0, 4, 4], state: "minecraft:white_concrete"}, + {pos: [1, 4, 0], state: "minecraft:white_concrete"}, + {pos: [1, 4, 1], state: "minecraft:white_concrete"}, + {pos: [1, 4, 2], state: "minecraft:white_concrete"}, + {pos: [1, 4, 3], state: "minecraft:white_concrete"}, + {pos: [1, 4, 4], state: "minecraft:white_concrete"}, + {pos: [2, 4, 0], state: "minecraft:white_concrete"}, + {pos: [2, 4, 1], state: "minecraft:white_concrete"}, + {pos: [2, 4, 2], state: "minecraft:white_concrete"}, + {pos: [2, 4, 3], state: "minecraft:white_concrete"}, + {pos: [2, 4, 4], state: "minecraft:white_concrete"}, + {pos: [3, 4, 0], state: "minecraft:white_concrete"}, + {pos: [3, 4, 1], state: "minecraft:white_concrete"}, + {pos: [3, 4, 2], state: "minecraft:white_concrete"}, + {pos: [3, 4, 3], state: "minecraft:white_concrete"}, + {pos: [3, 4, 4], state: "minecraft:white_concrete"}, + {pos: [4, 4, 0], state: "minecraft:white_concrete"}, + {pos: [4, 4, 1], state: "minecraft:white_concrete"}, + {pos: [4, 4, 2], state: "minecraft:white_concrete"}, + {pos: [4, 4, 3], state: "minecraft:white_concrete"}, + {pos: [4, 4, 4], state: "minecraft:white_concrete"} + ], + entities: [ + {blockPos: [2, 1, 1], pos: [2.3927139373022044d, 1.0d, 1.300000011920929d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.699999988079071d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanUpdate: 1b, CustomName: '{"text":"monitor_test.looks_acceptable_dark"}', DeathTime: 0s, DisabledSlots: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invisible: 1b, Invulnerable: 0b, Marker: 1b, Motion: [0.0d, 0.0d, 0.0d], NoBasePlate: 0b, OnGround: 0b, PortalCooldown: 0, Pos: [64.3927139373022d, 6.0d, 59.30000001192093d], Pose: {}, Rotation: [0.15043798f, 15.347454f], ShowArms: 0b, Small: 0b, UUID: [I; -1516632699, -1770765897, -1362337958, -475677268], id: "minecraft:armor_stand"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_concrete", + "minecraft:air", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/printouttest.in_frame_at_night.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/printouttest.in_frame_at_night.snbt new file mode 100644 index 000000000..d9458a303 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/printouttest.in_frame_at_night.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:white_concrete"}, + {pos: [0, 1, 1], state: "minecraft:white_concrete"}, + {pos: [0, 1, 2], state: "minecraft:white_concrete"}, + {pos: [0, 1, 3], state: "minecraft:white_concrete"}, + {pos: [0, 1, 4], state: "minecraft:white_concrete"}, + {pos: [1, 1, 0], state: "minecraft:white_concrete"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:white_concrete"}, + {pos: [2, 1, 0], state: "minecraft:white_concrete"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:white_concrete"}, + {pos: [3, 1, 0], state: "minecraft:white_concrete"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:white_concrete"}, + {pos: [4, 1, 0], state: "minecraft:white_concrete"}, + {pos: [4, 1, 1], state: "minecraft:white_concrete"}, + {pos: [4, 1, 2], state: "minecraft:white_concrete"}, + {pos: [4, 1, 3], state: "minecraft:white_concrete"}, + {pos: [4, 1, 4], state: "minecraft:white_concrete"}, + {pos: [0, 2, 0], state: "minecraft:white_concrete"}, + {pos: [0, 2, 1], state: "minecraft:white_concrete"}, + {pos: [0, 2, 2], state: "minecraft:white_concrete"}, + {pos: [0, 2, 3], state: "minecraft:white_concrete"}, + {pos: [0, 2, 4], state: "minecraft:white_concrete"}, + {pos: [1, 2, 0], state: "minecraft:white_concrete"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:white_concrete"}, + {pos: [2, 2, 0], state: "minecraft:white_concrete"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:white_concrete"}, + {pos: [3, 2, 0], state: "minecraft:white_concrete"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:white_concrete"}, + {pos: [4, 2, 0], state: "minecraft:white_concrete"}, + {pos: [4, 2, 1], state: "minecraft:white_concrete"}, + {pos: [4, 2, 2], state: "minecraft:white_concrete"}, + {pos: [4, 2, 3], state: "minecraft:white_concrete"}, + {pos: [4, 2, 4], state: "minecraft:white_concrete"}, + {pos: [0, 3, 0], state: "minecraft:white_concrete"}, + {pos: [0, 3, 1], state: "minecraft:white_concrete"}, + {pos: [0, 3, 2], state: "minecraft:white_concrete"}, + {pos: [0, 3, 3], state: "minecraft:white_concrete"}, + {pos: [0, 3, 4], state: "minecraft:white_concrete"}, + {pos: [1, 3, 0], state: "minecraft:white_concrete"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:white_concrete"}, + {pos: [2, 3, 0], state: "minecraft:white_concrete"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:white_concrete"}, + {pos: [3, 3, 0], state: "minecraft:white_concrete"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:white_concrete"}, + {pos: [4, 3, 0], state: "minecraft:white_concrete"}, + {pos: [4, 3, 1], state: "minecraft:white_concrete"}, + {pos: [4, 3, 2], state: "minecraft:white_concrete"}, + {pos: [4, 3, 3], state: "minecraft:white_concrete"}, + {pos: [4, 3, 4], state: "minecraft:white_concrete"}, + {pos: [0, 4, 0], state: "minecraft:white_concrete"}, + {pos: [0, 4, 1], state: "minecraft:white_concrete"}, + {pos: [0, 4, 2], state: "minecraft:white_concrete"}, + {pos: [0, 4, 3], state: "minecraft:white_concrete"}, + {pos: [0, 4, 4], state: "minecraft:white_concrete"}, + {pos: [1, 4, 0], state: "minecraft:white_concrete"}, + {pos: [1, 4, 1], state: "minecraft:white_concrete"}, + {pos: [1, 4, 2], state: "minecraft:white_concrete"}, + {pos: [1, 4, 3], state: "minecraft:white_concrete"}, + {pos: [1, 4, 4], state: "minecraft:white_concrete"}, + {pos: [2, 4, 0], state: "minecraft:white_concrete"}, + {pos: [2, 4, 1], state: "minecraft:white_concrete"}, + {pos: [2, 4, 2], state: "minecraft:white_concrete"}, + {pos: [2, 4, 3], state: "minecraft:white_concrete"}, + {pos: [2, 4, 4], state: "minecraft:white_concrete"}, + {pos: [3, 4, 0], state: "minecraft:white_concrete"}, + {pos: [3, 4, 1], state: "minecraft:white_concrete"}, + {pos: [3, 4, 2], state: "minecraft:white_concrete"}, + {pos: [3, 4, 3], state: "minecraft:white_concrete"}, + {pos: [3, 4, 4], state: "minecraft:white_concrete"}, + {pos: [4, 4, 0], state: "minecraft:white_concrete"}, + {pos: [4, 4, 1], state: "minecraft:white_concrete"}, + {pos: [4, 4, 2], state: "minecraft:white_concrete"}, + {pos: [4, 4, 3], state: "minecraft:white_concrete"}, + {pos: [4, 4, 4], state: "minecraft:white_concrete"} + ], + entities: [ + {blockPos: [2, 2, 3], pos: [2.5d, 2.5d, 3.96875d], nbt: {Air: 300s, CanUpdate: 1b, Facing: 2b, FallDistance: 0.0f, Fire: -1s, Fixed: 0b, Invisible: 0b, Invulnerable: 0b, Item: {Count: 1b, id: "computercraft:printed_page", tag: {Color0: "eeeeeeeeeeeeeeeeeeeeeeeee", Color1: "eeeeeeeeeeeeeeeeeeeeeeeee", Color10: "eeeeeeeeeeeeeeeeeeeeeeeee", Color11: "eeeeeeeeeeeeeeeeeeeeeeeee", Color12: "eeeeeeeeeeeeeeeeeeeeeeeee", Color13: "eeeeeeeeeeeeeeeeeeeeeeeee", Color14: "eeeeeeeeeeeeeeeeeeeeeeeee", Color15: "eeeeeeeeeeeeeeeeeeeeeeeee", Color16: "eeeeeeeeeeeeeeeeeeeeeeeee", Color17: "eeeeeeeeeeeeeeeeeeeeeeeee", Color18: "eeeeeeeeeeeeeeeeeeeeeeeee", Color19: "eeeeeeeeeeeeeeeeeeeeeeeee", Color2: "eeeeeeeeeeeeeeeeeeeeeeeee", Color20: "eeeeeeeeeeeeeeeeeeeeeeeee", Color3: "eeeeeeeeeeeeeeeeeeeeeeeee", Color4: "eeeeeeeeeeeeeeeeeeeeeeeee", Color5: "eeeeeeeeeeeeeeeeeeeeeeeee", Color6: "eeeeeeeeeeeeeeeeeeeeeeeee", Color7: "eeeeeeeeeeeeeeeeeeeeeeeee", Color8: "eeeeeeeeeeeeeeeeeeeeeeeee", Color9: "eeeeeeeeeeeeeeeeeeeeeeeee", Pages: 1, Text0: "If you're reading this, ", Text1: "the test failed. ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: "a.lua"}}, ItemDropChance: 1.0f, ItemRotation: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [10.5d, 7.5d, 44.96875d], Rotation: [180.0f, 0.0f], TileX: 10, TileY: 7, TileZ: 44, UUID: [I; 1043973837, -2076424529, -1762893135, -165665834], id: "minecraft:item_frame"}}, + {blockPos: [2, 1, 2], pos: [2.583196949396914d, 1.0d, 2.6089749199596d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.699999988079071d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanUpdate: 1b, CustomName: '{"text":"printouttest.in_frame_at_night"}', DeathTime: 0s, DisabledSlots: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invisible: 1b, Invulnerable: 0b, Marker: 1b, Motion: [0.0d, 0.0d, 0.0d], NoBasePlate: 0b, OnGround: 0b, PortalCooldown: 0, Pos: [10.583196949396914d, 6.0d, 43.6089749199596d], Pose: {}, Rotation: [1.3504658f, 6.7031174f], ShowArms: 0b, Small: 0b, UUID: [I; -1917933016, 1390888530, -2109873447, -2136052677], id: "minecraft:armor_stand"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_concrete", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity.snbt new file mode 100644 index 000000000..93c3f0341 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:light_gray_stained_glass"}, + {pos: [1, 1, 3], state: "minecraft:light_gray_stained_glass"}, + {pos: [1, 1, 4], state: "minecraft:light_gray_stained_glass"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [], Label: "turtle_test.attack_entity", LeftUpgrade: "minecraft:diamond_sword", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:light_gray_stained_glass"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:light_gray_stained_glass"}, + {pos: [3, 1, 3], state: "minecraft:light_gray_stained_glass"}, + {pos: [3, 1, 4], state: "minecraft:light_gray_stained_glass"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:light_gray_stained_glass"}, + {pos: [1, 2, 3], state: "minecraft:light_gray_stained_glass"}, + {pos: [1, 2, 4], state: "minecraft:light_gray_stained_glass"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:light_gray_stained_glass"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:light_gray_stained_glass"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:light_gray_stained_glass"}, + {pos: [3, 2, 3], state: "minecraft:light_gray_stained_glass"}, + {pos: [3, 2, 4], state: "minecraft:light_gray_stained_glass"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [ + {blockPos: [2, 1, 3], pos: [2.5d, 1.0d, 3.5d], nbt: {AbsorptionAmount: 0.0f, Age: 0, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.08d, Name: "forge:entity_gravity"}, {Base: 16.0d, Modifiers: [{Amount: -0.035951819981951794d, Name: "Random spawn bonus", Operation: 1, UUID: [I; 1700656572, -1622061405, -2001517321, -1044884103]}], Name: "minecraft:generic.follow_range"}, {Base: 0.23000000417232513d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, Color: 0b, DeathTime: 0s, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, ForcedAge: 0, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 8.0f, HurtByTimestamp: 0, HurtTime: 0s, InLove: 0, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [92.5d, -58.0d, 35.5d], Rotation: [5.6449127f, 0.0f], Sheared: 0b, UUID: [I; -551270274, -502513578, -1253838680, -1186962441], id: "minecraft:sheep"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:light_gray_stained_glass", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity_destroy.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity_destroy.snbt new file mode 100644 index 000000000..926c2ca45 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity_destroy.snbt @@ -0,0 +1,141 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:obsidian"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:barrier"}, + {pos: [0, 1, 1], state: "minecraft:barrier"}, + {pos: [0, 1, 2], state: "minecraft:barrier"}, + {pos: [0, 1, 3], state: "minecraft:barrier"}, + {pos: [0, 1, 4], state: "minecraft:barrier"}, + {pos: [1, 1, 0], state: "minecraft:barrier"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:barrier"}, + {pos: [2, 1, 0], state: "minecraft:barrier"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [], Label: "turtle_test.attack_entity_destroy", LeftUpgrade: "minecraft:diamond_sword", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:barrier"}, + {pos: [3, 1, 0], state: "minecraft:barrier"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:barrier"}, + {pos: [4, 1, 0], state: "minecraft:barrier"}, + {pos: [4, 1, 1], state: "minecraft:barrier"}, + {pos: [4, 1, 2], state: "minecraft:barrier"}, + {pos: [4, 1, 3], state: "minecraft:barrier"}, + {pos: [4, 1, 4], state: "minecraft:barrier"}, + {pos: [0, 2, 0], state: "minecraft:barrier"}, + {pos: [0, 2, 1], state: "minecraft:barrier"}, + {pos: [0, 2, 2], state: "minecraft:barrier"}, + {pos: [0, 2, 3], state: "minecraft:barrier"}, + {pos: [0, 2, 4], state: "minecraft:barrier"}, + {pos: [1, 2, 0], state: "minecraft:barrier"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:barrier"}, + {pos: [2, 2, 0], state: "minecraft:barrier"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:barrier"}, + {pos: [3, 2, 0], state: "minecraft:barrier"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:barrier"}, + {pos: [4, 2, 0], state: "minecraft:barrier"}, + {pos: [4, 2, 1], state: "minecraft:barrier"}, + {pos: [4, 2, 2], state: "minecraft:barrier"}, + {pos: [4, 2, 3], state: "minecraft:barrier"}, + {pos: [4, 2, 4], state: "minecraft:barrier"}, + {pos: [0, 3, 0], state: "minecraft:barrier"}, + {pos: [0, 3, 1], state: "minecraft:barrier"}, + {pos: [0, 3, 2], state: "minecraft:barrier"}, + {pos: [0, 3, 3], state: "minecraft:barrier"}, + {pos: [0, 3, 4], state: "minecraft:barrier"}, + {pos: [1, 3, 0], state: "minecraft:barrier"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:barrier"}, + {pos: [2, 3, 0], state: "minecraft:barrier"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:barrier"}, + {pos: [3, 3, 0], state: "minecraft:barrier"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:barrier"}, + {pos: [4, 3, 0], state: "minecraft:barrier"}, + {pos: [4, 3, 1], state: "minecraft:barrier"}, + {pos: [4, 3, 2], state: "minecraft:barrier"}, + {pos: [4, 3, 3], state: "minecraft:barrier"}, + {pos: [4, 3, 4], state: "minecraft:barrier"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [ + {blockPos: [2, 1, 3], pos: [2.5d, 1.0d, 3.5d], nbt: {Air: 300s, CanUpdate: 1b, FallDistance: 0.0f, Fire: -1s, Invulnerable: 0b, Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [84.5d, -58.0d, 35.5d], Rotation: [0.0f, 0.0f], ShowBottom: 0b, UUID: [I; 1784803273, 2137542103, -1349475969, -423460124], id: "minecraft:end_crystal"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:obsidian", + "minecraft:barrier", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.cleaned_with_cauldrons.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.cleaned_with_cauldrons.snbt new file mode 100644 index 000000000..cb9f5c194 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.cleaned_with_cauldrons.snbt @@ -0,0 +1,40 @@ +{ + DataVersion: 3218, + size: [3, 3, 3], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:turtle_normal", tag: {Color: 13388876, ComputerId: 0, display: {Name: '{"text":"Clean turtle"}'}}}], Label: "turtle_test.cleaned_with_cauldrons", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 1, 1], state: "minecraft:water_cauldron{level:3}"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "minecraft:water_cauldron{level:3}", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_chest.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_chest.snbt new file mode 100644 index 000000000..51bbe020b --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_chest.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 64b, Slot: 0b, id: "minecraft:dirt"}, {Count: 32b, Slot: 2b, id: "minecraft:dirt"}], Label: "turtle_test.drop_into_chest", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:chest{facing:west,type:single,waterlogged:false}", nbt: {Items: [{Count: 16b, Slot: 0b, id: "minecraft:dirt"}], id: "minecraft:chest"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:chest{facing:west,type:single,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_entity.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_entity.snbt new file mode 100644 index 000000000..5a1021899 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_entity.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 64b, Slot: 0b, id: "minecraft:dirt"}], Label: "turtle_test.drop_into_entity", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:powered_rail{powered:false,shape:east_west,waterlogged:false}"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [ + {blockPos: [2, 1, 3], pos: [2.5d, 1.0625d, 3.5d], nbt: {Air: 300s, CanUpdate: 1b, FallDistance: 0.0f, Fire: -1s, Invulnerable: 0b, Items: [{Count: 16b, Slot: 0b, id: "minecraft:dirt"}], Motion: [0.0d, 0.0d, 0.0d], OnGround: 0b, PortalCooldown: 0, Pos: [76.5d, -57.9375d, 24.5d], Rotation: [0.0f, 0.0f], UUID: [I; 248684729, -1164292658, -1115871518, 1954015777], id: "minecraft:chest_minecart"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "minecraft:powered_rail{powered:false,shape:east_west,waterlogged:false}", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.gather_lava.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.gather_lava.snbt new file mode 100644 index 000000000..e2e703e88 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.gather_lava.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 2], state: "minecraft:lava{level:0}"}, + {pos: [2, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:bucket"}], Label: "turtle_test.gather_lava", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_stained_glass", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:air", + "minecraft:lava{level:0}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.hoe_dirt.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.hoe_dirt.snbt new file mode 100644 index 000000000..4b43c47b3 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.hoe_dirt.snbt @@ -0,0 +1,40 @@ +{ + DataVersion: 2730, + size: [3, 3, 3], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [], Label: "turtle_test.hoe_dirt", LeftUpgrade: "minecraft:diamond_hoe", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 1, 1], state: "minecraft:dirt"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:dirt", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.item_detail_provider.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.item_detail_provider.snbt new file mode 100644 index 000000000..5e67a701f --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.item_detail_provider.snbt @@ -0,0 +1,39 @@ +{ + DataVersion: 2975, + size: [3, 3, 3], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:printed_page", tag: {Color0: "fffffffffffffffffffffffff", Color1: "fffffffffffffffffffffffff", Color10: "fffffffffffffffffffffffff", Color11: "fffffffffffffffffffffffff", Color12: "fffffffffffffffffffffffff", Color13: "fffffffffffffffffffffffff", Color14: "fffffffffffffffffffffffff", Color15: "fffffffffffffffffffffffff", Color16: "fffffffffffffffffffffffff", Color17: "fffffffffffffffffffffffff", Color18: "fffffffffffffffffffffffff", Color19: "fffffffffffffffffffffffff", Color2: "fffffffffffffffffffffffff", Color20: "fffffffffffffffffffffffff", Color3: "fffffffffffffffffffffffff", Color4: "fffffffffffffffffffffffff", Color5: "fffffffffffffffffffffffff", Color6: "fffffffffffffffffffffffff", Color7: "fffffffffffffffffffffffff", Color8: "fffffffffffffffffffffffff", Color9: "fffffffffffffffffffffffff", Pages: 1, Text0: "Example ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: "Example page"}}], Label: "turtle_test.item_detail_provider", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_obstruct.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_obstruct.snbt new file mode 100644 index 000000000..b41511b6e --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_obstruct.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [], Label: "turtle_test.move_obstruct", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:dirt"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:dirt", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_replace.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_replace.snbt new file mode 100644 index 000000000..a678cf757 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_replace.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:dirt"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Label: "turtle_test.move_replace", Fuel: 80, Items: [], On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:grass"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:dirt", + "minecraft:air", + "minecraft:grass", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_water.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_water.snbt new file mode 100644 index 000000000..ef3076f52 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_water.snbt @@ -0,0 +1,148 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:polished_andesite_stairs{facing:south,half:bottom,shape:outer_left,waterlogged:false}"}, + {pos: [1, 1, 1], state: "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [1, 1, 2], state: "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [1, 1, 3], state: "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [1, 1, 4], state: "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:outer_left,waterlogged:false}"}, + {pos: [2, 1, 0], state: "minecraft:polished_andesite_stairs{facing:south,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [2, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.move_water", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 2], state: "minecraft:water{level:0}"}, + {pos: [2, 1, 3], state: "minecraft:water{level:1}"}, + {pos: [2, 1, 4], state: "minecraft:polished_andesite_stairs{facing:north,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [3, 1, 0], state: "minecraft:polished_andesite_stairs{facing:west,half:bottom,shape:outer_left,waterlogged:false}"}, + {pos: [3, 1, 1], state: "minecraft:polished_andesite_stairs{facing:west,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [3, 1, 2], state: "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:true}"}, + {pos: [3, 1, 3], state: "minecraft:polished_andesite_stairs{facing:west,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [3, 1, 4], state: "minecraft:polished_andesite_stairs{facing:north,half:bottom,shape:outer_left,waterlogged:false}"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "minecraft:polished_andesite_stairs{facing:south,half:bottom,shape:outer_left,waterlogged:false}", + "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:false}", + "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:outer_left,waterlogged:false}", + "minecraft:polished_andesite_stairs{facing:south,half:bottom,shape:straight,waterlogged:false}", + "minecraft:water{level:0}", + "minecraft:water{level:1}", + "minecraft:polished_andesite_stairs{facing:north,half:bottom,shape:straight,waterlogged:false}", + "minecraft:polished_andesite_stairs{facing:west,half:bottom,shape:outer_left,waterlogged:false}", + "minecraft:polished_andesite_stairs{facing:west,half:bottom,shape:straight,waterlogged:false}", + "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:true}", + "minecraft:polished_andesite_stairs{facing:north,half:bottom,shape:outer_left,waterlogged:false}", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_lava.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_lava.snbt new file mode 100644 index 000000000..c93eb769e --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_lava.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:lava_bucket"}], Label: "turtle_test.place_lava", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_stained_glass", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_monitor.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_monitor.snbt new file mode 100644 index 000000000..a1621f782 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_monitor.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", nbt: {Height: 1, Width: 1, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:monitor_advanced"}], Label: "turtle_test.place_monitor", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:dark_oak_planks"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:l}", nbt: {Height: 1, Width: 3, XIndex: 2, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lr}", nbt: {Height: 1, Width: 3, XIndex: 1, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:r}", nbt: {Height: 1, Width: 3, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:dark_oak_planks", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:l}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:lr}", + "computercraft:monitor_advanced{facing:north,orientation:north,state:r}", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_waterlogged.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_waterlogged.snbt new file mode 100644 index 000000000..434b3d26f --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_waterlogged.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:true}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:oak_fence"}], Label: "turtle_test.place_waterlogged", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 2], state: "minecraft:water{level:0}"}, + {pos: [2, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_stained_glass", + "computercraft:turtle_normal{facing:south,waterlogged:true}", + "minecraft:air", + "minecraft:water{level:0}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_basic.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_basic.snbt new file mode 100644 index 000000000..6210a07c9 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_basic.snbt @@ -0,0 +1,137 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Label: "turtle_test.refuel_basic", Fuel: 0, Items: [{Count: 2b, Slot: 0b, id: "minecraft:coal"},{Count: 2b, Slot: 1b, id: "minecraft:blaze_rod"}], On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_container.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_container.snbt new file mode 100644 index 000000000..bf9d1c1ff --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_container.snbt @@ -0,0 +1,137 @@ +{ + DataVersion: 2975, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Label: "turtle_test.refuel_container", Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:lava_bucket"}], On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_entity_explosions.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_entity_explosions.snbt new file mode 100644 index 000000000..79b2f8ef6 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_entity_explosions.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {Fuel: 0, Items: [], On: 0b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 2], state: "computercraft:turtle_advanced{facing:south,waterlogged:false}", nbt: {Fuel: 0, Items: [], On: 0b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [ + {blockPos: [1, 1, 2], pos: [1.5d, 1.0d, 2.5d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.0d, Name: "forge:step_height_addition"}, {Base: 0.25d, Name: "minecraft:generic.movement_speed"}, {Base: 0.08d, Name: "forge:entity_gravity"}, {Base: 16.0d, Modifiers: [{Amount: -0.0871987524284032d, Name: "Random spawn bonus", Operation: 1, UUID: [I; -1592956383, -599506679, -1812844190, 1076877318]}], Name: "minecraft:generic.follow_range"}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, DeathTime: 0s, ExplosionRadius: 3b, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, Fuse: 30s, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [2.5d, -58.0d, 3.5d], Rotation: [143.85756f, 0.0f], UUID: [I; 1463798444, -662876850, -1423329658, 948503391], id: "minecraft:creeper", ignited: 0b}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "computercraft:turtle_advanced{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_explosions.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_explosions.snbt new file mode 100644 index 000000000..89ae4bc14 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_explosions.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:barrier"}, + {pos: [0, 1, 1], state: "minecraft:barrier"}, + {pos: [0, 1, 2], state: "minecraft:barrier"}, + {pos: [0, 1, 3], state: "minecraft:barrier"}, + {pos: [0, 1, 4], state: "minecraft:barrier"}, + {pos: [1, 1, 0], state: "minecraft:barrier"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:barrier"}, + {pos: [2, 1, 0], state: "minecraft:barrier"}, + {pos: [2, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {Fuel: 0, Items: [], On: 0b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 2], state: "computercraft:turtle_advanced{facing:south,waterlogged:false}", nbt: {Fuel: 0, Items: [], On: 0b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:barrier"}, + {pos: [3, 1, 0], state: "minecraft:barrier"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:barrier"}, + {pos: [4, 1, 0], state: "minecraft:barrier"}, + {pos: [4, 1, 1], state: "minecraft:barrier"}, + {pos: [4, 1, 2], state: "minecraft:barrier"}, + {pos: [4, 1, 3], state: "minecraft:barrier"}, + {pos: [4, 1, 4], state: "minecraft:barrier"}, + {pos: [0, 2, 0], state: "minecraft:barrier"}, + {pos: [0, 2, 1], state: "minecraft:barrier"}, + {pos: [0, 2, 2], state: "minecraft:barrier"}, + {pos: [0, 2, 3], state: "minecraft:barrier"}, + {pos: [0, 2, 4], state: "minecraft:barrier"}, + {pos: [1, 2, 0], state: "minecraft:barrier"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:barrier"}, + {pos: [2, 2, 0], state: "minecraft:barrier"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:barrier"}, + {pos: [3, 2, 0], state: "minecraft:barrier"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:barrier"}, + {pos: [4, 2, 0], state: "minecraft:barrier"}, + {pos: [4, 2, 1], state: "minecraft:barrier"}, + {pos: [4, 2, 2], state: "minecraft:barrier"}, + {pos: [4, 2, 3], state: "minecraft:barrier"}, + {pos: [4, 2, 4], state: "minecraft:barrier"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:barrier", + "minecraft:air", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "computercraft:turtle_advanced{facing:south,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.shears_sheep.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.shears_sheep.snbt new file mode 100644 index 000000000..4f6afef2c --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.shears_sheep.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 2], state: "minecraft:air"}, + {pos: [2, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:white_stained_glass"}, + {pos: [1, 2, 2], state: "minecraft:white_stained_glass"}, + {pos: [1, 2, 3], state: "minecraft:white_stained_glass"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:white_stained_glass"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:white_stained_glass"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:white_stained_glass"}, + {pos: [3, 2, 2], state: "minecraft:white_stained_glass"}, + {pos: [3, 2, 3], state: "minecraft:white_stained_glass"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "minecraft:shears", tag: {Damage: 0}}], Label: "turtle_test.shears_sheep", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [ + {blockPos: [2, 1, 2], pos: [2.5d, 1.0d, 2.5d], nbt: {AbsorptionAmount: 0.0f, Age: 0, Air: 300s, ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 8.0d, Name: "generic.maxHealth"}, {Base: 0.0d, Name: "generic.knockbackResistance"}, {Base: 0.23000000417232513d, Name: "generic.movementSpeed"}, {Base: 0.0d, Name: "generic.armor"}, {Base: 0.0d, Name: "generic.armorToughness"}, {Base: 1.0d, Name: "forge.swimSpeed"}, {Base: 64.0d, Name: "forge.nameTagDistance"}, {Base: 0.08d, Name: "forge.entity_gravity"}, {Base: 16.0d, Modifiers: [{Amount: -0.04393447767139704d, Name: "Random spawn bonus", Operation: 1, UUIDLeast: -7913974980122166977L, UUIDMost: 2135385928807173041L}], Name: "generic.followRange"}, {Base: 0.0d, Name: "generic.attackKnockback"}], Brain: {memories: {}}, CanPickUpLoot: 0b, CanUpdate: 1b, Color: 0b, DeathTime: 0s, Dimension: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, ForcedAge: 0, HandDropChances: [0.085f, 0.085f], HandItems: [{}, {}], Health: 8.0f, HurtByTimestamp: 0, HurtTime: 0s, InLove: 0, Invulnerable: 0b, LeftHanded: 0b, Motion: [0.0d, -0.0784000015258789d, 0.0d], OnGround: 1b, PersistenceRequired: 0b, PortalCooldown: 0, Pos: [-12.5d, 6.0d, 110.5d], Rotation: [99.779915f, 0.0f], Sheared: 0b, UUIDLeast: -5245632071702074643L, UUIDMost: -3792049278188698748L, id: "minecraft:sheep"}} + ], + palette: [ + "minecraft:polished_andesite", + "minecraft:white_stained_glass", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.unequip_refreshes_peripheral.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.unequip_refreshes_peripheral.snbt new file mode 100644 index 000000000..de5d48438 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.unequip_refreshes_peripheral.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "computercraft:disk_drive{facing:north,state:empty}", nbt: {id: "computercraft:disk_drive"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [], Label: "turtle_test.unequip_refreshes_peripheral", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, RightUpgrade: "computercraft:wireless_modem_normal", RightUpgradeNbt: {active: 0b}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "computercraft:disk_drive{facing:north,state:empty}", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:air" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.use_compostors.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.use_compostors.snbt new file mode 100644 index 000000000..7bf966662 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.use_compostors.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 2730, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "minecraft:composter{level:0}"}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 0, Items: [{Count: 64b, Slot: 0b, id: "minecraft:spruce_sapling"}], Label: "turtle_test.use_compostors", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "computercraft:turtle_normal{facing:south,waterlogged:false}", + "minecraft:air", + "minecraft:composter{level:0}" + ] +} diff --git a/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json b/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json new file mode 100644 index 000000000..0e238db06 --- /dev/null +++ b/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json @@ -0,0 +1,20 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:treasure_disk", + "functions": [ + { + "function": "minecraft:set_nbt", + "tag": "{\"Title\": \"Demo disk\", \"SubPath\": \"demo\", \"Colour\": 15905331}" + } + ] + } + ] + } + ] +} diff --git a/src/testMod/resources/data/computercraft/lua/rom/autorun/cctest.lua b/src/testMod/resources/data/computercraft/lua/rom/autorun/cctest.lua new file mode 100644 index 000000000..ecf36c4e9 --- /dev/null +++ b/src/testMod/resources/data/computercraft/lua/rom/autorun/cctest.lua @@ -0,0 +1,25 @@ +--- Extend the test API with some convenience functions. +-- +-- It's much easier to declare these in Lua rather than Java. + +function test.assert(ok, ...) + if ok then return ... end + + test.fail(... and tostring(...) or "Assertion failed") +end + +function test.eq(expected, actual, msg) + if expected == actual then return end + + local message = ("Assertion failed:\nExpected %s,\ngot %s"):format(expected, actual) + if msg then message = ("%s - %s"):format(msg, message) end + test.fail(message) +end + +function test.neq(expected, actual, msg) + if expected ~= actual then return end + + local message = ("Assertion failed:\nExpected something different to %s"):format(expected) + if msg then message = ("%s - %s"):format(msg, message) end + test.fail(message) +end diff --git a/src/testMod/resources/pack.mcmeta b/src/testMod/resources/pack.mcmeta index d5db9991c..9ed247d36 100755 --- a/src/testMod/resources/pack.mcmeta +++ b/src/testMod/resources/pack.mcmeta @@ -1,6 +1,6 @@ { - "pack": { - "pack_format": 4, - "description": "CC: Test" - } + "pack": { + "pack_format": 7, + "description": "CC: Test" + } } From 8fb24a85dbbb7370d59afa4d168e5517158d4f63 Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 3 May 2024 01:49:26 +0200 Subject: [PATCH 06/61] Added needed junit and hamcrest libraries to the minecraft classpath so they are included in the runtime when we run the tests --- build.gradle | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/build.gradle b/build.gradle index bf4df40bc..bbc4c6433 100644 --- a/build.gradle +++ b/build.gradle @@ -83,7 +83,13 @@ minecraft { accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') accessTransformer file('src/testMod/resources/META-INF/accesstransformer.cfg') + runs { + all { + lazyToken('minecraft_classpath') { + configurations.library.copyRecursive().resolve().collect { it.absolutePath }.join(File.pathSeparator) + } + } client { workingDirectory project.file('run') @@ -168,6 +174,20 @@ minecraft { } gameTestServer { + def old = lazyTokens["minecraft_classpath"] + lazyToken("minecraft_classpath") { + // Add all files in testMinecraftLibrary to the classpath. + def allFiles = new HashSet(); + + def oldVal = old?.get() + if (!oldVal != null && !oldVal.isEmpty()) allFiles.addAll(oldVal.split(File.pathSeparatorChar)) + + for (file in configurations["testMinecraftLibrary"]) allFiles.add(file.absolutePath) + + println("New classpath $allFiles") + allFiles.join(File.pathSeparator) + } + workingDirectory project.file('test-files/server') property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' @@ -272,6 +292,25 @@ repositories { } configurations { + named("testModCompileClasspath") { + shouldResolveConsistentlyWith compileClasspath + } + + named("testModRuntimeClasspath") { + shouldResolveConsistentlyWith runtimeClasspath + } + + munecraftLibrary { extendsFrom(minecraftEmbed) } + + testMinecraftLibrary { + canBeResolved = true + canBeConsumed = false + // Prevent ending up with multiple versions of libraries on the classpath. + shouldResolveConsistentlyWith(minecraftLibrary) + } + + library + implementation.extendsFrom library implementationExtra testImplementation.extendsFrom(implementation) testModImplementation.extendsFrom(implementation) @@ -369,6 +408,10 @@ dependencies { testModImplementation sourceSets.main.output testModImplementation sourceSets.testFixtures.output + testMinecraftLibrary("org.junit.jupiter:junit-jupiter-api:${junit_version}") + testMinecraftLibrary("org.junit.jupiter:junit-jupiter-params:${junit_version}") + testMinecraftLibrary("org.hamcrest:hamcrest:${hamcrest_version}") + // Testing stuff // JEI implementation fg.deobf("mezz.jei:jei-${jei_version}") From 09e4e81ad4774d1dab1332464f4c4d1336246aca Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 3 May 2024 01:51:26 +0200 Subject: [PATCH 07/61] Added jqwik database to gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8fa3a9245..6bf01776a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,12 +21,12 @@ build eclipse run server +/.jqwik-database # Files from Forge MDK forge*changelog.txt #github - 1.17 .env From 097a824686ee37a7555523612970d8bcee4da05a Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 3 May 2024 02:03:04 +0200 Subject: [PATCH 08/61] Fixed game tests for `runGameTestClient` --- build.gradle | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index bbc4c6433..0219cfd31 100644 --- a/build.gradle +++ b/build.gradle @@ -75,7 +75,6 @@ java.registerFeature("testFixtures") { disablePublication() } - minecraft { mappings channel: "${mappings_channel}", version: "${mappings_version}" @@ -152,6 +151,21 @@ minecraft { gameTestClient { workingDirectory project.file('test-files/client') parent runs.client + + def old = lazyTokens["minecraft_classpath"] + lazyToken("minecraft_classpath") { + // Add all files in testMinecraftLibrary to the classpath. + def allFiles = new HashSet(); + + def oldVal = old?.get() + if (!oldVal != null && !oldVal.isEmpty()) allFiles.addAll(oldVal.split(File.pathSeparatorChar)) + + for (file in configurations["testMinecraftLibrary"]) allFiles.add(file.absolutePath) + + println("New classpath $allFiles") + allFiles.join(File.pathSeparator) + } + property 'forge.logging.markers', 'REGISTRIES' property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' @@ -165,12 +179,6 @@ minecraft { source sourceSets.testFixtures } } - - lazyToken('minecraft_classpath') { - (configurations.implementationExtra.copyRecursive().resolve()) - .collect { it.absolutePath } - .join(File.pathSeparator) - } } gameTestServer { From c258ba499ec66b736e82bc8be879906cf3cd55fd Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 3 May 2024 13:57:17 +0200 Subject: [PATCH 09/61] Rename var old -> oldClasspath, oldVal -> minecraftClasspath --- build.gradle | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 0219cfd31..24438c78f 100644 --- a/build.gradle +++ b/build.gradle @@ -152,13 +152,13 @@ minecraft { workingDirectory project.file('test-files/client') parent runs.client - def old = lazyTokens["minecraft_classpath"] + def oldClasspath = lazyTokens["minecraft_classpath"] lazyToken("minecraft_classpath") { // Add all files in testMinecraftLibrary to the classpath. def allFiles = new HashSet(); - def oldVal = old?.get() - if (!oldVal != null && !oldVal.isEmpty()) allFiles.addAll(oldVal.split(File.pathSeparatorChar)) + def minecraftClasspath = oldClasspath?.get() + if (!minecraftClasspath != null && !minecraftClasspath.isEmpty()) allFiles.addAll(minecraftClasspath.split(File.pathSeparatorChar)) for (file in configurations["testMinecraftLibrary"]) allFiles.add(file.absolutePath) @@ -182,13 +182,13 @@ minecraft { } gameTestServer { - def old = lazyTokens["minecraft_classpath"] + def oldClasspath = lazyTokens["minecraft_classpath"] lazyToken("minecraft_classpath") { // Add all files in testMinecraftLibrary to the classpath. def allFiles = new HashSet(); - def oldVal = old?.get() - if (!oldVal != null && !oldVal.isEmpty()) allFiles.addAll(oldVal.split(File.pathSeparatorChar)) + def minecraftClasspath = oldClasspath?.get() + if (!minecraftClasspath != null && !minecraftClasspath.isEmpty()) allFiles.addAll(minecraftClasspath.split(File.pathSeparatorChar)) for (file in configurations["testMinecraftLibrary"]) allFiles.add(file.absolutePath) From 231b1756f0935308b66dccad6b6ab47169c320fe Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 3 May 2024 14:05:46 +0200 Subject: [PATCH 10/61] Remove some not needed stuff in the build.gradle --- build.gradle | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 24438c78f..0a29f2859 100644 --- a/build.gradle +++ b/build.gradle @@ -300,15 +300,7 @@ repositories { } configurations { - named("testModCompileClasspath") { - shouldResolveConsistentlyWith compileClasspath - } - - named("testModRuntimeClasspath") { - shouldResolveConsistentlyWith runtimeClasspath - } - - munecraftLibrary { extendsFrom(minecraftEmbed) } + minecraftLibrary { extendsFrom(minecraftEmbed) } testMinecraftLibrary { canBeResolved = true From d4c127d4edacb4b83a8c8809df2157928cc4cedc Mon Sep 17 00:00:00 2001 From: Srendi Date: Fri, 3 May 2024 15:00:49 +0200 Subject: [PATCH 11/61] Created a test using kotlin for the environmental detector. This was just a test, there is a bug loading the structures what I need to fix. --- build.gradle | 4 ++++ gradle/wrapper/gradle-wrapper.properties | 2 +- .../TestGameTests.java | 19 ---------------- .../test/Peripheral_Test.kt | 21 ++++++++++++++++++ .../structures/envdetectortest.nbt | Bin 548 -> 0 bytes .../peripheral_test.environment.nbt | Bin 0 -> 691 bytes 6 files changed, 26 insertions(+), 20 deletions(-) delete mode 100644 src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/envdetectortest.nbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.nbt diff --git a/build.gradle b/build.gradle index 0a29f2859..96662f578 100644 --- a/build.gradle +++ b/build.gradle @@ -319,6 +319,10 @@ configurations { testFixturesImplementation.extendsFrom(testImplementation) } +processTestModResources { + duplicatesStrategy = 'exclude' +} + dependencies { // If some of the dependencies are not needed in the dev environment, you can comment the `runtimeOnly` line so it // will not be included in the client. diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 309b4e18d..bb6c19194 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java b/src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java deleted file mode 100644 index 209e996e5..000000000 --- a/src/testMod/java/de/srendi/advancedperipheralstest/TestGameTests.java +++ /dev/null @@ -1,19 +0,0 @@ -package de.srendi.advancedperipheralstest; - -import net.minecraft.gametest.framework.GameTest; -import net.minecraft.gametest.framework.GameTestHelper; -import net.minecraftforge.gametest.GameTestHolder; -import net.minecraftforge.gametest.PrefixGameTestTemplate; -import org.junit.jupiter.api.Assertions; - - -@GameTestHolder("advancedperipheralstest") -public class TestGameTests { - - @PrefixGameTestTemplate(false) - @GameTest(templateNamespace = "advancedperipheralstest") - public static void envDetectorTest(GameTestHelper helper) { - Assertions.assertEquals("Cock", "Cock"); - } - -} diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt new file mode 100644 index 000000000..7b53fe454 --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt @@ -0,0 +1,21 @@ +package de.srendi.advancedperipherals.test + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.sequence +import de.srendi.advancedperipherals.common.setup.Blocks +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper + +@GameTestHolder +class Peripheral_Test { + + @GameTest + fun Environment(context: GameTestHelper) = context.sequence { + val detector = BlockPos(2, 2, 2); + thenExecute { + context.assertBlock(detector, {block -> block.defaultBlockState().`is`(Blocks.ENVIRONMENT_DETECTOR.get())}, "Block is not a environment detector"); + } + } + +} \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/envdetectortest.nbt b/src/testMod/resources/data/advancedperipheralstest/structures/envdetectortest.nbt deleted file mode 100644 index c833300f1352bf4ed03a9945c5454414fb3a7334..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 548 zcmb2|=3oGW|Gn27^KThQw0|_;_Hxpe-R~|PF1u6sJnpvdDz#kew?UyNRPr{?x-l`g z>c;YXrafDnkN$Lb()e)XXJcxCZ^*>1Z}TU*nAnQ_i3!Y%*>rN2$K}9_H&=Z=8@%TD zgB)jt%7ce$=F5c) zybr8l*vxc>%Rn2*Fn;?yIqz+Uq_KH%w)>eGJ7-2)7pLVtyLN8QPKGnA31SUES1`^1 zGnmpiXQ(DjYlvh@W1S(I5Y`aMnD%wuPPLa|E0?`$=kI?O#Xr$YXxq~Bz3B&BmYj!OEKSNYEZ}Q7>>Bn<_YCmQZezU>MvHatyJ$zepzB|wTAziV0 zO7iE#3v)eB`s~gPopkGwUiIrU@4O{z(jVX2;{7&C_-%!(yL`NI?qQDg|5@x;Et^~8 zna;m!aJ1R2#HSd~b?U(yqv(_>{eCg+eYwZs|ym!C! Z(?qx4x8rg^$;aL}hS?@rV#|3L7yu&j3xEIs diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.nbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.nbt new file mode 100644 index 0000000000000000000000000000000000000000..cf4ecf423af054fd99326f3b57280e4eb0d83c81 GIT binary patch literal 691 zcmb2|=3oGW|GhUh=3jOYIsUQy{az9E)~QRGdwe=}W^)IrviRt5xK96ZYtF12(`sKf z9QogO_u1B^S?}v6F48!8{ds?JmGd5jS(Eub`U@z{nrB>nZY7s*mu6ezvg335!fuz< z+UguLuYax*YkkAX0mw$9bg<` zWPRWbgE4a&8`Ng813EC9A+815e14X=%2};Yli#nx6TQ`AUnFnm+ Date: Sun, 5 May 2024 21:52:06 +0200 Subject: [PATCH 12/61] Remove CC tests and complete the environment detector test The test can be run via `runGameTestClient` using the /test command or `runGameTestServer` to run all the tests automatically --- .../computercraft/gametest/Computer_Test.kt | 72 ---- .../computercraft/gametest/CraftOs_Test.kt | 22 - .../computercraft/gametest/Disk_Drive_Test.kt | 55 --- .../computercraft/gametest/Loot_Test.kt | 37 -- .../computercraft/gametest/Modem_Test.kt | 102 ----- .../computercraft/gametest/Monitor_Test.kt | 50 --- .../computercraft/gametest/Recipe_Test.kt | 65 --- .../computercraft/gametest/Turtle_Test.kt | 384 ------------------ .../test/Peripheral_Test.kt | 5 +- ..._test.sends_basic_rednet_messages.echo.lua | 8 - ..._test.sends_basic_rednet_messages.main.lua | 10 - .../tests/peripheral_test.environment.lua | 8 + .../computer_test.computer_peripheral.snbt | 138 ------- .../computer_test.no_through_signal.snbt | 141 ------- ...mputer_test.no_through_signal_reverse.snbt | 141 ------- .../computer_test.set_and_destroy.snbt | 138 ------- ...ftos_test.sends_basic_rednet_messages.snbt | 139 ------- .../structures/default.snbt | 136 ------- .../disk_drive_test.audio_disk.snbt | 40 -- .../disk_drive_test.ejects_disk.snbt | 139 ------- .../modem_test.gains_peripherals.snbt | 145 ------- .../modem_test.have_peripherals.snbt | 146 ------- .../modem_test.transmits_messages.snbt | 140 ------- .../monitor_test.ensures_valid_on_place.snbt | 136 ------- .../monitor_test.looks_acceptable.snbt | 146 ------- .../monitor_test.looks_acceptable_dark.snbt | 145 ------- .../peripheral_test.environment.nbt | Bin 691 -> 0 bytes ....snbt => peripheral_test.environment.snbt} | 10 +- .../printouttest.in_frame_at_night.snbt | 140 ------- .../structures/turtle_test.attack_entity.snbt | 140 ------- .../turtle_test.attack_entity_destroy.snbt | 141 ------- .../turtle_test.cleaned_with_cauldrons.snbt | 40 -- .../turtle_test.drop_into_chest.snbt | 138 ------- .../turtle_test.drop_into_entity.snbt | 140 ------- .../structures/turtle_test.gather_lava.snbt | 139 ------- .../structures/turtle_test.hoe_dirt.snbt | 40 -- .../turtle_test.item_detail_provider.snbt | 39 -- .../structures/turtle_test.move_obstruct.snbt | 138 ------- .../structures/turtle_test.move_replace.snbt | 139 ------- .../structures/turtle_test.move_water.snbt | 148 ------- .../structures/turtle_test.place_lava.snbt | 138 ------- .../structures/turtle_test.place_monitor.snbt | 142 ------- .../turtle_test.place_waterlogged.snbt | 139 ------- .../structures/turtle_test.refuel_basic.snbt | 137 ------- .../turtle_test.refuel_container.snbt | 137 ------- ...turtle_test.resists_entity_explosions.snbt | 140 ------- .../turtle_test.resists_explosions.snbt | 139 ------- .../structures/turtle_test.shears_sheep.snbt | 140 ------- ...tle_test.unequip_refreshes_peripheral.snbt | 138 ------- .../turtle_test.use_compostors.snbt | 138 ------- .../loot_tables/treasure_disk.json | 20 - .../computers/computer/0/startup.lua | 11 - .../computer/0/tests/automata.weak.lua | 25 -- .../computer/0/tests/botania.manapool.lua | 0 .../0/tests/peripherals.geoscanner.lua | 9 - src/testMod/server-files/eula.txt | 2 - src/testMod/server-files/server.properties | 45 -- 57 files changed, 15 insertions(+), 5565 deletions(-) delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt delete mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/default.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.nbt rename src/testMod/resources/data/advancedperipheralstest/structures/{disk_drive_test.adds_removes_mount.snbt => peripheral_test.environment.snbt} (92%) delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/printouttest.in_frame_at_night.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.attack_entity_destroy.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.cleaned_with_cauldrons.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_chest.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.drop_into_entity.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.gather_lava.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.hoe_dirt.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.item_detail_provider.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_obstruct.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_replace.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.move_water.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_lava.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_monitor.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.place_waterlogged.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_basic.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.refuel_container.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_entity_explosions.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.resists_explosions.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.shears_sheep.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.unequip_refreshes_peripheral.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/turtle_test.use_compostors.snbt delete mode 100644 src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json delete mode 100644 src/testMod/server-files/computers/computer/0/startup.lua delete mode 100644 src/testMod/server-files/computers/computer/0/tests/automata.weak.lua delete mode 100644 src/testMod/server-files/computers/computer/0/tests/botania.manapool.lua delete mode 100644 src/testMod/server-files/computers/computer/0/tests/peripherals.geoscanner.lua delete mode 100644 src/testMod/server-files/eula.txt delete mode 100644 src/testMod/server-files/server.properties diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt deleted file mode 100644 index 8eec0fabf..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Computer_Test.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.core.apis.RedstoneAPI -import dan200.computercraft.core.computer.ComputerSide -import dan200.computercraft.gametest.api.* -import dan200.computercraft.test.core.computer.getApi -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.world.level.block.Blocks -import net.minecraft.world.level.block.LeverBlock -import net.minecraft.world.level.block.RedstoneLampBlock - -@GameTestHolder -class Computer_Test { - /** - * Ensures redstone signals do not travel through computers. - * - * @see [#548](https://github.com/cc-tweaked/CC-Tweaked/issues/548) - */ - @GameTest - fun No_through_signal(context: GameTestHelper) = context.sequence { - val lamp = BlockPos(2, 2, 4) - val lever = BlockPos(2, 2, 0) - thenExecute { - context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should not be lit") - context.modifyBlock(lever) { x -> x.setValue(LeverBlock.POWERED, true) } - } - thenIdle(3) - thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should still not be lit") } - } - - /** - * Similar to the above, but with a repeater before the computer - */ - @GameTest - fun No_through_signal_reverse(context: GameTestHelper) = context.sequence { - val lamp = BlockPos(2, 2, 4) - val lever = BlockPos(2, 2, 0) - thenExecute { - context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should not be lit") - context.modifyBlock(lever) { x -> x.setValue(LeverBlock.POWERED, true) } - } - thenIdle(3) - thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should still not be lit") } - } - - @GameTest - fun Set_and_destroy(context: GameTestHelper) = context.sequence { - val lamp = BlockPos(2, 2, 3) - - thenOnComputer { getApi().setOutput(ComputerSide.BACK, true) } - thenIdle(3) - thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, true, "Lamp should be lit") } - thenExecute { context.setBlock(BlockPos(2, 2, 2), Blocks.AIR) } - thenIdle(4) - thenExecute { context.assertBlockHas(lamp, RedstoneLampBlock.LIT, false, "Lamp should not be lit") } - } - - @GameTest - fun Computer_peripheral(context: GameTestHelper) = context.sequence { - thenExecute { - context.assertPeripheral(BlockPos(3, 2, 2), type = "computer") - context.assertPeripheral(BlockPos(1, 2, 2), type = "turtle") - } - } -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt deleted file mode 100644 index 0ec7e3427..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/CraftOs_Test.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.Timeouts -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.gametest.api.thenComputerOk -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper - -@GameTestHolder -class CraftOs_Test { - /** - * Sends a rednet message to another a computer and back again. - */ - @GameTest(timeoutTicks = Timeouts.COMPUTER_TIMEOUT) - fun Sends_basic_rednet_messages(context: GameTestHelper) = context.sequence { thenComputerOk("main") } -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt deleted file mode 100644 index a45cf0772..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Disk_Drive_Test.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.core.apis.FSAPI -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.gametest.api.thenOnComputer -import dan200.computercraft.test.core.assertArrayEquals -import dan200.computercraft.test.core.computer.getApi -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.world.item.Items -import org.junit.jupiter.api.Assertions.assertEquals - -@GameTestHolder -class Disk_Drive_Test { - /** - * Ensure audio disks exist and we can play them. - * - * @see [#688](https://github.com/cc-tweaked/CC-Tweaked/issues/688) - */ - @GameTest - fun Audio_disk(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - callPeripheral("right", "hasAudio") - .assertArrayEquals(true, message = "Disk has audio") - - callPeripheral("right", "getAudioTitle") - .assertArrayEquals("C418 - 13", message = "Correct audio title") - } - } - - @GameTest - fun Ejects_disk(helper: GameTestHelper) = helper.sequence { - val stackAt = BlockPos(2, 2, 2) - thenOnComputer { callPeripheral("right", "ejectDisk") } - thenWaitUntil { helper.assertItemEntityPresent(Items.MUSIC_DISC_13, stackAt, 0.0) } - } - - @GameTest - fun Adds_removes_mount(helper: GameTestHelper) = helper.sequence { - thenIdle(2) - thenOnComputer { - getApi().getDrive("disk").assertArrayEquals("right") - callPeripheral("right", "ejectDisk") - } - thenIdle(2) - thenOnComputer { assertEquals(null, getApi().getDrive("disk")) } - } -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt deleted file mode 100644 index dd5b52121..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Loot_Test.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.Structures -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.shared.Registry -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.world.level.block.Blocks -import net.minecraft.world.level.block.entity.ChestBlockEntity -import net.minecraft.world.level.storage.loot.BuiltInLootTables - -@GameTestHolder -class Loot_Test { - /** - * Test that the loot tables will spawn in treasure disks. - */ - @GameTest(template = Structures.DEFAULT) - fun Chest_contains_disk(context: GameTestHelper) = context.sequence { - thenExecute { - val pos = BlockPos(2, 2, 2) - - context.setBlock(pos, Blocks.CHEST) - val chest = context.getBlockEntity(pos) as ChestBlockEntity - chest.setLootTable(BuiltInLootTables.SIMPLE_DUNGEON, 123) - chest.unpackLootTable(null) - - context.assertContainerContains(pos, Registry.ModItems.TREASURE_DISK.get()) - } - } -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt deleted file mode 100644 index a4b454ba3..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Modem_Test.kt +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.api.lua.ObjectArguments -import dan200.computercraft.core.apis.PeripheralAPI -import dan200.computercraft.core.computer.ComputerSide -import dan200.computercraft.gametest.api.* -import dan200.computercraft.shared.peripheral.modem.wired.BlockCable -import dan200.computercraft.test.core.assertArrayEquals -import dan200.computercraft.test.core.computer.LuaTaskContext -import dan200.computercraft.test.core.computer.getApi -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper -import org.junit.jupiter.api.Assertions.assertEquals -import kotlin.time.Duration.Companion.milliseconds - -@GameTestHolder -class Modem_Test { - @GameTest - fun Have_peripherals(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - assertEquals(listOf("monitor_0", "printer_0", "right"), getPeripheralNames(), "Starts with peripherals") - } - } - - @GameTest - fun Gains_peripherals(helper: GameTestHelper) = helper.sequence { - val position = BlockPos(2, 2, 2) - thenOnComputer { - assertEquals(listOf("back"), getPeripheralNames(), "Starts with peripherals") - } - thenExecute { - helper.setBlock( - position, - BlockCable.correctConnections( - helper.level, - helper.absolutePos(position), - dan200.computercraft.shared.Registry.ModBlocks.CABLE.get().defaultBlockState().setValue(BlockCable.CABLE, true), - ), - ) - } - thenIdle(1) - thenOnComputer { - assertEquals(listOf("back", "monitor_1", "printer_1"), getPeripheralNames(), "Gains new peripherals") - } - } - - /** - * Sends a modem message to another computer on the same network - */ - @GameTest - fun Transmits_messages(context: GameTestHelper) = context.sequence { - thenStartComputer("send") { - val modem = findPeripheral("modem") ?: throw IllegalStateException("Cannot find modem") - while (true) { - callPeripheral(modem, "transmit", 12, 34, "Hello") - sleep(50.milliseconds) - } - } - thenOnComputer("receive") { - val modem = findPeripheral("modem") ?: throw IllegalStateException("Cannot find modem") - callPeripheral(modem, "open", 12) - - pullEvent("modem_message") - .assertArrayEquals("modem_message", "left", 12, 34, "Hello", 4, message = "Modem message") - } - } -} - -private fun LuaTaskContext.findPeripheral(type: String): String? { - val peripheral = getApi() - for (side in ComputerSide.NAMES) { - val hasType = peripheral.hasType(side, type) - if (hasType != null && hasType[0] == true) return side - } - - return null -} - -private suspend fun LuaTaskContext.getPeripheralNames(): List { - val peripheral = getApi() - val peripherals = mutableListOf() - for (side in ComputerSide.NAMES) { - if (!peripheral.isPresent(side)) continue - peripherals.add(side) - - val hasType = peripheral.hasType(side, "modem") - if (hasType == null || hasType[0] != true) continue - - val names = peripheral.call(context, ObjectArguments(side, "getNamesRemote")).await() ?: continue - @Suppress("UNCHECKED_CAST") - peripherals.addAll(names[0] as Collection) - } - - peripherals.sort() - return peripherals -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt deleted file mode 100644 index e34ba16d3..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Monitor_Test.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.getBlockEntity -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.gametest.api.setBlock -import dan200.computercraft.shared.Registry -import net.minecraft.commands.arguments.blocks.BlockInput -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.nbt.CompoundTag -import net.minecraft.world.level.block.Blocks -import java.util.* - -@GameTestHolder -class Monitor_Test { - @GameTest - fun Ensures_valid_on_place(context: GameTestHelper) = context.sequence { - val pos = BlockPos(2, 2, 2) - - thenExecute { - val tag = CompoundTag() - tag.putInt("Width", 2) - tag.putInt("Height", 2) - - val toSet = BlockInput( - Registry.ModBlocks.MONITOR_ADVANCED.get().defaultBlockState(), - Collections.emptySet(), - tag, - ) - - context.setBlock(pos, Blocks.AIR.defaultBlockState()) - context.setBlock(pos, toSet) - } - thenIdle(2) - thenExecute { - val tile = context.getBlockEntity(pos, Registry.ModBlockEntities.MONITOR_ADVANCED.get()) - - if (tile.width != 1 || tile.height != 1) { - context.fail("Tile has width and height of ${tile.width}x${tile.height}, but should be 1x1", pos) - } - } - } -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt deleted file mode 100644 index 9e9fc868c..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Recipe_Test.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.Structures -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.shared.Registry -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestAssertException -import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.nbt.CompoundTag -import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.inventory.CraftingContainer -import net.minecraft.world.inventory.MenuType -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items -import net.minecraft.world.item.crafting.CraftingRecipe -import net.minecraft.world.item.crafting.RecipeType -import org.junit.jupiter.api.Assertions.assertEquals -import java.util.* - -@GameTestHolder -class Recipe_Test { - /** - * Test that crafting results contain NBT data. - * - * Mostly useful for Fabric, where we need a mixin for this. - */ - @GameTest(template = Structures.DEFAULT) - fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence { - thenExecute { - val container = CraftingContainer(DummyMenu, 3, 3) - container.setItem(0, ItemStack(Items.SKELETON_SKULL)) - container.setItem(1, ItemStack(Registry.ModItems.COMPUTER_ADVANCED.get())) - - val recipe: Optional = context.level.server.recipeManager - .getRecipeFor(RecipeType.CRAFTING, container, context.level) - if (!recipe.isPresent) throw GameTestAssertException("No recipe matches") - - val result = recipe.get().assemble(container) - - val owner = CompoundTag() - owner.putString("Name", "dan200") - owner.putString("Id", "f3c8d69b-0776-4512-8434-d1b2165909eb") - val tag = CompoundTag() - tag.put("SkullOwner", owner) - - - if (tag.equals(result.tag)) { - context.succeed(); - } - context.fail("Expected NBT tags to be the same") - } - } - - object DummyMenu : AbstractContainerMenu(MenuType.GENERIC_9x1, 0) { - override fun quickMoveStack(player: Player, slot: Int): ItemStack = ItemStack.EMPTY - override fun stillValid(p0: Player): Boolean = true - } -} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt b/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt deleted file mode 100644 index 0548fbd46..000000000 --- a/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt +++ /dev/null @@ -1,384 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest - -import dan200.computercraft.api.detail.BasicItemDetailProvider -import dan200.computercraft.api.detail.VanillaDetailRegistries -import dan200.computercraft.api.lua.ObjectArguments -import dan200.computercraft.core.apis.PeripheralAPI -import dan200.computercraft.gametest.api.* -import dan200.computercraft.shared.Registry -import dan200.computercraft.shared.media.items.ItemPrintout -import dan200.computercraft.shared.peripheral.monitor.BlockMonitor -import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState -import dan200.computercraft.shared.turtle.apis.TurtleAPI -import dan200.computercraft.shared.util.WaterloggableHelpers -import dan200.computercraft.test.core.assertArrayEquals -import dan200.computercraft.test.core.computer.LuaTaskContext -import dan200.computercraft.test.core.computer.getApi -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper -import net.minecraft.world.entity.EntityType -import net.minecraft.world.entity.item.PrimedTnt -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items -import net.minecraft.world.level.block.Blocks -import net.minecraft.world.level.block.FenceBlock -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.array -import org.hamcrest.Matchers.instanceOf -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertNotEquals -import java.util.* - -@GameTestHolder -class Turtle_Test { - @GameTest - fun Unequip_refreshes_peripheral(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - getApi().getType("right").assertArrayEquals("modem", message = "Starts with a modem") - turtle.equipRight().await() - getApi().getType("right").assertArrayEquals("drive", message = "Unequipping gives a drive") - } - } - - /** - * Checks turtles can sheer sheep (and drop items) - * - * @see [#537](https://github.com/cc-tweaked/CC-Tweaked/issues/537) - */ - @GameTest - fun Shears_sheep(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.placeDown(ObjectArguments()).await() - .assertArrayEquals(true, message = "Shears the sheep") - - assertEquals("minecraft:white_wool", getTurtleItemDetail(2)["name"]) - } - } - - /** - * Checks turtles can place lava. - * - * @see [#518](https://github.com/cc-tweaked/CC-Tweaked/issues/518) - */ - @GameTest - fun Place_lava(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.placeDown(ObjectArguments()).await() - .assertArrayEquals(true, message = "Placed lava") - } - thenExecute { helper.assertBlockPresent(Blocks.LAVA, BlockPos(2, 2, 2)) } - } - - /** - * Checks turtles can place when waterlogged. - * - * @see [#385](https://github.com/cc-tweaked/CC-Tweaked/issues/385) - */ - @GameTest - fun Place_waterlogged(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.place(ObjectArguments()).await() - .assertArrayEquals(true, message = "Placed oak fence") - } - thenExecute { - helper.assertBlockIs(BlockPos(2, 2, 2), { it.block == Blocks.OAK_FENCE && it.getValue(FenceBlock.WATERLOGGED) }) - } - } - - /** - * Checks turtles can pick up lava - * - * @see [#297](https://github.com/cc-tweaked/CC-Tweaked/issues/297) - */ - @GameTest - fun Gather_lava(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.placeDown(ObjectArguments()).await() - .assertArrayEquals(true, message = "Picked up lava") - - assertEquals("minecraft:lava_bucket", getTurtleItemDetail()["name"]) - } - thenExecute { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) } - } - - /** - * Checks turtles can hoe dirt. - * - * @see [#258](https://github.com/cc-tweaked/CC-Tweaked/issues/258) - */ - @GameTest - fun Hoe_dirt(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.dig(Optional.empty()).await() - .assertArrayEquals(true, message = "Dug with hoe") - } - thenExecute { helper.assertBlockPresent(Blocks.FARMLAND, BlockPos(1, 2, 1)) } - } - - /** - * Checks turtles can place monitors - * - * @see [#691](https://github.com/cc-tweaked/CC-Tweaked/issues/691) - */ - @GameTest - fun Place_monitor(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.place(ObjectArguments()).await() - .assertArrayEquals(true, message = "Block was placed") - } - thenIdle(1) - thenExecute { helper.assertBlockHas(BlockPos(1, 2, 3), BlockMonitor.STATE, MonitorEdgeState.LR) } - } - - /** - * Checks turtles can place into compostors. These are non-typical inventories, so - * worth testing. - */ - @GameTest - fun Use_compostors(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - turtle.dropDown(Optional.empty()).await() - .assertArrayEquals(true, message = "Item was dropped") - assertEquals(63, turtle.getItemCount(Optional.of(1)), "Only dropped one item") - } - } - - /** - * Checks turtles can be cleaned in cauldrons. - */ - @GameTest - fun Cleaned_with_cauldrons(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - val details = getTurtleItemDetail(1, true) - turtle.place(ObjectArguments()).await() - .assertArrayEquals(true, message = "Used item on cauldron") - val newDetails = getTurtleItemDetail(1, true) - - assertEquals("computercraft:turtle_normal", newDetails["name"], "Still a turtle") - assertNotEquals(details["nbt"], newDetails["nbt"], "Colour should have changed") - } - } - - /** - * Checks turtles can use IDetailProviders by getting details for a printed page. - */ - @GameTest - fun Item_detail_provider(helper: GameTestHelper) = helper.sequence { - // Register a dummy provider for printout items - thenExecute { - VanillaDetailRegistries.ITEM_STACK.addProvider( - object : - BasicItemDetailProvider("printout", ItemPrintout::class.java) { - override fun provideDetails(data: MutableMap, stack: ItemStack, item: ItemPrintout) { - data["type"] = item.type.toString().lowercase() - } - }, - ) - } - thenOnComputer { - val details = getTurtleItemDetail(detailed = true) - assertEquals(mapOf("type" to "page"), details["printout"]) { - "Printout information is returned (whole map is $details)" - } - } - } - - /** - * Advanced turtles resist all explosions but normal ones don't. - */ - @GameTest - fun Resists_explosions(helper: GameTestHelper) = helper.sequence { - thenExecute { - val pos = helper.absolutePos(BlockPos(2, 2, 2)) - val tnt = PrimedTnt(helper.level, pos.x + 0.5, pos.y + 1.0, pos.z + 0.5, null) - tnt.fuse = 1 - helper.level.addFreshEntity(tnt) - } - thenWaitUntil { helper.assertEntityNotPresent(EntityType.TNT) } - thenExecute { - helper.assertBlockPresent(Registry.ModBlocks.TURTLE_ADVANCED.get(), BlockPos(2, 2, 2)) - helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 1)) - } - } - - /** - * Turtles resist mob explosions - */ - @GameTest - fun Resists_entity_explosions(helper: GameTestHelper) = helper.sequence { - thenExecute { helper.getEntity(EntityType.CREEPER).ignite() } - thenWaitUntil { helper.assertEntityNotPresent(EntityType.CREEPER) } - thenExecute { - helper.assertBlockPresent(Registry.ModBlocks.TURTLE_ADVANCED.get(), BlockPos(2, 2, 2)) - helper.assertBlockPresent(Registry.ModBlocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 1)) - } - } - - /** - * Test calling `turtle.drop` into an inventory. - */ - @GameTest - fun Drop_into_chest(helper: GameTestHelper) = helper.sequence { - val turtlePos = BlockPos(2, 2, 2) - val chest = BlockPos(2, 2, 3) - - thenOnComputer { - turtle.drop(Optional.of(32)).await() - .assertArrayEquals(true, message = "Could not drop items") - } - thenExecute { - helper.assertContainerExactly(turtlePos, listOf(ItemStack(Blocks.DIRT, 32), ItemStack.EMPTY, ItemStack(Blocks.DIRT, 32))) - helper.assertContainerExactly(chest, listOf(ItemStack(Blocks.DIRT, 48))) - } - } - - /** - * Test calling `turtle.drop` into an entity with an inventory - */ - @GameTest - fun Drop_into_entity(helper: GameTestHelper) = helper.sequence { - // When running /test runthis, the previous items pop from the chest. Remove them first! - thenExecute { for (it in helper.getEntities(EntityType.ITEM)) it.discard() } - - thenOnComputer { - turtle.drop(Optional.of(32)).await() - .assertArrayEquals(true, message = "Could not drop items") - } - thenExecute { - helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Blocks.DIRT, 32))) - helper.assertContainerExactly(helper.getEntity(EntityType.CHEST_MINECART), listOf(ItemStack(Blocks.DIRT, 48))) - helper.assertEntityNotPresent(EntityType.ITEM) - } - } - - /** - * Test calling `turtle.refuel` on solid fuels (coal, blaze powder) - */ - @GameTest - fun Refuel_basic(helper: GameTestHelper) = helper.sequence { - val turtlePos = BlockPos(2, 2, 2) - - // Test refueling from slot 1 with no limit. - thenOnComputer { - assertEquals(0, turtle.fuelLevel) - turtle.refuel(Optional.empty()).await().assertArrayEquals(true) - assertEquals(160, turtle.fuelLevel) - } - thenExecute { - helper.assertContainerExactly(turtlePos, listOf(ItemStack.EMPTY, ItemStack(Items.BLAZE_ROD, 2))) - } - - // Test refueling from slot 2 with a limit. - thenOnComputer { - turtle.select(2) - turtle.refuel(Optional.of(1)).await().assertArrayEquals(true) - assertEquals(280, turtle.fuelLevel) - } - thenExecute { - helper.assertContainerExactly(turtlePos, listOf(ItemStack.EMPTY, ItemStack(Items.BLAZE_ROD, 1))) - } - } - - /** - * Test calling `turtle.refuel` with a bucket of lava - */ - @GameTest - fun Refuel_container(helper: GameTestHelper) = helper.sequence { - val turtlePos = BlockPos(2, 2, 2) - - // Test refueling from slot 1 with no limit. - thenOnComputer { - assertEquals(0, turtle.fuelLevel) - turtle.refuel(Optional.empty()).await().assertArrayEquals(true) - assertEquals(1000, turtle.fuelLevel) - } - thenExecute { - helper.assertContainerExactly(turtlePos, listOf(ItemStack(Items.BUCKET))) - } - } - - /** - * Test turtles are not obstructed by plants and instead replace them. - */ - @GameTest - fun Move_replace(helper: GameTestHelper) = helper.sequence { - thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") } - thenExecute { helper.assertBlockPresent(Registry.ModBlocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 3)) } - } - - /** - * Test turtles become waterlogged when moving through liquid. - */ - @GameTest - fun Move_water(helper: GameTestHelper) = helper.sequence { - thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") } - thenExecute { - // Assert we're waterlogged. - helper.assertBlockHas(BlockPos(2, 2, 2), WaterloggableHelpers.WATERLOGGED, true) - } - thenOnComputer { turtle.forward().await().assertArrayEquals(true, message = "Turtle moved forward") } - thenExecute { - // Assert we're no longer waterlogged and we've left a source block. - helper.assertBlockIs(BlockPos(2, 2, 2), { it.block == Blocks.WATER && it.fluidState.isSource }) - helper.assertBlockHas(BlockPos(2, 2, 3), WaterloggableHelpers.WATERLOGGED, false) - } - } - - /** - * Test turtles can't move through solid blocks. - */ - @GameTest - fun Move_obstruct(helper: GameTestHelper) = helper.sequence { - thenOnComputer { turtle.forward().await().assertArrayEquals(false, "Movement obstructed") } - thenExecute { - helper.assertBlockPresent(Registry.ModBlocks.TURTLE_NORMAL.get(), BlockPos(2, 2, 2)) - helper.assertBlockPresent(Blocks.DIRT, BlockPos(2, 2, 3)) - } - } - - /** - * Test a turtle can attack an entity and capture its drops. - */ - @GameTest - fun Attack_entity(helper: GameTestHelper) = helper.sequence { - val turtlePos = BlockPos(2, 2, 2) - thenOnComputer { - turtle.attack(Optional.empty()).await().assertArrayEquals(true, message = "Attacked entity") - } - thenExecute { - helper.assertEntityNotPresent(EntityType.SHEEP) - val count = helper.getBlockEntity(turtlePos, Registry.ModBlockEntities.TURTLE_NORMAL.get()).countItem(Items.WHITE_WOOL) - if (count == 0) helper.fail("Expected turtle to have white wool", turtlePos) - } - } - - /** - * Test a turtle can be destroyed while performing an action. - * - * @see [#585](https://github.com/cc-tweaked/CC-Tweaked/issues/585) - */ - @GameTest - fun Attack_entity_destroy(helper: GameTestHelper) = helper.sequence { - thenStartComputer { turtle.attack(Optional.empty()) } - thenWaitUntil { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) } - } - - // TODO: Ghost peripherals? - // TODO: Turtle sucking from items -} - -private val LuaTaskContext.turtle get() = getApi() - -private suspend fun LuaTaskContext.getTurtleItemDetail(slot: Int = 1, detailed: Boolean = false): Map { - val item = turtle.getItemDetail(context, Optional.of(slot), Optional.of(detailed)).await() - assertThat("Returns details", item, array(instanceOf(Map::class.java))) - - @Suppress("UNCHECKED_CAST") - return item!![0] as Map -} diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt index 7b53fe454..bb662fe28 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt @@ -2,6 +2,7 @@ package de.srendi.advancedperipherals.test import dan200.computercraft.gametest.api.GameTestHolder import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenComputerOk import de.srendi.advancedperipherals.common.setup.Blocks import net.minecraft.core.BlockPos import net.minecraft.gametest.framework.GameTest @@ -13,9 +14,7 @@ class Peripheral_Test { @GameTest fun Environment(context: GameTestHelper) = context.sequence { val detector = BlockPos(2, 2, 2); - thenExecute { - context.assertBlock(detector, {block -> block.defaultBlockState().`is`(Blocks.ENVIRONMENT_DETECTOR.get())}, "Block is not a environment detector"); - } + thenComputerOk() } } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua deleted file mode 100644 index c7f3a2056..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.echo.lua +++ /dev/null @@ -1,8 +0,0 @@ -os.getComputerID = function() return 1 end -os.computerID = os.getComputerID - -rednet.open("top") -while true do - local id, msg, protocol = rednet.receive() - rednet.send(id, msg, protocol) -end diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua deleted file mode 100644 index 6cc619802..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/craftos_test.sends_basic_rednet_messages.main.lua +++ /dev/null @@ -1,10 +0,0 @@ -rednet.open("top") - -local id, msg -repeat - rednet.send(1, "Test msg") -- Keep sending, as other computer may not have started yet. - - id, msg = rednet.receive(nil, 1) -until id == 1 - -test.eq("Test msg", msg) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua new file mode 100644 index 000000000..4e906969e --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua @@ -0,0 +1,8 @@ +detector = peripheral.find("environmentDetector") +if (detector == nil) then + test.fail("Peripheral not found") +end + + +isRaining = detector.isRaining() +test.eq(true,isRaining) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt deleted file mode 100644 index 9a22ee331..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.computer_peripheral.snbt +++ /dev/null @@ -1,138 +0,0 @@ -{ - DataVersion: 2975, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "computercraft:turtle_advanced{facing:south,waterlogged:false}", nbt: {Fuel: 0, Items: [], On: 0b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_advanced"}}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "computercraft:computer_advanced{facing:north,state:off}", nbt: {On: 0b, id: "computercraft:computer_advanced"}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "computercraft:turtle_advanced{facing:south,waterlogged:false}", - "computercraft:computer_advanced{facing:north,state:off}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt deleted file mode 100644 index 58c570746..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal.snbt +++ /dev/null @@ -1,141 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:lever{face:floor,facing:south,powered:false}"}, - {pos: [2, 1, 1], state: "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}"}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, Label: "computer_test.no_through_signal", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:redstone_wire{east:none,north:side,power:0,south:none,west:none}"}, - {pos: [2, 1, 4], state: "minecraft:redstone_lamp{lit:false}"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:redstone_lamp{lit:false}", - "computercraft:computer_advanced{facing:north,state:blinking}", - "minecraft:air", - "minecraft:lever{face:floor,facing:south,powered:false}", - "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}", - "minecraft:redstone_wire{east:none,north:side,power:0,south:none,west:none}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt deleted file mode 100644 index 592ccefaa..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.no_through_signal_reverse.snbt +++ /dev/null @@ -1,141 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:lever{face:floor,facing:south,powered:false}"}, - {pos: [2, 1, 1], state: "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}"}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:off}", nbt: {ComputerId: 0, Label: "computer_test.no_through_signal_rev", On: 0b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}"}, - {pos: [2, 1, 4], state: "minecraft:redstone_lamp{lit:false}"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:redstone_lamp{lit:false}", - "minecraft:air", - "minecraft:lever{face:floor,facing:south,powered:false}", - "minecraft:repeater{delay:1,facing:north,locked:false,powered:false}", - "minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}", - "computercraft:computer_advanced{facing:north,state:off}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt deleted file mode 100644 index c9dcb29c8..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/computer_test.set_and_destroy.snbt +++ /dev/null @@ -1,138 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:on}", nbt: {ComputerId: 1, Label: "computer_test.set_and_destroy", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:redstone_lamp{lit:false}"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:redstone_lamp{lit:false}", - "minecraft:air", - "computercraft:computer_advanced{facing:north,state:on}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt deleted file mode 100644 index 40c0c4854..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/craftos_test.sends_basic_rednet_messages.snbt +++ /dev/null @@ -1,139 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "computercraft:computer_advanced{facing:north,state:on}", nbt: {ComputerId: 0, Label: "craftos_test.sends_basic_rednet_messages.echo", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, Label: "craftos_test.sends_basic_rednet_messages.main", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "computercraft:wireless_modem_normal{facing:down,on:true,waterlogged:false}", nbt: {id: "computercraft:wireless_modem_normal"}}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "computercraft:wireless_modem_normal{facing:down,on:true,waterlogged:false}", nbt: {id: "computercraft:wireless_modem_normal"}}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "computercraft:computer_advanced{facing:north,state:on}", - "computercraft:computer_advanced{facing:north,state:blinking}", - "computercraft:wireless_modem_normal{facing:down,on:true,waterlogged:false}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/default.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/default.snbt deleted file mode 100644 index 6bbbe27a5..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/default.snbt +++ /dev/null @@ -1,136 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt deleted file mode 100644 index 95da26f01..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.audio_disk.snbt +++ /dev/null @@ -1,40 +0,0 @@ -{ - DataVersion: 2730, - size: [3, 3, 3], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "computercraft:disk_drive{facing:north,state:full}", nbt: {Item: {Count: 1b, id: "minecraft:music_disc_13"}, id: "computercraft:disk_drive"}}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "disk_drive_test.audio_disk", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "computercraft:disk_drive{facing:north,state:full}", - "computercraft:computer_advanced{facing:north,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt deleted file mode 100644 index d3576a9c4..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/disk_drive_test.ejects_disk.snbt +++ /dev/null @@ -1,139 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:white_stained_glass"}, - {pos: [1, 1, 2], state: "minecraft:white_stained_glass"}, - {pos: [1, 1, 3], state: "minecraft:white_stained_glass"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "computercraft:disk_drive{facing:south,state:full}", nbt: {Item: {Count: 1b, id: "minecraft:music_disc_13"}, id: "computercraft:disk_drive"}}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "minecraft:white_stained_glass"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "disk_drive_test.ejects_disk", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [3, 1, 2], state: "minecraft:white_stained_glass"}, - {pos: [3, 1, 3], state: "minecraft:white_stained_glass"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:white_stained_glass"}, - {pos: [1, 2, 2], state: "minecraft:white_stained_glass"}, - {pos: [1, 2, 3], state: "minecraft:white_stained_glass"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:white_stained_glass"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:white_stained_glass"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:white_stained_glass"}, - {pos: [3, 2, 2], state: "minecraft:white_stained_glass"}, - {pos: [3, 2, 3], state: "minecraft:white_stained_glass"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:white_stained_glass", - "minecraft:air", - "computercraft:disk_drive{facing:south,state:full}", - "computercraft:computer_advanced{facing:north,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt deleted file mode 100644 index 63e670a58..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.gains_peripherals.snbt +++ /dev/null @@ -1,145 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "computercraft:printer{bottom:false,facing:north,top:false}", nbt: {Items: [], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}}, - {pos: [0, 1, 1], state: "computercraft:cable{cable:true,down:false,east:true,modem:north_on,north:true,south:false,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 1b, PeripheralId: 1, PeripheralType: "printer", id: "computercraft:cable"}}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", nbt: {Height: 1, Width: 1, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [1, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [1, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [1, 1, 4], state: "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 1b, PeripheralId: 1, PeripheralType: "monitor", id: "computercraft:cable"}}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.gains_peripherals", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [4, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:north_off,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "computercraft:printer{bottom:false,facing:north,top:false}", - "computercraft:cable{cable:true,down:false,east:true,modem:north_on,north:true,south:false,up:false,waterlogged:false,west:false}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", - "computercraft:cable{cable:true,down:false,east:false,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", - "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", - "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", - "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:false}", - "computercraft:computer_advanced{facing:north,state:blinking}", - "computercraft:cable{cable:true,down:false,east:false,modem:north_off,north:true,south:false,up:false,waterlogged:false,west:true}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt deleted file mode 100644 index c16283a27..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.have_peripherals.snbt +++ /dev/null @@ -1,146 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "computercraft:printer{bottom:false,facing:north,top:false}", nbt: {Items: [], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}}, - {pos: [0, 1, 1], state: "computercraft:cable{cable:true,down:false,east:false,modem:north_on,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 1b, PeripheralId: 0, PeripheralType: "printer", id: "computercraft:cable"}}, - {pos: [0, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:false,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", nbt: {Height: 1, Width: 1, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [1, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [1, 1, 4], state: "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 1b, PeripheralId: 0, PeripheralType: "monitor", id: "computercraft:cable"}}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:false,up:false,waterlogged:false,west:true}", nbt: {PeirpheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.have_peripherals", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "computercraft:printer{bottom:false,facing:north,top:false}", - "computercraft:cable{cable:true,down:false,east:false,modem:north_on,north:true,south:true,up:false,waterlogged:false,west:false}", - "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:false,up:false,waterlogged:false,west:false}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:none}", - "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:true,up:false,waterlogged:false,west:true}", - "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", - "computercraft:cable{cable:true,down:false,east:false,modem:west_on,north:true,south:false,up:false,waterlogged:false,west:true}", - "computercraft:cable{cable:true,down:false,east:true,modem:none,north:false,south:false,up:false,waterlogged:false,west:true}", - "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:false,up:false,waterlogged:false,west:true}", - "computercraft:computer_advanced{facing:north,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt deleted file mode 100644 index 79ed20b01..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modem_test.transmits_messages.snbt +++ /dev/null @@ -1,140 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.transmits_messages.receive", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:true,up:false,waterlogged:false,west:false}", nbt: {PeripheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [2, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {PeripheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [2, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:west_off,north:true,south:false,up:false,waterlogged:false,west:true}", nbt: {PeripheralAccess: 0b, id: "computercraft:cable"}}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "modem_test.transmits_messages.send", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "computercraft:computer_advanced{facing:north,state:blinking}", - "computercraft:cable{cable:true,down:false,east:true,modem:east_off,north:false,south:true,up:false,waterlogged:false,west:false}", - "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", - "computercraft:cable{cable:true,down:false,east:false,modem:west_off,north:true,south:false,up:false,waterlogged:false,west:true}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt deleted file mode 100644 index ff0a97bf1..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.ensures_valid_on_place.snbt +++ /dev/null @@ -1,136 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt deleted file mode 100644 index f8c60dc15..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable.snbt +++ /dev/null @@ -1,146 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:white_concrete"}, - {pos: [0, 1, 1], state: "minecraft:shroomlight"}, - {pos: [0, 1, 2], state: "minecraft:white_concrete"}, - {pos: [0, 1, 3], state: "minecraft:white_concrete"}, - {pos: [0, 1, 4], state: "minecraft:white_concrete"}, - {pos: [1, 1, 0], state: "minecraft:white_concrete"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [1, 1, 4], state: "minecraft:white_concrete"}, - {pos: [2, 1, 0], state: "minecraft:white_concrete"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [2, 1, 4], state: "minecraft:white_concrete"}, - {pos: [3, 1, 0], state: "minecraft:white_concrete"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [3, 1, 4], state: "minecraft:white_concrete"}, - {pos: [4, 1, 0], state: "minecraft:white_concrete"}, - {pos: [4, 1, 1], state: "minecraft:shroomlight"}, - {pos: [4, 1, 2], state: "minecraft:white_concrete"}, - {pos: [4, 1, 3], state: "minecraft:white_concrete"}, - {pos: [4, 1, 4], state: "minecraft:white_concrete"}, - {pos: [0, 2, 0], state: "minecraft:white_concrete"}, - {pos: [0, 2, 1], state: "minecraft:white_concrete"}, - {pos: [0, 2, 2], state: "minecraft:white_concrete"}, - {pos: [0, 2, 3], state: "minecraft:white_concrete"}, - {pos: [0, 2, 4], state: "minecraft:white_concrete"}, - {pos: [1, 2, 0], state: "minecraft:white_concrete"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 1, id: "computercraft:monitor_advanced"}}, - {pos: [1, 2, 4], state: "minecraft:white_concrete"}, - {pos: [2, 2, 0], state: "minecraft:white_concrete"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 1, id: "computercraft:monitor_advanced"}}, - {pos: [2, 2, 4], state: "minecraft:white_concrete"}, - {pos: [3, 2, 0], state: "minecraft:white_concrete"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 1, id: "computercraft:monitor_advanced"}}, - {pos: [3, 2, 4], state: "minecraft:white_concrete"}, - {pos: [4, 2, 0], state: "minecraft:white_concrete"}, - {pos: [4, 2, 1], state: "minecraft:white_concrete"}, - {pos: [4, 2, 2], state: "minecraft:white_concrete"}, - {pos: [4, 2, 3], state: "minecraft:white_concrete"}, - {pos: [4, 2, 4], state: "minecraft:white_concrete"}, - {pos: [0, 3, 0], state: "minecraft:white_concrete"}, - {pos: [0, 3, 1], state: "minecraft:white_concrete"}, - {pos: [0, 3, 2], state: "minecraft:white_concrete"}, - {pos: [0, 3, 3], state: "minecraft:white_concrete"}, - {pos: [0, 3, 4], state: "minecraft:white_concrete"}, - {pos: [1, 3, 0], state: "minecraft:white_concrete"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:white_concrete"}, - {pos: [2, 3, 0], state: "minecraft:white_concrete"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:white_concrete"}, - {pos: [3, 3, 0], state: "minecraft:white_concrete"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:white_concrete"}, - {pos: [4, 3, 0], state: "minecraft:white_concrete"}, - {pos: [4, 3, 1], state: "minecraft:white_concrete"}, - {pos: [4, 3, 2], state: "minecraft:white_concrete"}, - {pos: [4, 3, 3], state: "minecraft:white_concrete"}, - {pos: [4, 3, 4], state: "minecraft:white_concrete"}, - {pos: [0, 4, 0], state: "minecraft:white_concrete"}, - {pos: [0, 4, 1], state: "minecraft:white_concrete"}, - {pos: [0, 4, 2], state: "minecraft:white_concrete"}, - {pos: [0, 4, 3], state: "minecraft:white_concrete"}, - {pos: [0, 4, 4], state: "minecraft:white_concrete"}, - {pos: [1, 4, 0], state: "minecraft:white_concrete"}, - {pos: [1, 4, 1], state: "minecraft:white_concrete"}, - {pos: [1, 4, 2], state: "minecraft:white_concrete"}, - {pos: [1, 4, 3], state: "minecraft:shroomlight"}, - {pos: [1, 4, 4], state: "minecraft:white_concrete"}, - {pos: [2, 4, 0], state: "minecraft:white_concrete"}, - {pos: [2, 4, 1], state: "minecraft:white_concrete"}, - {pos: [2, 4, 2], state: "minecraft:white_concrete"}, - {pos: [2, 4, 3], state: "minecraft:white_concrete"}, - {pos: [2, 4, 4], state: "minecraft:white_concrete"}, - {pos: [3, 4, 0], state: "minecraft:white_concrete"}, - {pos: [3, 4, 1], state: "minecraft:white_concrete"}, - {pos: [3, 4, 2], state: "minecraft:white_concrete"}, - {pos: [3, 4, 3], state: "minecraft:shroomlight"}, - {pos: [3, 4, 4], state: "minecraft:white_concrete"}, - {pos: [4, 4, 0], state: "minecraft:white_concrete"}, - {pos: [4, 4, 1], state: "minecraft:white_concrete"}, - {pos: [4, 4, 2], state: "minecraft:white_concrete"}, - {pos: [4, 4, 3], state: "minecraft:white_concrete"}, - {pos: [4, 4, 4], state: "minecraft:white_concrete"} - ], - entities: [ - {blockPos: [2, 1, 1], pos: [2.392713937302208d, 1.0d, 1.300000011920929d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.699999988079071d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanUpdate: 1b, CustomName: '{"text":"monitor_test.looks_acceptable"}', DeathTime: 0s, DisabledSlots: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invisible: 1b, Invulnerable: 0b, Marker: 1b, Motion: [0.0d, 0.0d, 0.0d], NoBasePlate: 0b, OnGround: 0b, PortalCooldown: 0, Pos: [21.392713937302208d, 6.0d, 35.30000001192093d], Pose: {}, Rotation: [0.15043798f, 15.347454f], ShowArms: 0b, Small: 0b, UUID: [I; 474729512, 2108312608, -1494837479, 630038770], id: "minecraft:armor_stand"}} - ], - palette: [ - "minecraft:polished_andesite", - "minecraft:white_concrete", - "minecraft:shroomlight", - "minecraft:air", - "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt deleted file mode 100644 index 1bbce9d32..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/monitor_test.looks_acceptable_dark.snbt +++ /dev/null @@ -1,145 +0,0 @@ -{ - DataVersion: 2730, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:white_concrete"}, - {pos: [0, 1, 1], state: "minecraft:white_concrete"}, - {pos: [0, 1, 2], state: "minecraft:white_concrete"}, - {pos: [0, 1, 3], state: "minecraft:white_concrete"}, - {pos: [0, 1, 4], state: "minecraft:white_concrete"}, - {pos: [1, 1, 0], state: "minecraft:white_concrete"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [1, 1, 4], state: "minecraft:white_concrete"}, - {pos: [2, 1, 0], state: "minecraft:white_concrete"}, - {pos: [2, 1, 1], state: "minecraft:air"}, - {pos: [2, 1, 2], state: "minecraft:air"}, - {pos: [2, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [2, 1, 4], state: "minecraft:white_concrete"}, - {pos: [3, 1, 0], state: "minecraft:white_concrete"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}}, - {pos: [3, 1, 4], state: "minecraft:white_concrete"}, - {pos: [4, 1, 0], state: "minecraft:white_concrete"}, - {pos: [4, 1, 1], state: "minecraft:white_concrete"}, - {pos: [4, 1, 2], state: "minecraft:white_concrete"}, - {pos: [4, 1, 3], state: "minecraft:white_concrete"}, - {pos: [4, 1, 4], state: "minecraft:white_concrete"}, - {pos: [0, 2, 0], state: "minecraft:white_concrete"}, - {pos: [0, 2, 1], state: "minecraft:white_concrete"}, - {pos: [0, 2, 2], state: "minecraft:white_concrete"}, - {pos: [0, 2, 3], state: "minecraft:white_concrete"}, - {pos: [0, 2, 4], state: "minecraft:white_concrete"}, - {pos: [1, 2, 0], state: "minecraft:white_concrete"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", nbt: {Height: 2, Width: 3, XIndex: 2, YIndex: 1, id: "computercraft:monitor_advanced"}}, - {pos: [1, 2, 4], state: "minecraft:white_concrete"}, - {pos: [2, 2, 0], state: "minecraft:white_concrete"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", nbt: {Height: 2, Width: 3, XIndex: 1, YIndex: 1, id: "computercraft:monitor_advanced"}}, - {pos: [2, 2, 4], state: "minecraft:white_concrete"}, - {pos: [3, 2, 0], state: "minecraft:white_concrete"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}", nbt: {Height: 2, Width: 3, XIndex: 0, YIndex: 1, id: "computercraft:monitor_advanced"}}, - {pos: [3, 2, 4], state: "minecraft:white_concrete"}, - {pos: [4, 2, 0], state: "minecraft:white_concrete"}, - {pos: [4, 2, 1], state: "minecraft:white_concrete"}, - {pos: [4, 2, 2], state: "minecraft:white_concrete"}, - {pos: [4, 2, 3], state: "minecraft:white_concrete"}, - {pos: [4, 2, 4], state: "minecraft:white_concrete"}, - {pos: [0, 3, 0], state: "minecraft:white_concrete"}, - {pos: [0, 3, 1], state: "minecraft:white_concrete"}, - {pos: [0, 3, 2], state: "minecraft:white_concrete"}, - {pos: [0, 3, 3], state: "minecraft:white_concrete"}, - {pos: [0, 3, 4], state: "minecraft:white_concrete"}, - {pos: [1, 3, 0], state: "minecraft:white_concrete"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:white_concrete"}, - {pos: [2, 3, 0], state: "minecraft:white_concrete"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:white_concrete"}, - {pos: [3, 3, 0], state: "minecraft:white_concrete"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:white_concrete"}, - {pos: [4, 3, 0], state: "minecraft:white_concrete"}, - {pos: [4, 3, 1], state: "minecraft:white_concrete"}, - {pos: [4, 3, 2], state: "minecraft:white_concrete"}, - {pos: [4, 3, 3], state: "minecraft:white_concrete"}, - {pos: [4, 3, 4], state: "minecraft:white_concrete"}, - {pos: [0, 4, 0], state: "minecraft:white_concrete"}, - {pos: [0, 4, 1], state: "minecraft:white_concrete"}, - {pos: [0, 4, 2], state: "minecraft:white_concrete"}, - {pos: [0, 4, 3], state: "minecraft:white_concrete"}, - {pos: [0, 4, 4], state: "minecraft:white_concrete"}, - {pos: [1, 4, 0], state: "minecraft:white_concrete"}, - {pos: [1, 4, 1], state: "minecraft:white_concrete"}, - {pos: [1, 4, 2], state: "minecraft:white_concrete"}, - {pos: [1, 4, 3], state: "minecraft:white_concrete"}, - {pos: [1, 4, 4], state: "minecraft:white_concrete"}, - {pos: [2, 4, 0], state: "minecraft:white_concrete"}, - {pos: [2, 4, 1], state: "minecraft:white_concrete"}, - {pos: [2, 4, 2], state: "minecraft:white_concrete"}, - {pos: [2, 4, 3], state: "minecraft:white_concrete"}, - {pos: [2, 4, 4], state: "minecraft:white_concrete"}, - {pos: [3, 4, 0], state: "minecraft:white_concrete"}, - {pos: [3, 4, 1], state: "minecraft:white_concrete"}, - {pos: [3, 4, 2], state: "minecraft:white_concrete"}, - {pos: [3, 4, 3], state: "minecraft:white_concrete"}, - {pos: [3, 4, 4], state: "minecraft:white_concrete"}, - {pos: [4, 4, 0], state: "minecraft:white_concrete"}, - {pos: [4, 4, 1], state: "minecraft:white_concrete"}, - {pos: [4, 4, 2], state: "minecraft:white_concrete"}, - {pos: [4, 4, 3], state: "minecraft:white_concrete"}, - {pos: [4, 4, 4], state: "minecraft:white_concrete"} - ], - entities: [ - {blockPos: [2, 1, 1], pos: [2.3927139373022044d, 1.0d, 1.300000011920929d], nbt: {AbsorptionAmount: 0.0f, Air: 300s, ArmorItems: [{}, {}, {}, {}], Attributes: [{Base: 0.699999988079071d, Name: "minecraft:generic.movement_speed"}], Brain: {memories: {}}, CanUpdate: 1b, CustomName: '{"text":"monitor_test.looks_acceptable_dark"}', DeathTime: 0s, DisabledSlots: 0, FallDistance: 0.0f, FallFlying: 0b, Fire: -1s, HandItems: [{}, {}], Health: 20.0f, HurtByTimestamp: 0, HurtTime: 0s, Invisible: 1b, Invulnerable: 0b, Marker: 1b, Motion: [0.0d, 0.0d, 0.0d], NoBasePlate: 0b, OnGround: 0b, PortalCooldown: 0, Pos: [64.3927139373022d, 6.0d, 59.30000001192093d], Pose: {}, Rotation: [0.15043798f, 15.347454f], ShowArms: 0b, Small: 0b, UUID: [I; -1516632699, -1770765897, -1362337958, -475677268], id: "minecraft:armor_stand"}} - ], - palette: [ - "minecraft:polished_andesite", - "minecraft:white_concrete", - "minecraft:air", - "computercraft:monitor_advanced{facing:north,orientation:north,state:lu}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:lru}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:ru}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:ld}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:lrd}", - "computercraft:monitor_advanced{facing:north,orientation:north,state:rd}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.nbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.nbt deleted file mode 100644 index cf4ecf423af054fd99326f3b57280e4eb0d83c81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 691 zcmb2|=3oGW|GhUh=3jOYIsUQy{az9E)~QRGdwe=}W^)IrviRt5xK96ZYtF12(`sKf z9QogO_u1B^S?}v6F48!8{ds?JmGd5jS(Eub`U@z{nrB>nZY7s*mu6ezvg335!fuz< z+UguLuYax*YkkAX0mw$9bg<` zWPRWbgE4a&8`Ng813EC9A+815e14X=%2};Yli#nx6TQ`AUnFnm+ Date: Sun, 5 May 2024 22:35:34 +0200 Subject: [PATCH 13/61] Add game test action --- .github/workflows/build-and-test.yaml | 4 +++- .../computer/tests/peripheral_test.environment.lua | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index f3c7b7f7e..62d0cd328 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -10,4 +10,6 @@ on: jobs: build-and-test: - uses: IntelligenceModding/actions/.github/workflows/build-and-test.yaml@master \ No newline at end of file + uses: IntelligenceModding/actions/.github/workflows/build-and-test.yaml@master + run-gametests: + uses: IntelligenceModding/actions/.github/workflows/run-gametests.yaml@master \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua index 4e906969e..38fbb766e 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua @@ -3,6 +3,5 @@ if (detector == nil) then test.fail("Peripheral not found") end - isRaining = detector.isRaining() -test.eq(true,isRaining) +test.eq(false,isRaining, "It should not rain") From 3c6c9f1c732df2ecd81b9a5886a2ff6c9d201d80 Mon Sep 17 00:00:00 2001 From: Srendi Date: Sun, 5 May 2024 23:07:31 +0200 Subject: [PATCH 14/61] Satisfy checkstyle --- config/checkstyle/checkstyle.xml | 6 +- .../test/core/ArbitraryByteBuffer.java | 180 ++++++++---------- .../test/core/ByteBufferMatcher.java | 57 +++--- .../computercraft/test/core/CallCounter.java | 19 +- .../test/core/ContramapMatcher.java | 25 +-- .../test/core/CustomMatchers.java | 8 +- .../test/core/apis/BasicApiEnvironment.java | 80 +++----- .../test/core/computer/BasicEnvironment.java | 155 ++++++--------- .../test/core/filesystem/MemoryMount.java | 118 +++++------- .../test/core/terminal/TerminalMatchers.java | 39 ++-- .../core/computer/KotlinComputerManager.kt | 3 +- .../dan200/computercraft/export/Exporter.java | 130 ++++++------- .../computercraft/export/ImageRenderer.java | 42 ++-- .../dan200/computercraft/export/JsonDump.java | 49 +++-- .../gametest/api/ComputerState.java | 20 +- .../gametest/api/GameTestHolder.java | 7 +- .../gametest/core/CCTestCommand.java | 133 ++++++------- .../gametest/core/ClientHooks.java | 66 ++----- .../computercraft/gametest/core/Copier.java | 43 ++--- .../computercraft/gametest/core/TestAPI.java | 61 +++--- .../gametest/core/TestHooks.java | 37 ++-- .../gametest/GameTestHelperAccessor.java | 5 +- .../mixin/gametest/GameTestInfoAccessor.java | 7 +- .../gametest/GameTestSequenceAccessor.java | 5 +- .../mixin/gametest/GameTestSequenceMixin.java | 36 ++-- .../mixin/gametest/TestCommandAccessor.java | 8 +- .../gametest/api/TestExtensions.kt | 19 +- .../gametest/core/ManagedComputers.kt | 10 +- .../test/Peripheral_Test.kt | 1 - 29 files changed, 576 insertions(+), 793 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 7ca06cbc2..f1323c000 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -22,7 +22,7 @@ - + @@ -93,12 +93,12 @@ - - + + diff --git a/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java b/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java index ea5585e3b..8efdc74c1 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/ArbitraryByteBuffer.java @@ -5,7 +5,13 @@ */ package dan200.computercraft.test.core; -import net.jqwik.api.*; +import net.jqwik.api.Arbitraries; +import net.jqwik.api.Arbitrary; +import net.jqwik.api.EdgeCases; +import net.jqwik.api.RandomDistribution; +import net.jqwik.api.RandomGenerator; +import net.jqwik.api.Shrinkable; +import net.jqwik.api.ShrinkingDistance; import net.jqwik.api.arbitraries.SizableArbitrary; import javax.annotation.Nonnull; @@ -26,171 +32,143 @@ * This is more efficient than using {@link Arbitraries#bytes()} and {@link Arbitrary#array(Class)}, as it does not * try to shrink the contents, only the size. */ -public final class ArbitraryByteBuffer implements SizableArbitrary -{ - private static final ArbitraryByteBuffer DEFAULT = new ArbitraryByteBuffer( 0, null, null ); - - private int minSize = 0; +public final class ArbitraryByteBuffer implements SizableArbitrary { + private static final ArbitraryByteBuffer DEFAULT = new ArbitraryByteBuffer(0, null, null); private final @Nullable Integer maxSize; private final @Nullable RandomDistribution distribution; + private int minSize = 0; - private ArbitraryByteBuffer( int minSize, @Nullable Integer maxSize, @Nullable RandomDistribution distribution ) - { + private ArbitraryByteBuffer(int minSize, @Nullable Integer maxSize, @Nullable RandomDistribution distribution) { this.minSize = minSize; this.maxSize = maxSize; this.distribution = distribution; } - public static ArbitraryByteBuffer bytes() - { + public static ArbitraryByteBuffer bytes() { return DEFAULT; } + private static ToIntFunction sizeGeneratorWithCutoff(int minSize, int maxSize, int genSize) { + // If we've a large range, we either pick between generating small (<10) or large lists. + int range = maxSize - minSize; + int offset = (int) Math.max(Math.round(Math.sqrt(genSize)), 10); + int cutoff = range <= offset ? maxSize : Math.min(offset + minSize, maxSize); + + if (cutoff >= maxSize) return random -> nextInt(random, minSize, maxSize); + + // Choose size below cutoff with probability of 0.1. + double maxSizeProbability = Math.min(0.02, 1.0 / (genSize / 10.0)); + double cutoffProbability = 0.1; + return random -> { + if (random.nextDouble() <= maxSizeProbability) { + return maxSize; + } else if (random.nextDouble() <= cutoffProbability + maxSizeProbability) { + return nextInt(random, cutoff + 1, maxSize); + } else { + return nextInt(random, minSize, cutoff); + } + }; + } + + private static int nextInt(Random random, int minSize, int maxSize) { + return random.nextInt(maxSize - minSize + 1) + minSize; + } + + private static ByteBuffer allocateRandom(int size, Random random) { + ByteBuffer buffer = ByteBuffer.allocate(size); + + for (int i = 0; i < size; i++) buffer.put(i, (byte) random.nextInt()); + return buffer.asReadOnlyBuffer(); + } + @Nonnull @Override - public SizableArbitrary ofMinSize( int minSize ) - { - return new ArbitraryByteBuffer( minSize, maxSize, distribution ); + public SizableArbitrary ofMinSize(int minSize) { + return new ArbitraryByteBuffer(minSize, maxSize, distribution); } @Nonnull @Override - public SizableArbitrary ofMaxSize( int maxSize ) - { - return new ArbitraryByteBuffer( minSize, maxSize, distribution ); + public SizableArbitrary ofMaxSize(int maxSize) { + return new ArbitraryByteBuffer(minSize, maxSize, distribution); } @Nonnull @Override - public SizableArbitrary withSizeDistribution( @Nonnull RandomDistribution distribution ) - { - return new ArbitraryByteBuffer( minSize, maxSize, distribution ); + public SizableArbitrary withSizeDistribution(@Nonnull RandomDistribution distribution) { + return new ArbitraryByteBuffer(minSize, maxSize, distribution); } @Nonnull @Override - public RandomGenerator generator( int genSize ) - { - BigInteger min = BigInteger.valueOf( minSize ); + public RandomGenerator generator(int genSize) { + BigInteger min = BigInteger.valueOf(minSize); ToIntFunction generator; - if( distribution == null ) - { - generator = sizeGeneratorWithCutoff( minSize, getMaxSize(), genSize ); - } - else - { - RandomDistribution.RandomNumericGenerator gen = distribution.createGenerator( genSize, min, BigInteger.valueOf( getMaxSize() ), min ); - generator = r -> gen.next( r ).intValueExact(); + if (distribution == null) { + generator = sizeGeneratorWithCutoff(minSize, getMaxSize(), genSize); + } else { + RandomDistribution.RandomNumericGenerator gen = distribution.createGenerator(genSize, min, BigInteger.valueOf(getMaxSize()), min); + generator = r -> gen.next(r).intValueExact(); } return r -> { - int size = generator.applyAsInt( r ); - return new ShrinkableBuffer( allocateRandom( size, r ), minSize ); + int size = generator.applyAsInt(r); + return new ShrinkableBuffer(allocateRandom(size, r), minSize); }; } @Nonnull @Override - public EdgeCases edgeCases( int maxEdgeCases ) - { - return EdgeCases.fromSuppliers( Arrays.asList( - () -> new ShrinkableBuffer( allocateRandom( minSize, new Random() ), minSize ), - () -> new ShrinkableBuffer( allocateRandom( getMaxSize(), new Random() ), minSize ) - ) ); - } - - private int getMaxSize() - { - return maxSize == null ? Math.max( minSize * 2, 255 ) : maxSize; + public EdgeCases edgeCases(int maxEdgeCases) { + return EdgeCases.fromSuppliers(Arrays.asList( + () -> new ShrinkableBuffer(allocateRandom(minSize, new Random()), minSize), + () -> new ShrinkableBuffer(allocateRandom(getMaxSize(), new Random()), minSize) + )); } - private static ToIntFunction sizeGeneratorWithCutoff( int minSize, int maxSize, int genSize ) - { - // If we've a large range, we either pick between generating small (<10) or large lists. - int range = maxSize - minSize; - int offset = (int) Math.max( Math.round( Math.sqrt( genSize ) ), 10 ); - int cutoff = range <= offset ? maxSize : Math.min( offset + minSize, maxSize ); - - if( cutoff >= maxSize ) return random -> nextInt( random, minSize, maxSize ); - - // Choose size below cutoff with probability of 0.1. - double maxSizeProbability = Math.min( 0.02, 1.0 / (genSize / 10.0) ); - double cutoffProbability = 0.1; - return random -> { - if( random.nextDouble() <= maxSizeProbability ) - { - return maxSize; - } - else if( random.nextDouble() <= cutoffProbability + maxSizeProbability ) - { - return nextInt( random, cutoff + 1, maxSize ); - } - else - { - return nextInt( random, minSize, cutoff ); - } - }; - } - - private static int nextInt( Random random, int minSize, int maxSize ) - { - return random.nextInt( maxSize - minSize + 1 ) + minSize; - } - - private static ByteBuffer allocateRandom( int size, Random random ) - { - ByteBuffer buffer = ByteBuffer.allocate( size ); - - for( int i = 0; i < size; i++ ) buffer.put( i, (byte) random.nextInt() ); - return buffer.asReadOnlyBuffer(); + private int getMaxSize() { + return maxSize == null ? Math.max(minSize * 2, 255) : maxSize; } - private static final class ShrinkableBuffer implements Shrinkable - { + private static final class ShrinkableBuffer implements Shrinkable { private final ByteBuffer value; private final int minSize; - private ShrinkableBuffer( ByteBuffer value, int minSize ) - { + private ShrinkableBuffer(ByteBuffer value, int minSize) { this.value = value; this.minSize = minSize; } @Nonnull @Override - public ByteBuffer value() - { + public ByteBuffer value() { return value; } @Nonnull @Override - public Stream> shrink() - { - return StreamSupport.stream( new Spliterators.AbstractSpliterator>( 3, 0 ) - { + public Stream> shrink() { + return StreamSupport.stream(new Spliterators.AbstractSpliterator>(3, 0) { int size = value.remaining(); @Override - public boolean tryAdvance( Consumer> action ) - { - if( size <= minSize ) return false; + public boolean tryAdvance(Consumer> action) { + if (size <= minSize) return false; int half = (size / 2) - (minSize / 2); size = half == 0 ? minSize : size - half; ByteBuffer slice = value.duplicate(); - slice.limit( size ); - action.accept( new ShrinkableBuffer( slice.slice(), minSize ) ); + slice.limit(size); + action.accept(new ShrinkableBuffer(slice.slice(), minSize)); return true; } - }, false ); + }, false); } @Nonnull @Override - public ShrinkingDistance distance() - { - return ShrinkingDistance.of( value.remaining() - minSize ); + public ShrinkingDistance distance() { + return ShrinkingDistance.of(value.remaining() - minSize); } } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java b/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java index c0f801b4c..46e27235b 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/ByteBufferMatcher.java @@ -11,65 +11,58 @@ import java.nio.ByteBuffer; -public final class ByteBufferMatcher extends TypeSafeMatcher -{ +public final class ByteBufferMatcher extends TypeSafeMatcher { private final ByteBuffer expected; - private ByteBufferMatcher( ByteBuffer expected ) - { + private ByteBufferMatcher(ByteBuffer expected) { this.expected = expected; } + public static Matcher bufferEqual(ByteBuffer buffer) { + return new ByteBufferMatcher(buffer); + } + @Override - protected boolean matchesSafely( ByteBuffer actual ) - { - return expected.equals( actual ); + protected boolean matchesSafely(ByteBuffer actual) { + return expected.equals(actual); } @Override - public void describeTo( Description description ) - { - description.appendValue( expected ); + public void describeTo(Description description) { + description.appendValue(expected); } @Override - protected void describeMismatchSafely( ByteBuffer actual, Description mismatchDescription ) - { - if( expected.remaining() != actual.remaining() ) - { + protected void describeMismatchSafely(ByteBuffer actual, Description mismatchDescription) { + if (expected.remaining() != actual.remaining()) { mismatchDescription - .appendValue( actual ).appendText( " has " ).appendValue( actual.remaining() ).appendText( " bytes remaining" ); + .appendValue(actual).appendText(" has ").appendValue(actual.remaining()).appendText(" bytes remaining"); return; } int remaining = expected.remaining(); int expectedPos = expected.position(); int actualPos = actual.position(); - for( int i = 0; i < remaining; i++ ) - { - if( expected.get( expectedPos + i ) == actual.get( actualPos + i ) ) continue; + for (int i = 0; i < remaining; i++) { + if (expected.get(expectedPos + i) == actual.get(actualPos + i)) + continue; - int offset = Math.max( i - 5, 0 ); - int length = Math.min( i + 5, remaining - 1 ) - offset + 1; + int offset = Math.max(i - 5, 0); + int length = Math.min(i + 5, remaining - 1) - offset + 1; byte[] expectedBytes = new byte[length]; - expected.duplicate().position( expectedPos + offset ); - expected.get( expectedBytes ); + expected.duplicate().position(expectedPos + offset); + expected.get(expectedBytes); byte[] actualBytes = new byte[length]; - actual.duplicate().position( actualPos + offset ); - actual.get( actualBytes ); + actual.duplicate().position(actualPos + offset); + actual.get(actualBytes); mismatchDescription - .appendText( "failed at " ).appendValue( i ).appendText( System.lineSeparator() ) - .appendText( "expected " ).appendValue( expectedBytes ).appendText( System.lineSeparator() ) - .appendText( "was " ).appendValue( actual ); + .appendText("failed at ").appendValue(i).appendText(System.lineSeparator()) + .appendText("expected ").appendValue(expectedBytes).appendText(System.lineSeparator()) + .appendText("was ").appendValue(actual); return; } } - - public static Matcher bufferEqual( ByteBuffer buffer ) - { - return new ByteBufferMatcher( buffer ); - } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java b/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java index 5916f865b..e828eba6d 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/CallCounter.java @@ -7,28 +7,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class CallCounter implements Runnable -{ +public class CallCounter implements Runnable { private int timesCalled = 0; @Override - public void run() - { + public void run() { timesCalled++; } - public void assertCalledTimes( int expectedTimesCalled ) - { - assertEquals( expectedTimesCalled, timesCalled, "Callback was not called the correct number of times" ); + public void assertCalledTimes(int expectedTimesCalled) { + assertEquals(expectedTimesCalled, timesCalled, "Callback was not called the correct number of times"); } - public void assertNotCalled() - { - assertEquals( 0, timesCalled, "Should never have been called." ); + public void assertNotCalled() { + assertEquals(0, timesCalled, "Should never have been called."); } - public void reset() - { + public void reset() { this.timesCalled = 0; } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java b/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java index 4a982d558..50bc7fd4e 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/ContramapMatcher.java @@ -17,29 +17,24 @@ * @param The type of the object to be matched. * @param The type of the projection/field to be matched. */ -public final class ContramapMatcher extends FeatureMatcher -{ +public final class ContramapMatcher extends FeatureMatcher { private final Function convert; - public ContramapMatcher( String desc, Function convert, Matcher matcher ) - { - super( matcher, desc, desc ); + public ContramapMatcher(String desc, Function convert, Matcher matcher) { + super(matcher, desc, desc); this.convert = convert; } - @Override - protected U featureValueOf( T actual ) - { - return convert.apply( actual ); + public static Matcher contramap(Matcher matcher, String desc, Function convert) { + return new ContramapMatcher<>(desc, convert, matcher); } - public static Matcher contramap( Matcher matcher, String desc, Function convert ) - { - return new ContramapMatcher<>( desc, convert, matcher ); + public static Matcher contramap(Matcher matcher, Function convert) { + return new ContramapMatcher<>("-f(_)->", convert, matcher); } - public static Matcher contramap( Matcher matcher, Function convert ) - { - return new ContramapMatcher<>( "-f(_)->", convert, matcher ); + @Override + protected U featureValueOf(T actual) { + return convert.apply(actual); } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java b/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java index e321ff855..ced9d73ac 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/CustomMatchers.java @@ -12,8 +12,7 @@ import static org.hamcrest.Matchers.contains; -public class CustomMatchers -{ +public class CustomMatchers { /** * Assert two lists are equal according to some matcher. *

@@ -24,8 +23,7 @@ public class CustomMatchers * @param The type to compare against. * @return A matcher which compares against a list of items. */ - public static Matcher> containsWith( List items, Function> matcher ) - { - return contains( items.stream().map( matcher ).toList() ); + public static Matcher> containsWith(List items, Function> matcher) { + return contains(items.stream().map(matcher).toList()); } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java b/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java index 28ecb964d..349cb83ad 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java @@ -19,143 +19,119 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -public abstract class BasicApiEnvironment implements IAPIEnvironment -{ +public abstract class BasicApiEnvironment implements IAPIEnvironment { private final BasicEnvironment environment; private @Nullable String label; - public BasicApiEnvironment( BasicEnvironment environment ) - { + public BasicApiEnvironment(BasicEnvironment environment) { this.environment = environment; } @Override - public int getComputerID() - { + public int getComputerID() { return 0; } @Nonnull @Override - public ComputerEnvironment getComputerEnvironment() - { + public ComputerEnvironment getComputerEnvironment() { return environment; } @Nonnull @Override - public GlobalEnvironment getGlobalEnvironment() - { + public GlobalEnvironment getGlobalEnvironment() { return environment; } @Nonnull @Override - public IWorkMonitor getMainThreadMonitor() - { - throw new IllegalStateException( "Main thread monitor not available" ); + public IWorkMonitor getMainThreadMonitor() { + throw new IllegalStateException("Main thread monitor not available"); } @Nonnull @Override - public Terminal getTerminal() - { - throw new IllegalStateException( "Terminal not available" ); + public Terminal getTerminal() { + throw new IllegalStateException("Terminal not available"); } @Override - public FileSystem getFileSystem() - { - throw new IllegalStateException( "Filesystem not available" ); + public FileSystem getFileSystem() { + throw new IllegalStateException("Filesystem not available"); } @Override - public void shutdown() - { + public void shutdown() { } @Override - public void reboot() - { + public void reboot() { } @Override - public void setOutput( ComputerSide side, int output ) - { + public void setOutput(ComputerSide side, int output) { } @Override - public int getOutput( ComputerSide side ) - { + public int getOutput(ComputerSide side) { return 0; } @Override - public int getInput( ComputerSide side ) - { + public int getInput(ComputerSide side) { return 0; } @Override - public void setBundledOutput( ComputerSide side, int output ) - { + public void setBundledOutput(ComputerSide side, int output) { } @Override - public int getBundledOutput( ComputerSide side ) - { + public int getBundledOutput(ComputerSide side) { return 0; } @Override - public int getBundledInput( ComputerSide side ) - { + public int getBundledInput(ComputerSide side) { return 0; } @Override - public void setPeripheralChangeListener( @Nullable IPeripheralChangeListener listener ) - { + public void setPeripheralChangeListener(@Nullable IPeripheralChangeListener listener) { } @Nullable @Override - public IPeripheral getPeripheral( ComputerSide side ) - { + public IPeripheral getPeripheral(ComputerSide side) { return null; } @Nullable @Override - public String getLabel() - { + public String getLabel() { return label; } @Override - public void setLabel( @Nullable String label ) - { + public void setLabel(@Nullable String label) { this.label = label; } @Override - public int startTimer( long ticks ) - { - throw new IllegalStateException( "Cannot start timers" ); + public int startTimer(long ticks) { + throw new IllegalStateException("Cannot start timers"); } @Override - public void cancelTimer( int id ) - { + public void cancelTimer(int id) { } @Override - public void observe( @Nonnull Metric.Event summary, long value ) - { + public void observe(@Nonnull Metric.Event summary, long value) { } @Override - public void observe( @Nonnull Metric.Counter counter ) - { + public void observe(@Nonnull Metric.Counter counter) { } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java b/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java index 8d48343a9..f763238eb 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/computer/BasicEnvironment.java @@ -29,140 +29,111 @@ * A basic implementation of {@link ComputerEnvironment} and {@link GlobalEnvironment}, suitable for a context which * will only run a single computer. */ -public class BasicEnvironment implements ComputerEnvironment, GlobalEnvironment, MetricsObserver -{ +public class BasicEnvironment implements ComputerEnvironment, GlobalEnvironment, MetricsObserver { private final IWritableMount mount; - public BasicEnvironment() - { - this( new MemoryMount() ); + public BasicEnvironment() { + this(new MemoryMount()); } - public BasicEnvironment( IWritableMount mount ) - { + public BasicEnvironment(IWritableMount mount) { this.mount = mount; } + public static IMount createMount(Class klass, String path, String fallback) { + File file = getContainingFile(klass); + + if (file.isFile()) { + try { + return new JarMount(file, path); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } else { + File wholeFile = new File(file, path); + + // If we don't exist, walk up the tree looking for resource folders + File baseFile = file; + while (baseFile != null && !wholeFile.exists()) { + baseFile = baseFile.getParentFile(); + wholeFile = new File(baseFile, "src/" + fallback + "/resources/" + path); + } + + if (!wholeFile.exists()) throw new IllegalStateException("Cannot find ROM mount at " + file); + + return new FileMount(wholeFile, 0); + } + } + + private static File getContainingFile(Class klass) { + String path = klass.getProtectionDomain().getCodeSource().getLocation().getPath(); + int bangIndex = path.indexOf("!"); + + // Plain old file, so step up from dan200.computercraft. + if (bangIndex < 0) return new File(path); + + path = path.substring(0, bangIndex); + URL url; + try { + url = new URL(path); + } catch (MalformedURLException e) { + throw new IllegalStateException(e); + } + + try { + return new File(url.toURI()); + } catch (URISyntaxException e) { + return new File(url.getPath()); + } + } + @Override - public IWritableMount createRootMount() - { + public IWritableMount createRootMount() { return mount; } @Override - public int getDay() - { + public int getDay() { return 0; } @Override - public double getTimeOfDay() - { + public double getTimeOfDay() { return 0; } @Override - public MetricsObserver getMetrics() - { + public MetricsObserver getMetrics() { return this; } @Nonnull @Override - public String getHostString() - { + public String getHostString() { return "ComputerCraft 1.0 (Test environment)"; } @Nonnull @Override - public String getUserAgent() - { + public String getUserAgent() { return "ComputerCraft/1.0"; } @Override - public IMount createResourceMount( String domain, String subPath ) - { - return createMount( ComputerCraft.class, "data/" + domain + "/" + subPath, "main" ); + public IMount createResourceMount(String domain, String subPath) { + return createMount(ComputerCraft.class, "data/" + domain + "/" + subPath, "main"); } @Override - public InputStream createResourceFile( String domain, String subPath ) - { - return ComputerCraft.class.getClassLoader().getResourceAsStream( "data/" + domain + "/" + subPath ); - } - - public static IMount createMount( Class klass, String path, String fallback ) - { - File file = getContainingFile( klass ); - - if( file.isFile() ) - { - try - { - return new JarMount( file, path ); - } - catch( IOException e ) - { - throw new UncheckedIOException( e ); - } - } - else - { - File wholeFile = new File( file, path ); - - // If we don't exist, walk up the tree looking for resource folders - File baseFile = file; - while( baseFile != null && !wholeFile.exists() ) - { - baseFile = baseFile.getParentFile(); - wholeFile = new File( baseFile, "src/" + fallback + "/resources/" + path ); - } - - if( !wholeFile.exists() ) throw new IllegalStateException( "Cannot find ROM mount at " + file ); - - return new FileMount( wholeFile, 0 ); - } - } - - - private static File getContainingFile( Class klass ) - { - String path = klass.getProtectionDomain().getCodeSource().getLocation().getPath(); - int bangIndex = path.indexOf( "!" ); - - // Plain old file, so step up from dan200.computercraft. - if( bangIndex < 0 ) return new File( path ); - - path = path.substring( 0, bangIndex ); - URL url; - try - { - url = new URL( path ); - } - catch( MalformedURLException e ) - { - throw new IllegalStateException( e ); - } - - try - { - return new File( url.toURI() ); - } - catch( URISyntaxException e ) - { - return new File( url.getPath() ); - } + public InputStream createResourceFile(String domain, String subPath) { + return ComputerCraft.class.getClassLoader().getResourceAsStream("data/" + domain + "/" + subPath); } @Override - public void observe( Metric.Counter counter ) - { + public void observe(Metric.Counter counter) { } @Override - public void observe( Metric.Event event, long value ) - { + public void observe(Metric.Event event, long value) { } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java b/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java index 8219d75db..29863cf5e 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/filesystem/MemoryMount.java @@ -15,134 +15,116 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * In-memory file mounts. */ -public class MemoryMount implements IWritableMount -{ +public class MemoryMount implements IWritableMount { private final Map files = new HashMap<>(); private final Set directories = new HashSet<>(); - public MemoryMount() - { - directories.add( "" ); + public MemoryMount() { + directories.add(""); } @Override - public void makeDirectory( @Nonnull String path ) - { - File file = new File( path ); - while( file != null ) - { - directories.add( file.getPath() ); + public void makeDirectory(@Nonnull String path) { + File file = new File(path); + while (file != null) { + directories.add(file.getPath()); file = file.getParentFile(); } } @Override - public void delete( @Nonnull String path ) - { - if( files.containsKey( path ) ) - { - files.remove( path ); - } - else - { - directories.remove( path ); - for( String file : files.keySet().toArray( new String[0] ) ) - { - if( file.startsWith( path ) ) - { - files.remove( file ); + public void delete(@Nonnull String path) { + if (files.containsKey(path)) { + files.remove(path); + } else { + directories.remove(path); + for (String file : files.keySet().toArray(new String[0])) { + if (file.startsWith(path)) { + files.remove(file); } } - File parent = new File( path ).getParentFile(); - if( parent != null ) delete( parent.getPath() ); + File parent = new File(path).getParentFile(); + if (parent != null) + delete(parent.getPath()); } } @Nonnull @Override - public WritableByteChannel openForWrite( @Nonnull final String path ) - { - return Channels.newChannel( new ByteArrayOutputStream() - { + public WritableByteChannel openForWrite(@Nonnull final String path) { + return Channels.newChannel(new ByteArrayOutputStream() { @Override - public void close() throws IOException - { + public void close() throws IOException { super.close(); - files.put( path, toByteArray() ); + files.put(path, toByteArray()); } - } ); + }); } @Nonnull @Override - public WritableByteChannel openForAppend( @Nonnull final String path ) throws IOException - { - ByteArrayOutputStream stream = new ByteArrayOutputStream() - { + public WritableByteChannel openForAppend(@Nonnull final String path) throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream() { @Override - public void close() throws IOException - { + public void close() throws IOException { super.close(); - files.put( path, toByteArray() ); + files.put(path, toByteArray()); } }; - byte[] current = files.get( path ); - if( current != null ) stream.write( current ); + byte[] current = files.get(path); + if (current != null) + stream.write(current); - return Channels.newChannel( stream ); + return Channels.newChannel(stream); } @Override - public long getRemainingSpace() - { + public long getRemainingSpace() { return 1000000L; } @Override - public boolean exists( @Nonnull String path ) - { - return files.containsKey( path ) || directories.contains( path ); + public boolean exists(@Nonnull String path) { + return files.containsKey(path) || directories.contains(path); } @Override - public boolean isDirectory( @Nonnull String path ) - { - return directories.contains( path ); + public boolean isDirectory(@Nonnull String path) { + return directories.contains(path); } @Override - public void list( @Nonnull String path, @Nonnull List files ) - { - for( String file : this.files.keySet() ) - { - if( file.startsWith( path ) ) files.add( file.substring( path.length() + 1 ) ); + public void list(@Nonnull String path, @Nonnull List files) { + for (String file : this.files.keySet()) { + if (file.startsWith(path)) files.add(file.substring(path.length() + 1)); } } @Override - public long getSize( @Nonnull String path ) - { - throw new RuntimeException( "Not implemented" ); + public long getSize(@Nonnull String path) { + throw new RuntimeException("Not implemented"); } @Nonnull @Override - public ReadableByteChannel openForRead( @Nonnull String path ) - { - return new ArrayByteChannel( files.get( path ) ); + public ReadableByteChannel openForRead(@Nonnull String path) { + return new ArrayByteChannel(files.get(path)); } - public MemoryMount addFile( String file, String contents ) - { - files.put( file, contents.getBytes() ); + public MemoryMount addFile(String file, String contents) { + files.put(file, contents.getBytes()); return this; } } diff --git a/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java b/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java index 248883339..80520f2f9 100644 --- a/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java +++ b/src/testFixtures/java/dan200/computercraft/test/core/terminal/TerminalMatchers.java @@ -13,42 +13,35 @@ import java.util.Arrays; -public class TerminalMatchers -{ - public static Matcher textColourMatches( String[] x ) - { - return linesMatch( "text colour", Terminal::getTextColourLine, x ); +public class TerminalMatchers { + public static Matcher textColourMatches(String[] x) { + return linesMatch("text colour", Terminal::getTextColourLine, x); } - public static Matcher backgroundColourMatches( String[] x ) - { - return linesMatch( "background colour", Terminal::getBackgroundColourLine, x ); + public static Matcher backgroundColourMatches(String[] x) { + return linesMatch("background colour", Terminal::getBackgroundColourLine, x); } - public static Matcher textMatches( String[] x ) - { - return linesMatch( "text", Terminal::getLine, x ); + public static Matcher textMatches(String[] x) { + return linesMatch("text", Terminal::getLine, x); } - @SuppressWarnings( "unchecked" ) - public static Matcher linesMatch( String kind, LineProvider getLine, String[] lines ) - { - return linesMatchWith( kind, getLine, Arrays.stream( lines ).map( Matchers::equalTo ).toArray( Matcher[]::new ) ); + @SuppressWarnings("unchecked") + public static Matcher linesMatch(String kind, LineProvider getLine, String[] lines) { + return linesMatchWith(kind, getLine, Arrays.stream(lines).map(Matchers::equalTo).toArray(Matcher[]::new)); } - public static Matcher linesMatchWith( String kind, LineProvider getLine, Matcher[] lines ) - { - return ContramapMatcher.contramap( Matchers.array( lines ), kind, terminal -> { + public static Matcher linesMatchWith(String kind, LineProvider getLine, Matcher[] lines) { + return ContramapMatcher.contramap(Matchers.array(lines), kind, terminal -> { String[] termLines = new String[terminal.getHeight()]; - for( int i = 0; i < termLines.length; i++ ) termLines[i] = getLine.getLine( terminal, i ).toString(); + for (int i = 0; i < termLines.length; i++) termLines[i] = getLine.getLine(terminal, i).toString(); return termLines; - } ); + }); } @FunctionalInterface - public interface LineProvider - { - TextBuffer getLine( Terminal terminal, int line ); + public interface LineProvider { + TextBuffer getLine(Terminal terminal, int line); } } diff --git a/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt index 4805cb48f..f263eed3c 100644 --- a/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt +++ b/src/testFixtures/kotlin/dan200/computercraft/test/core/computer/KotlinComputerManager.kt @@ -28,7 +28,8 @@ typealias FakeComputerTask = (state: TimeoutState) -> MachineResult class KotlinComputerManager : AutoCloseable { private val machines: MutableMap> = HashMap() - private val context = ComputerContext(BasicEnvironment(), ComputerThread(1), NoWorkMainThreadScheduler()) { DummyLuaMachine(it) } + private val context = + ComputerContext(BasicEnvironment(), ComputerThread(1), NoWorkMainThreadScheduler()) { DummyLuaMachine(it) } private val errorLock: Lock = ReentrantLock() private val hasError = errorLock.newCondition() diff --git a/src/testMod/java/dan200/computercraft/export/Exporter.java b/src/testMod/java/dan200/computercraft/export/Exporter.java index 398c1fadc..ad12f2396 100644 --- a/src/testMod/java/dan200/computercraft/export/Exporter.java +++ b/src/testMod/java/dan200/computercraft/export/Exporter.java @@ -21,7 +21,11 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.*; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.ShapedRecipe; +import net.minecraft.world.item.crafting.ShapelessRecipe; import net.minecraftforge.registries.ForgeRegistries; import java.io.File; @@ -36,123 +40,103 @@ /** * Provides a {@literal /ccexport } command which exports icons and recipes for all ComputerCraft items. */ -public class Exporter -{ +public class Exporter { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); - public static void register( CommandDispatcher dispatcher ) - { + public static void register(CommandDispatcher dispatcher) { dispatcher.register( - LiteralArgumentBuilder.literal( "ccexport" ) - .then( RequiredArgumentBuilder.argument( "path", StringArgumentType.string() ) - .executes( c -> { - run( c.getArgument( "name", String.class ) ); - return 0; - } ) ) ); + LiteralArgumentBuilder.literal("ccexport") + .then(RequiredArgumentBuilder.argument("path", StringArgumentType.string()) + .executes(c -> { + run(c.getArgument("name", String.class)); + return 0; + }))); } - private static void run( String path ) - { - Path output = new File( path ).getAbsoluteFile().toPath(); - if( !Files.isDirectory( output ) ) - { - Minecraft.getInstance().gui.getChat().addMessage( Component.literal( "Output path does not exist" ) ); + private static void run(String path) { + Path output = new File(path).getAbsoluteFile().toPath(); + if (!Files.isDirectory(output)) { + Minecraft.getInstance().gui.getChat().addMessage(Component.literal("Output path does not exist")); return; } RenderSystem.assertOnRenderThread(); - try( ImageRenderer renderer = new ImageRenderer() ) - { - export( output, renderer ); - } - catch( IOException e ) - { - throw new UncheckedIOException( e ); + try (ImageRenderer renderer = new ImageRenderer()) { + export(output, renderer); + } catch (IOException e) { + throw new UncheckedIOException(e); } - Minecraft.getInstance().gui.getChat().addMessage( Component.literal( "Export finished!" ) ); + Minecraft.getInstance().gui.getChat().addMessage(Component.literal("Export finished!")); } - private static void export( Path root, ImageRenderer renderer ) throws IOException - { + private static void export(Path root, ImageRenderer renderer) throws IOException { JsonDump dump = new JsonDump(); Set items = new HashSet<>(); // First find all CC items - for( Item item : ForgeRegistries.ITEMS ) - { - if( ForgeRegistries.ITEMS.getKey( item ).getNamespace().equals( ComputerCraft.MOD_ID ) ) items.add( item ); + for (Item item : ForgeRegistries.ITEMS) { + if (ForgeRegistries.ITEMS.getKey(item).getNamespace().equals(ComputerCraft.MOD_ID)) + items.add(item); } // Now find all CC recipes. - for( CraftingRecipe recipe : Minecraft.getInstance().level.getRecipeManager().getAllRecipesFor( RecipeType.CRAFTING ) ) - { + for (CraftingRecipe recipe : Minecraft.getInstance().level.getRecipeManager().getAllRecipesFor(RecipeType.CRAFTING)) { ItemStack result = recipe.getResultItem(); - if( !ForgeRegistries.ITEMS.getKey( result.getItem() ).getNamespace().equals( ComputerCraft.MOD_ID ) ) - { + if (!ForgeRegistries.ITEMS.getKey(result.getItem()).getNamespace().equals(ComputerCraft.MOD_ID)) { continue; } - if( result.hasTag() ) - { - ComputerCraft.log.warn( "Skipping recipe {} as it has NBT", recipe.getId() ); + if (result.hasTag()) { + ComputerCraft.log.warn("Skipping recipe {} as it has NBT", recipe.getId()); continue; } - if( recipe instanceof ShapedRecipe shaped ) - { - JsonDump.Recipe converted = new JsonDump.Recipe( result ); + if (recipe instanceof ShapedRecipe shaped) { + JsonDump.Recipe converted = new JsonDump.Recipe(result); - for( int x = 0; x < shaped.getWidth(); x++ ) - { - for( int y = 0; y < shaped.getHeight(); y++ ) - { - Ingredient ingredient = shaped.getIngredients().get( x + y * shaped.getWidth() ); - if( ingredient.isEmpty() ) continue; + for (int x = 0; x < shaped.getWidth(); x++) { + for (int y = 0; y < shaped.getHeight(); y++) { + Ingredient ingredient = shaped.getIngredients().get(x + y * shaped.getWidth()); + if (ingredient.isEmpty()) + continue; - converted.setInput( x + y * 3, ingredient, items ); + converted.setInput(x + y * 3, ingredient, items); } } - dump.recipes.put( recipe.getId().toString(), converted ); - } - else if( recipe instanceof ShapelessRecipe shapeless ) - { - JsonDump.Recipe converted = new JsonDump.Recipe( result ); + dump.recipes.put(recipe.getId().toString(), converted); + } else if (recipe instanceof ShapelessRecipe shapeless) { + JsonDump.Recipe converted = new JsonDump.Recipe(result); NonNullList ingredients = shapeless.getIngredients(); - for( int i = 0; i < ingredients.size(); i++ ) - { - converted.setInput( i, ingredients.get( i ), items ); + for (int i = 0; i < ingredients.size(); i++) { + converted.setInput(i, ingredients.get(i), items); } - dump.recipes.put( recipe.getId().toString(), converted ); - } - else - { - ComputerCraft.log.info( "Don't know how to handle recipe {}", recipe ); + dump.recipes.put(recipe.getId().toString(), converted); + } else { + ComputerCraft.log.info("Don't know how to handle recipe {}", recipe); } } - Path itemDir = root.resolve( "items" ); - if( Files.exists( itemDir ) ) MoreFiles.deleteRecursively( itemDir, RecursiveDeleteOption.ALLOW_INSECURE ); + Path itemDir = root.resolve("items"); + if (Files.exists(itemDir)) MoreFiles.deleteRecursively(itemDir, RecursiveDeleteOption.ALLOW_INSECURE); renderer.setupState(); - for( Item item : items ) - { - ItemStack stack = new ItemStack( item ); - ResourceLocation location = ForgeRegistries.ITEMS.getKey( item ); - - dump.itemNames.put( location.toString(), stack.getHoverName().getString() ); - renderer.captureRender( itemDir.resolve( location.getNamespace() ).resolve( location.getPath() + ".png" ), - () -> Minecraft.getInstance().getItemRenderer().renderAndDecorateFakeItem( stack, 0, 0 ) + for (Item item : items) { + ItemStack stack = new ItemStack(item); + ResourceLocation location = ForgeRegistries.ITEMS.getKey(item); + + dump.itemNames.put(location.toString(), stack.getHoverName().getString()); + renderer.captureRender(itemDir.resolve(location.getNamespace()).resolve(location.getPath() + ".png"), + () -> Minecraft.getInstance().getItemRenderer().renderAndDecorateFakeItem(stack, 0, 0) ); } renderer.clearState(); - try( Writer writer = Files.newBufferedWriter( root.resolve( "index.json" ) ) ) - { - GSON.toJson( dump, writer ); + try (Writer writer = Files.newBufferedWriter(root.resolve("index.json"))) { + GSON.toJson(dump, writer); } } } diff --git a/src/testMod/java/dan200/computercraft/export/ImageRenderer.java b/src/testMod/java/dan200/computercraft/export/ImageRenderer.java index 7d4c2955f..a6b6b3d2d 100644 --- a/src/testMod/java/dan200/computercraft/export/ImageRenderer.java +++ b/src/testMod/java/dan200/computercraft/export/ImageRenderer.java @@ -20,60 +20,54 @@ /** * Utilities for saving OpenGL output to an image rather than displaying it on the screen. */ -public class ImageRenderer implements AutoCloseable -{ +public class ImageRenderer implements AutoCloseable { public static final int WIDTH = 64; public static final int HEIGHT = 64; - private final TextureTarget framebuffer = new TextureTarget( WIDTH, HEIGHT, true, Minecraft.ON_OSX ); - private final NativeImage image = new NativeImage( WIDTH, HEIGHT, Minecraft.ON_OSX ); + private final TextureTarget framebuffer = new TextureTarget(WIDTH, HEIGHT, true, Minecraft.ON_OSX); + private final NativeImage image = new NativeImage(WIDTH, HEIGHT, Minecraft.ON_OSX); private Matrix4f projectionMatrix; - public ImageRenderer() - { - framebuffer.setClearColor( 0, 0, 0, 0 ); - framebuffer.clear( Minecraft.ON_OSX ); + public ImageRenderer() { + framebuffer.setClearColor(0, 0, 0, 0); + framebuffer.clear(Minecraft.ON_OSX); } - public void setupState() - { + public void setupState() { projectionMatrix = RenderSystem.getProjectionMatrix(); - RenderSystem.setProjectionMatrix( Matrix4f.orthographic( 0, 16, 0, 16, 1000, 3000 ) ); + RenderSystem.setProjectionMatrix(Matrix4f.orthographic(0, 16, 0, 16, 1000, 3000)); var transform = RenderSystem.getModelViewStack(); transform.setIdentity(); - transform.translate( 0.0f, 0.0f, -2000.0f ); + transform.translate(0.0f, 0.0f, -2000.0f); FogRenderer.setupNoFog(); } - public void clearState() - { - RenderSystem.setProjectionMatrix( projectionMatrix ); + public void clearState() { + RenderSystem.setProjectionMatrix(projectionMatrix); RenderSystem.getModelViewStack().popPose(); } - public void captureRender( Path output, Runnable render ) throws IOException - { - Files.createDirectories( output.getParent() ); + public void captureRender(Path output, Runnable render) throws IOException { + Files.createDirectories(output.getParent()); - framebuffer.bindWrite( true ); - RenderSystem.clear( GL12.GL_COLOR_BUFFER_BIT | GL12.GL_DEPTH_BUFFER_BIT, Minecraft.ON_OSX ); + framebuffer.bindWrite(true); + RenderSystem.clear(GL12.GL_COLOR_BUFFER_BIT | GL12.GL_DEPTH_BUFFER_BIT, Minecraft.ON_OSX); render.run(); framebuffer.unbindWrite(); framebuffer.bindRead(); - image.downloadTexture( 0, false ); + image.downloadTexture(0, false); image.flipY(); framebuffer.unbindRead(); - image.writeToFile( output ); + image.writeToFile(output); } @Override - public void close() - { + public void close() { image.close(); framebuffer.destroyBuffers(); } diff --git a/src/testMod/java/dan200/computercraft/export/JsonDump.java b/src/testMod/java/dan200/computercraft/export/JsonDump.java index bc26f145d..863745dc3 100644 --- a/src/testMod/java/dan200/computercraft/export/JsonDump.java +++ b/src/testMod/java/dan200/computercraft/export/JsonDump.java @@ -11,56 +11,55 @@ import net.minecraft.world.item.crafting.Ingredient; import net.minecraftforge.registries.ForgeRegistries; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; -public class JsonDump -{ +public class JsonDump { public Map itemNames = new TreeMap<>(); public Map recipes = new TreeMap<>(); - public static class Recipe - { + public static class Recipe { + private static final Set canonicalItem = new HashSet<>(Arrays.asList( + Items.GLASS_PANE, Items.STONE, Items.CHEST + )); public final String[][] inputs = new String[9][]; public String output; public int count; - public Recipe( ItemStack output ) - { - this.output = ForgeRegistries.ITEMS.getKey( output.getItem() ).toString(); + public Recipe(ItemStack output) { + this.output = ForgeRegistries.ITEMS.getKey(output.getItem()).toString(); count = output.getCount(); } - public void setInput( int pos, Ingredient ingredient, Set trackedItems ) - { - if( ingredient.isEmpty() ) return; + public void setInput(int pos, Ingredient ingredient, Set trackedItems) { + if (ingredient.isEmpty()) + return; ItemStack[] items = ingredient.getItems(); // First try to simplify some tags to something easier. - for( ItemStack stack : items ) - { + for (ItemStack stack : items) { Item item = stack.getItem(); - if( !canonicalItem.contains( item ) ) continue; + if (!canonicalItem.contains(item)) + continue; - trackedItems.add( item ); - inputs[pos] = new String[] { ForgeRegistries.ITEMS.getKey( item ).toString() }; + trackedItems.add(item); + inputs[pos] = new String[]{ForgeRegistries.ITEMS.getKey(item).toString()}; return; } String[] itemIds = new String[items.length]; - for( int i = 0; i < items.length; i++ ) - { + for (int i = 0; i < items.length; i++) { Item item = items[i].getItem(); - trackedItems.add( item ); - itemIds[i] = ForgeRegistries.ITEMS.getKey( item ).toString(); + trackedItems.add(item); + itemIds[i] = ForgeRegistries.ITEMS.getKey(item).toString(); } - Arrays.sort( itemIds ); + Arrays.sort(itemIds); inputs[pos] = itemIds; } - - private static final Set canonicalItem = new HashSet<>( Arrays.asList( - Items.GLASS_PANE, Items.STONE, Items.CHEST - ) ); } } diff --git a/src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java b/src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java index d4b82a347..0e63f8f67 100644 --- a/src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java +++ b/src/testMod/java/dan200/computercraft/gametest/api/ComputerState.java @@ -21,8 +21,7 @@ * @see TestAPI For the Lua interface for this. * @see TestExtensionsKt#thenComputerOk(GameTestSequence, String, String) */ -public class ComputerState -{ +public class ComputerState { public static final String DONE = "DONE"; protected static final Map lookup = new ConcurrentHashMap<>(); @@ -30,19 +29,16 @@ public class ComputerState protected final Set markers = new HashSet<>(); protected String error; - public boolean isDone( @Nonnull String marker ) - { - return markers.contains( marker ); + public static ComputerState get(String label) { + return lookup.get(label); } - public void check( @Nonnull String marker ) - { - if( !markers.contains( marker ) ) throw new IllegalStateException( "Not yet at " + marker ); - if( error != null ) throw new GameTestAssertException( error ); + public boolean isDone(@Nonnull String marker) { + return markers.contains(marker); } - public static ComputerState get( String label ) - { - return lookup.get( label ); + public void check(@Nonnull String marker) { + if (!markers.contains(marker)) throw new IllegalStateException("Not yet at " + marker); + if (error != null) throw new GameTestAssertException(error); } } diff --git a/src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java b/src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java index be4684cb6..e0cc3a6a4 100644 --- a/src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java +++ b/src/testMod/java/dan200/computercraft/gametest/api/GameTestHolder.java @@ -17,8 +17,7 @@ *

* This is used by Forge to automatically load and test classes. */ -@Target( ElementType.TYPE ) -@Retention( RetentionPolicy.RUNTIME ) -public @interface GameTestHolder -{ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface GameTestHolder { } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java b/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java index de82eafe1..8c613eb13 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java @@ -34,99 +34,84 @@ /** * Helper commands for importing/exporting the computer directory. */ -class CCTestCommand -{ - public static final LevelResource LOCATION = new LevelResource( ComputerCraft.MOD_ID ); +class CCTestCommand { + public static final LevelResource LOCATION = new LevelResource(ComputerCraft.MOD_ID); - public static void register( CommandDispatcher dispatcher ) - { - dispatcher.register( choice( "cctest" ) - .then( literal( "import" ).executes( context -> { - importFiles( context.getSource().getServer() ); - return 0; - } ) ) - .then( literal( "export" ).executes( context -> { - exportFiles( context.getSource().getServer() ); + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(choice("cctest") + .then(literal("import").executes(context -> { + importFiles(context.getSource().getServer()); + return 0; + })) + .then(literal("export").executes(context -> { + exportFiles(context.getSource().getServer()); - for( TestFunction function : GameTestRegistry.getAllTestFunctions() ) - { - TestCommandAccessor.callExportTestStructure( context.getSource(), function.getStructureName() ); - } - return 0; - } ) ) - .then( literal( "regen-structures" ).executes( context -> { - for( TestFunction function : GameTestRegistry.getAllTestFunctions() ) - { - dispatcher.execute( "test import " + function.getTestName(), context.getSource() ); - TestCommandAccessor.callExportTestStructure( context.getSource(), function.getStructureName() ); - } - return 0; - } ) ) + for (TestFunction function : GameTestRegistry.getAllTestFunctions()) { + TestCommandAccessor.callExportTestStructure(context.getSource(), function.getStructureName()); + } + return 0; + })) + .then(literal("regen-structures").executes(context -> { + for (TestFunction function : GameTestRegistry.getAllTestFunctions()) { + dispatcher.execute("test import " + function.getTestName(), context.getSource()); + TestCommandAccessor.callExportTestStructure(context.getSource(), function.getStructureName()); + } + return 0; + })) - .then( literal( "marker" ).executes( context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - BlockPos pos = StructureUtils.findNearestStructureBlock( player.blockPosition(), 15, player.getLevel() ); - if( pos == null ) return error( context.getSource(), "No nearby test" ); + .then(literal("marker").executes(context -> { + ServerPlayer player = context.getSource().getPlayerOrException(); + BlockPos pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.getLevel()); + if (pos == null) return error(context.getSource(), "No nearby test"); - StructureBlockEntity structureBlock = (StructureBlockEntity) player.getLevel().getBlockEntity( pos ); - TestFunction info = GameTestRegistry.getTestFunction( structureBlock.getStructurePath() ); + StructureBlockEntity structureBlock = (StructureBlockEntity) player.getLevel().getBlockEntity(pos); + TestFunction info = GameTestRegistry.getTestFunction(structureBlock.getStructurePath()); - // Kill the existing armor stand - player - .getLevel().getEntities( EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals( info.getTestName() ) ) - .forEach( Entity::kill ); + // Kill the existing armor stand + player + .getLevel().getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(info.getTestName())) + .forEach(Entity::kill); - // And create a new one - CompoundTag nbt = new CompoundTag(); - nbt.putBoolean( "Marker", true ); - nbt.putBoolean( "Invisible", true ); - ArmorStand armorStand = EntityType.ARMOR_STAND.create( player.getLevel() ); - armorStand.readAdditionalSaveData( nbt ); - armorStand.copyPosition( player ); - armorStand.setCustomName( Component.literal( info.getTestName() ) ); - player.getLevel().addFreshEntity( armorStand ); - return 0; - } ) ) + // And create a new one + CompoundTag nbt = new CompoundTag(); + nbt.putBoolean("Marker", true); + nbt.putBoolean("Invisible", true); + ArmorStand armorStand = EntityType.ARMOR_STAND.create(player.getLevel()); + armorStand.readAdditionalSaveData(nbt); + armorStand.copyPosition(player); + armorStand.setCustomName(Component.literal(info.getTestName())); + player.getLevel().addFreshEntity(armorStand); + return 0; + })) ); } - public static void importFiles( MinecraftServer server ) - { - try - { - Copier.replicate( getSourceComputerPath(), getWorldComputerPath( server ) ); - } - catch( IOException e ) - { - throw new UncheckedIOException( e ); + public static void importFiles(MinecraftServer server) { + try { + Copier.replicate(getSourceComputerPath(), getWorldComputerPath(server)); + } catch (IOException e) { + throw new UncheckedIOException(e); } } - static void exportFiles( MinecraftServer server ) - { - try - { - Copier.replicate( getWorldComputerPath( server ), getSourceComputerPath() ); - } - catch( IOException e ) - { - throw new UncheckedIOException( e ); + static void exportFiles(MinecraftServer server) { + try { + Copier.replicate(getWorldComputerPath(server), getSourceComputerPath()); + } catch (IOException e) { + throw new UncheckedIOException(e); } } - private static Path getWorldComputerPath( MinecraftServer server ) - { - return server.getWorldPath( LOCATION ).resolve( "computer" ).resolve( "0" ); + private static Path getWorldComputerPath(MinecraftServer server) { + return server.getWorldPath(LOCATION).resolve("computer").resolve("0"); } - private static Path getSourceComputerPath() - { - return TestHooks.sourceDir.resolve( "computer" ); + private static Path getSourceComputerPath() { + return TestHooks.sourceDir.resolve("computer"); } - private static int error( CommandSourceStack source, String message ) - { - source.sendFailure( Component.literal( message ).withStyle( ChatFormatting.RED ) ); + private static int error(CommandSourceStack source, String message) { + source.sendFailure(Component.literal(message).withStyle(ChatFormatting.RED)); return 0; } } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java b/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java index 78638ad66..14170d26a 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java @@ -17,73 +17,33 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -@Mod.EventBusSubscriber( modid = "cctest", value = Dist.CLIENT ) -public final class ClientHooks -{ - private static final Logger LOG = LogManager.getLogger( TestHooks.class ); +@Mod.EventBusSubscriber(modid = "cctest", value = Dist.CLIENT) +public final class ClientHooks { + private static final Logger LOG = LogManager.getLogger(TestHooks.class); private static boolean triggered = false; - private ClientHooks() - { + private ClientHooks() { } @SubscribeEvent - public static void onGuiInit( ScreenEvent.Init event ) - { - if( triggered || !(event.getScreen() instanceof TitleScreen) ) return; + public static void onGuiInit(ScreenEvent.Init event) { + if (triggered || !(event.getScreen() instanceof TitleScreen)) + return; triggered = true; ClientHooks.openWorld(); } - private static void openWorld() - { + private static void openWorld() { Minecraft minecraft = Minecraft.getInstance(); // Clear some options before we get any further. - minecraft.options.autoJump().set( false ); - minecraft.options.cloudStatus().set( CloudStatus.OFF ); - minecraft.options.particles().set( ParticleStatus.MINIMAL ); + minecraft.options.autoJump().set(false); + minecraft.options.cloudStatus().set(CloudStatus.OFF); + minecraft.options.particles().set(ParticleStatus.MINIMAL); minecraft.options.tutorialStep = TutorialSteps.NONE; - minecraft.options.renderDistance().set( 6 ); - minecraft.options.gamma().set( 1.0 ); - - /* - if( minecraft.getLevelSource().levelExists( "test" ) ) - { - LOG.info( "World exists, loading it" ); - Minecraft.getInstance().loadLevel( "test" ); - } - else - { - LOG.info( "World does not exist, creating it for the first time" ); - - RegistryAccess registries = RegistryAccess.builtinCopy(); - - Registry dimensions = registries.registryOrThrow( Registry.DIMENSION_TYPE_REGISTRY ); - var biomes = registries.registryOrThrow( Registry.BIOME_REGISTRY ); - var structures = registries.registryOrThrow( Registry.STRUCTURE_SET_REGISTRY ); - - FlatLevelGeneratorSettings flatSettings = FlatLevelGeneratorSettings.getDefault( biomes, structures ) - .withLayers( - Collections.singletonList( new FlatLayerInfo( 4, Blocks.WHITE_CONCRETE ) ), - Optional.empty() - ); - flatSettings.setBiome( biomes.getHolderOrThrow( Biomes.DESERT ) ); - - WorldGenSettings generator = new WorldGenSettings( 0, false, false, withOverworld( - dimensions, - DimensionType.defaultDimensions( registries, 0 ), - new FlatLevelSource( structures, flatSettings ) - ) ); - - LevelSettings settings = new LevelSettings( - "test", GameType.CREATIVE, false, Difficulty.PEACEFUL, true, - new GameRules(), DataPackConfig.DEFAULT - ); - Minecraft.getInstance().createLevel( "test", settings, registries, generator ); - } - */ + minecraft.options.renderDistance().set(6); + minecraft.options.gamma().set(1.0); } } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/Copier.java b/src/testMod/java/dan200/computercraft/gametest/core/Copier.java index df198af9d..65351c637 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/Copier.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/Copier.java @@ -16,47 +16,40 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.function.Predicate; -final class Copier extends SimpleFileVisitor -{ +final class Copier extends SimpleFileVisitor { private final Path sourceDir; private final Path targetDir; private final Predicate predicate; - private Copier( Path sourceDir, Path targetDir, Predicate predicate ) - { + private Copier(Path sourceDir, Path targetDir, Predicate predicate) { this.sourceDir = sourceDir; this.targetDir = targetDir; this.predicate = predicate; } - @Override - public FileVisitResult visitFile( Path file, BasicFileAttributes attributes ) throws IOException - { - if( predicate.test( file ) ) Files.copy( file, targetDir.resolve( sourceDir.relativize( file ) ) ); - return FileVisitResult.CONTINUE; + public static void copy(Path from, Path to) throws IOException { + Files.walkFileTree(from, new Copier(from, to, p -> true)); } - @Override - public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attributes ) throws IOException - { - Path newDir = targetDir.resolve( sourceDir.relativize( dir ) ); - Files.createDirectories( newDir ); - return FileVisitResult.CONTINUE; + public static void replicate(Path from, Path to) throws IOException { + replicate(from, to, p -> true); } - public static void copy( Path from, Path to ) throws IOException - { - Files.walkFileTree( from, new Copier( from, to, p -> true ) ); + public static void replicate(Path from, Path to, Predicate check) throws IOException { + if (Files.exists(to)) MoreFiles.deleteRecursively(to, RecursiveDeleteOption.ALLOW_INSECURE); + Files.walkFileTree(from, new Copier(from, to, check)); } - public static void replicate( Path from, Path to ) throws IOException - { - replicate( from, to, p -> true ); + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException { + if (predicate.test(file)) Files.copy(file, targetDir.resolve(sourceDir.relativize(file))); + return FileVisitResult.CONTINUE; } - public static void replicate( Path from, Path to, Predicate check ) throws IOException - { - if( Files.exists( to ) ) MoreFiles.deleteRecursively( to, RecursiveDeleteOption.ALLOW_INSECURE ); - Files.walkFileTree( from, new Copier( from, to, check ) ); + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attributes) throws IOException { + Path newDir = targetDir.resolve(sourceDir.relativize(dir)); + Files.createDirectories(newDir); + return FileVisitResult.CONTINUE; } } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java index c939f6900..5539d9ac1 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java @@ -23,70 +23,61 @@ * * @see TestExtensionsKt#thenComputerOk(GameTestSequence, String, String) To check tests on the computer have passed. */ -public class TestAPI extends ComputerState implements ILuaAPI -{ +public class TestAPI extends ComputerState implements ILuaAPI { private final IComputerSystem system; private String label; - TestAPI( IComputerSystem system ) - { + TestAPI(IComputerSystem system) { this.system = system; } @Override - public void startup() - { - if( label == null ) label = system.getLabel(); - if( label == null ) - { + public void startup() { + if (label == null) label = system.getLabel(); + if (label == null) { label = "#" + system.getID(); - ComputerCraft.log.warn( "Computer {} has no label", label ); + ComputerCraft.log.warn("Computer {} has no label", label); } - ComputerCraft.log.info( "Computer '{}' has turned on.", label ); + ComputerCraft.log.info("Computer '{}' has turned on.", label); markers.clear(); error = null; - lookup.put( label, this ); + lookup.put(label, this); } @Override - public void shutdown() - { - ComputerCraft.log.info( "Computer '{}' has shut down.", label ); - if( lookup.get( label ) == this ) lookup.remove( label ); + public void shutdown() { + ComputerCraft.log.info("Computer '{}' has shut down.", label); + if (lookup.get(label) == this) + lookup.remove(label); } @Override - public String[] getNames() - { - return new String[] { "test" }; + public String[] getNames() { + return new String[]{"test"}; } @LuaFunction - public final void fail( String message ) throws LuaException - { - ComputerCraft.log.error( "Computer '{}' failed with {}", label, message ); - if( markers.contains( ComputerState.DONE ) ) throw new LuaException( "Cannot call fail/ok multiple times." ); - markers.add( ComputerState.DONE ); + public final void fail(String message) throws LuaException { + ComputerCraft.log.error("Computer '{}' failed with {}", label, message); + if (markers.contains(ComputerState.DONE)) throw new LuaException("Cannot call fail/ok multiple times."); + markers.add(ComputerState.DONE); error = message; - throw new LuaException( message ); + throw new LuaException(message); } @LuaFunction - public final void ok( Optional marker ) throws LuaException - { - String actualMarker = marker.orElse( ComputerState.DONE ); - if( markers.contains( ComputerState.DONE ) || markers.contains( actualMarker ) ) - { - throw new LuaException( "Cannot call fail/ok multiple times." ); + public final void ok(Optional marker) throws LuaException { + String actualMarker = marker.orElse(ComputerState.DONE); + if (markers.contains(ComputerState.DONE) || markers.contains(actualMarker)) { + throw new LuaException("Cannot call fail/ok multiple times."); } - markers.add( actualMarker ); + markers.add(actualMarker); } @LuaFunction - public final void log( String message ) - { - ComputerCraft.log.info( "[Computer '{}'] {}", label, message ); + public final void log(String message) { + ComputerCraft.log.info("[Computer '{}'] {}", label, message); } } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java b/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java index 45d8f69f3..cf1164c52 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java @@ -22,39 +22,36 @@ import java.nio.file.Path; import java.nio.file.Paths; -public class TestHooks -{ - public static final Logger LOGGER = LoggerFactory.getLogger( TestHooks.class ); +public class TestHooks { + public static final Logger LOGGER = LoggerFactory.getLogger(TestHooks.class); - public static final Path sourceDir = Paths.get( System.getProperty( "advancedperipheralstest.sources" ) ).normalize().toAbsolutePath(); + public static final Path sourceDir = Paths.get(System.getProperty("advancedperipheralstest.sources")).normalize().toAbsolutePath(); - public static void init() - { + public static void init() { ServerContext.luaMachine = ManagedComputers.INSTANCE; - ComputerCraftAPI.registerAPIFactory( TestAPI::new ); - StructureUtils.testStructuresDir = sourceDir.resolve( "structures" ).toString(); + ComputerCraftAPI.registerAPIFactory(TestAPI::new); + StructureUtils.testStructuresDir = sourceDir.resolve("structures").toString(); } - public static void onServerStarted( MinecraftServer server ) - { + public static void onServerStarted(MinecraftServer server) { GameRules rules = server.getGameRules(); - rules.getRule( GameRules.RULE_DAYLIGHT ).set( false, server ); + rules.getRule(GameRules.RULE_DAYLIGHT).set(false, server); - ServerLevel world = server.getLevel( Level.OVERWORLD ); - if( world != null ) world.setDayTime( Times.NOON ); + ServerLevel world = server.getLevel(Level.OVERWORLD); + if (world != null) + world.setDayTime(Times.NOON); - LOGGER.info( "Cleaning up after last run" ); - GameTestRunner.clearAllTests( server.overworld(), new BlockPos( 0, -60, 0 ), GameTestTicker.SINGLETON, 200 ); + LOGGER.info("Cleaning up after last run"); + GameTestRunner.clearAllTests(server.overworld(), new BlockPos(0, -60, 0), GameTestTicker.SINGLETON, 200); // Delete server context and add one with a mutable machine factory. This allows us to set the factory for // specific test batches without having to reset all computers. - for( var computer : ServerContext.get( server ).registry().getComputers() ) - { + for (var computer : ServerContext.get(server).registry().getComputers()) { var label = computer.getLabel() == null ? "#" + computer.getID() : computer.getLabel(); - LOGGER.warn( "Unexpected computer {}", label ); + LOGGER.warn("Unexpected computer {}", label); } - LOGGER.info( "Importing files" ); - CCTestCommand.importFiles( server ); + LOGGER.info("Importing files"); + CCTestCommand.importFiles(server); } } diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java index 8e66a929f..7a92267e6 100644 --- a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestHelperAccessor.java @@ -12,9 +12,8 @@ import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin( GameTestHelper.class ) -public interface GameTestHelperAccessor -{ +@Mixin(GameTestHelper.class) +public interface GameTestHelperAccessor { @Invoker AABB callGetBounds(); diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java index b7e2a1846..258be4718 100644 --- a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestInfoAccessor.java @@ -9,9 +9,8 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin( GameTestInfo.class ) -public interface GameTestInfoAccessor -{ - @Invoker( "getTick" ) +@Mixin(GameTestInfo.class) +public interface GameTestInfoAccessor { + @Invoker("getTick") long computercraft$getTick(); } diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java index 9e9dad1ab..a23a707fb 100644 --- a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceAccessor.java @@ -10,9 +10,8 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; -@Mixin( GameTestSequence.class ) -public interface GameTestSequenceAccessor -{ +@Mixin(GameTestSequence.class) +public interface GameTestSequenceAccessor { @Accessor GameTestInfo getParent(); } diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java index efc7293c7..bbc65b042 100644 --- a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java @@ -14,9 +14,8 @@ import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; -@Mixin( GameTestSequence.class ) -class GameTestSequenceMixin -{ +@Mixin(GameTestSequence.class) +class GameTestSequenceMixin { @Shadow @Final GameTestInfo parent; @@ -24,35 +23,26 @@ class GameTestSequenceMixin /** * Override {@link GameTestSequence#tickAndContinue(long)} to catch non-{@link GameTestAssertException} failures. * - * @param ticks The current tick. * @author Jonathan Coates + * @param ticks The current tick. * @reason There's no sense doing this in a more compatible way for game tests. */ @Overwrite - public void tickAndContinue( long ticks ) - { - try - { - tick( ticks ); - } - catch( GameTestAssertException ignored ) - { + public void tickAndContinue(long ticks) { + try { + tick(ticks); + } catch (GameTestAssertException ignored) { // Mimic the original behaviour. - } - catch( AssertionError e ) - { - parent.fail( e ); - } - catch( Exception e ) - { + } catch (AssertionError e) { + parent.fail(e); + } catch (Exception e) { // Fail the test, rather than crashing the server. - TestHooks.LOGGER.error( "{} threw unexpected exception", parent.getTestName(), e ); - parent.fail( e ); + TestHooks.LOGGER.error("{} threw unexpected exception", parent.getTestName(), e); + parent.fail(e); } } @Shadow - private void tick( long tick ) - { + private void tick(long tick) { } } diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java b/src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java index 70ce8ee55..8f87246a1 100644 --- a/src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/TestCommandAccessor.java @@ -10,12 +10,10 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Invoker; -@Mixin( TestCommand.class ) -public interface TestCommandAccessor -{ +@Mixin(TestCommand.class) +public interface TestCommandAccessor { @Invoker - static int callExportTestStructure( CommandSourceStack source, String structure ) - { + static int callExportTestStructure(CommandSourceStack source, String structure) { return 0; } } diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt index ef3227d80..6f776aee7 100644 --- a/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt +++ b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt @@ -77,7 +77,10 @@ fun GameTestSequence.thenComputerOk(name: String? = null, marker: String = Compu /** * Run a task on a computer but don't wait for it to finish. */ -fun GameTestSequence.thenStartComputer(name: String? = null, action: suspend LuaTaskContext.() -> Unit): GameTestSequence { +fun GameTestSequence.thenStartComputer( + name: String? = null, + action: suspend LuaTaskContext.() -> Unit +): GameTestSequence { val test = (this as GameTestSequenceAccessor).parent val label = test.testName + (if (name == null) "" else ".$name") return thenExecuteFailFast { ManagedComputers.enqueue(test, label, action) } @@ -108,7 +111,12 @@ fun GameTestHelper.sequence(run: GameTestSequence.() -> Unit) { /** * A custom instance of [GameTestAssertPosException] which allows for longer error messages. */ -private class VerboseGameTestAssertPosException(message: String, absolutePos: BlockPos, relativePos: BlockPos, tick: Long) : +private class VerboseGameTestAssertPosException( + message: String, + absolutePos: BlockPos, + relativePos: BlockPos, + tick: Long +) : GameTestAssertPosException(message, absolutePos, relativePos, tick) { override fun getMessageToShowAtBlock(): String = message!!.lineSequence().first() } @@ -136,7 +144,12 @@ fun GameTestHelper.assertBlockIs(pos: BlockPos, predicate: (BlockState) -> Boole /** * A version of [GameTestHelper.assertBlockProperty] which includes the current block state in the error message. */ -fun > GameTestHelper.assertBlockHas(pos: BlockPos, property: Property, value: T, message: String = "") { +fun > GameTestHelper.assertBlockHas( + pos: BlockPos, + property: Property, + value: T, + message: String = "" +) { val state = getBlockState(pos) if (!state.hasProperty(property)) { val id = ForgeRegistries.BLOCKS.getKey(state.block) diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt index 624c98ea7..6cfe36f9b 100644 --- a/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/ManagedComputers.kt @@ -106,7 +106,8 @@ object ManagedComputers : ILuaMachine.Factory { } } - private class KotlinMachine(environment: MachineEnvironment, private val label: String) : KotlinLuaMachine(environment) { + private class KotlinMachine(environment: MachineEnvironment, private val label: String) : + KotlinLuaMachine(environment) { override fun getTask(): (suspend KotlinLuaMachine.() -> Unit)? = computers[label]?.poll() } @@ -130,7 +131,12 @@ object ManagedComputers : ILuaMachine.Factory { } else { val pos = computer.position val relativePos = pos.subtract(test.structureBlockPos) - throw GameTestAssertPosException(message, pos, relativePos, (test as GameTestInfoAccessor).`computercraft$getTick`()) + throw GameTestAssertPosException( + message, + pos, + relativePos, + (test as GameTestInfoAccessor).`computercraft$getTick`() + ) } } } diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt index bb662fe28..23d03beaf 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt @@ -3,7 +3,6 @@ package de.srendi.advancedperipherals.test import dan200.computercraft.gametest.api.GameTestHolder import dan200.computercraft.gametest.api.sequence import dan200.computercraft.gametest.api.thenComputerOk -import de.srendi.advancedperipherals.common.setup.Blocks import net.minecraft.core.BlockPos import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper From 53bf4b2ab9961f69a57c2035d8cea68443d34d28 Mon Sep 17 00:00:00 2001 From: Srendi Date: Sun, 5 May 2024 23:10:44 +0200 Subject: [PATCH 15/61] Fixed if statement --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 96662f578..6cfde6fb4 100644 --- a/build.gradle +++ b/build.gradle @@ -158,7 +158,7 @@ minecraft { def allFiles = new HashSet(); def minecraftClasspath = oldClasspath?.get() - if (!minecraftClasspath != null && !minecraftClasspath.isEmpty()) allFiles.addAll(minecraftClasspath.split(File.pathSeparatorChar)) + if (minecraftClasspath != null && !minecraftClasspath.isEmpty()) allFiles.addAll(minecraftClasspath.split(File.pathSeparatorChar)) for (file in configurations["testMinecraftLibrary"]) allFiles.add(file.absolutePath) @@ -188,7 +188,7 @@ minecraft { def allFiles = new HashSet(); def minecraftClasspath = oldClasspath?.get() - if (!minecraftClasspath != null && !minecraftClasspath.isEmpty()) allFiles.addAll(minecraftClasspath.split(File.pathSeparatorChar)) + if (minecraftClasspath != null && !minecraftClasspath.isEmpty()) allFiles.addAll(minecraftClasspath.split(File.pathSeparatorChar)) for (file in configurations["testMinecraftLibrary"]) allFiles.add(file.absolutePath) From 8324d84262e628456c6faf75a40226863a4051b6 Mon Sep 17 00:00:00 2001 From: Srendi Date: Mon, 6 May 2024 14:43:43 +0200 Subject: [PATCH 16/61] Added a prototype test for the ME Bridge. Used to know how the ME System handles the game tests. We need to wait a bit using `sleep` in the test lua script so the system has enough time to boot up Don't implement kotlinforforge to prevent issues with kotlin and kotlin coroutines --- build.gradle | 5 +- gradle.properties | 2 + .../test/PeripheralTest.kt | 25 ++ .../test/Peripheral_Test.kt | 19 -- ...ent.lua => peripheraltest.environment.lua} | 4 +- .../tests/peripheraltest.mecrafting.lua | 30 ++ ...t.snbt => peripheraltest.environment.snbt} | 2 +- .../structures/peripheraltest.mecrafting.snbt | 271 ++++++++++++++++++ 8 files changed, 333 insertions(+), 25 deletions(-) create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt delete mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt rename src/testMod/resources/data/advancedperipheralstest/computer/tests/{peripheral_test.environment.lua => peripheraltest.environment.lua} (65%) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua rename src/testMod/resources/data/advancedperipheralstest/structures/{peripheral_test.environment.snbt => peripheraltest.environment.snbt} (98%) create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt diff --git a/build.gradle b/build.gradle index 6cfde6fb4..c66075c79 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { id 'net.darkhax.curseforgegradle' version '1.1.16' id 'org.jetbrains.changelog' version '1.2.1' id "com.modrinth.minotaur" version "2.+" - id "org.jetbrains.kotlin.jvm" version "1.9.23" + id "org.jetbrains.kotlin.jvm" version "${kotlin_version}" id 'net.minecraftforge.gradle' version '[6.0.18,6.2)' id 'org.parchmentmc.librarian.forgegradle' version '1.+' id 'org.spongepowered.mixin' version '0.7.+' @@ -367,7 +367,7 @@ dependencies { compileOnly fg.deobf("curse.maven:ae-additions-493962:${ae2additions_version}") //runtimeOnly fg.deobf("curse.maven:ae-additions-493962:${ae2additions_version}") - implementation fg.deobf("thedarkcolour:kotlinforforge:${kotlinforforge_version}") + runtimeOnly fg.deobf("thedarkcolour:kotlinforforge:${kotlinforforge_version}") // Botania compileOnly fg.deobf("vazkii.botania:Botania:${botania_version}") @@ -408,6 +408,7 @@ dependencies { testImplementation "org.junit.jupiter:junit-jupiter-params:${junit_version}" testImplementation "org.junit.jupiter:junit-jupiter-engine:${junit_version}" testImplementation "net.jqwik:jqwik:${jqwikVersion}" + testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${kotlin_coroutines_version}" testImplementation "org.hamcrest:hamcrest:${hamcrest_version}" testModImplementation sourceSets.main.output testModImplementation sourceSets.testFixtures.output diff --git a/gradle.properties b/gradle.properties index 18bec706c..d7ebea3ca 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,6 +18,8 @@ junit_version=5.10.2 hamcrest_version=2.2 ttoolkit_version=0.1.3 jqwikVersion=1.8.4 +kotlin_version=1.9.23 +kotlin_coroutines_version=1.8.0 # Mod dependencies cc_version=1.101.3 diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt new file mode 100644 index 000000000..63f17c26f --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -0,0 +1,25 @@ +package de.srendi.advancedperipherals.test + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenComputerOk +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper + +@GameTestHolder +class PeripheralTest { + + @GameTest + fun environment(context: GameTestHelper) = context.sequence { + context.level.setWeatherParameters(6000, 0, false, false); + thenComputerOk(); + } + + // The ME System needs to boot up, so we use a sleep() in the specific lua script + // We set the timeoutTicks to 300 so the test does not fail + @GameTest(timeoutTicks = 300) + fun meCrafting(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + +} \ No newline at end of file diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt deleted file mode 100644 index 23d03beaf..000000000 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/Peripheral_Test.kt +++ /dev/null @@ -1,19 +0,0 @@ -package de.srendi.advancedperipherals.test - -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.gametest.api.thenComputerOk -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper - -@GameTestHolder -class Peripheral_Test { - - @GameTest - fun Environment(context: GameTestHelper) = context.sequence { - val detector = BlockPos(2, 2, 2); - thenComputerOk() - } - -} \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua similarity index 65% rename from src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua rename to src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua index 38fbb766e..500b323ea 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheral_test.environment.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua @@ -1,7 +1,5 @@ detector = peripheral.find("environmentDetector") -if (detector == nil) then - test.fail("Peripheral not found") -end +test.eq(detector ~= nil, true, "Peripheral not found") isRaining = detector.isRaining() test.eq(false,isRaining, "It should not rain") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua new file mode 100644 index 000000000..d5a5a7107 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -0,0 +1,30 @@ +sleep(4) +bridge = peripheral.wrap("bottom") +test.assert(bridge, "Peripheral not found") + +isOnline = bridge.isConnected() +test.assert(isOnline, "Bridge is not connected/system is not online") + +validEnergy = bridge.getEnergyUsage() > 24 +test.assert(validEnergy, tostring(bridge.getEnergyUsage()) .. "Consumption does not seem right") + +stickFilter = {name="minecraft:stick"} +planksFilter = {name="minecraft:oak_planks"} +logFilter = {name="minecraft:oak_log"} + +isItemCrafting = bridge.isItemCrafting(stickFilter) +test.assert(not isItemCrafting, "There shouldn't be a crafting job") + +-- Should be true. We have a pattern for it. +isItemCraftable = bridge.isItemCraftable(stickFilter) +test.assert(isItemCraftable, "Stick should be craftable") + +-- Logs should not be craftable, we don't have a pattern for it +isItemCraftable = bridge.getItem(logFilter).isCraftable +-- We use == false here since the not keyword would also return true if the value is nil +test.assert(isItemCraftable == false, "Log should not be craftable") + +-- Planks are craftable +isItemCraftable = bridge.getItem(planksFilter).isCraftable +test.assert(isItemCraftable == true, "Planks should be craftable") + diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.environment.snbt similarity index 98% rename from src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.snbt rename to src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.environment.snbt index 34b15f3b3..be7577190 100644 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheral_test.environment.snbt +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.environment.snbt @@ -34,7 +34,7 @@ {pos: [0, 1, 4], state: "minecraft:air"}, {pos: [1, 1, 0], state: "minecraft:air"}, {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheral_test.environment", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.environment", On: 1b, id: "computercraft:computer_advanced"}}, {pos: [1, 1, 3], state: "minecraft:air"}, {pos: [1, 1, 4], state: "minecraft:air"}, {pos: [2, 1, 0], state: "minecraft:air"}, diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt new file mode 100644 index 000000000..148fbf2f3 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt @@ -0,0 +1,271 @@ +{ + DataVersion: 3120, + size: [5, 10, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_planks"}, {"#c": "ae2:i", id: "minecraft:oak_log"}]}}, item1: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, online: 1b}}}, + {pos: [1, 1, 2], state: "advancedperipherals:me_bridge{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[ME Bridge]"}, Items: [], id: "advancedperipherals:me_bridge"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "ae2:controller{state:online,type:block}", nbt: {ForgeCaps: {}, id: "ae2:controller", internalCurrentPower: 0.0d, proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [2, 1, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsNorth: 0, channelsUp: 0, channelsWest: 0, connections: ["up", "north", "west"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "ae2:creative_energy_cell", nbt: {ForgeCaps: {}, forward: "WEST", id: "ae2:creative_energy_cell", proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.mecrafting", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {blankPattern: [{Count: 60b, Slot: 0, id: "ae2:blank_pattern"}], encodedInputs: [{}, {"#": 1L, "#c": "ae2:i", id: "ae2:white_smart_dense_cable"}], encodedOutputs: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}], filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "PROCESSING", sort_by: "AMOUNT", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, + {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, + {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsSouth: 0, channelsUp: 0, connections: ["down", "up", "south"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 4, 3], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsEast: 0, channelsNorth: 0, channelsSouth: 0, channelsWest: 0, connections: ["north", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 4, 4], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [0, 7, 0], state: "minecraft:air"}, + {pos: [0, 7, 1], state: "minecraft:air"}, + {pos: [0, 7, 2], state: "minecraft:air"}, + {pos: [0, 7, 3], state: "minecraft:air"}, + {pos: [0, 7, 4], state: "minecraft:air"}, + {pos: [1, 7, 0], state: "minecraft:air"}, + {pos: [1, 7, 1], state: "minecraft:air"}, + {pos: [1, 7, 2], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {}], out: {Count: 1b, id: "minecraft:oak_pressure_plate"}, recipe: "minecraft:oak_pressure_plate", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [1, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [1, 7, 4], state: "minecraft:air"}, + {pos: [2, 7, 0], state: "minecraft:air"}, + {pos: [2, 7, 1], state: "minecraft:air"}, + {pos: [2, 7, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsEast: 0, channelsSouth: 0, channelsWest: 0, connections: ["down", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 7, 3], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}], out: {Count: 4b, id: "minecraft:stick"}, recipe: "minecraft:stick", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [2, 7, 4], state: "minecraft:air"}, + {pos: [3, 7, 0], state: "minecraft:air"}, + {pos: [3, 7, 1], state: "minecraft:air"}, + {pos: [3, 7, 2], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {Count: 1b, id: "minecraft:oak_log"}, {}, {}, {}, {}, {}], out: {Count: 4b, id: "minecraft:oak_planks"}, recipe: "minecraft:oak_planks", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [3, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 7, 4], state: "minecraft:air"}, + {pos: [4, 7, 0], state: "minecraft:air"}, + {pos: [4, 7, 1], state: "minecraft:air"}, + {pos: [4, 7, 2], state: "minecraft:air"}, + {pos: [4, 7, 3], state: "minecraft:air"}, + {pos: [4, 7, 4], state: "minecraft:air"}, + {pos: [0, 8, 0], state: "minecraft:air"}, + {pos: [0, 8, 1], state: "minecraft:air"}, + {pos: [0, 8, 2], state: "minecraft:air"}, + {pos: [0, 8, 3], state: "minecraft:air"}, + {pos: [0, 8, 4], state: "minecraft:air"}, + {pos: [1, 8, 0], state: "minecraft:air"}, + {pos: [1, 8, 1], state: "minecraft:air"}, + {pos: [1, 8, 2], state: "minecraft:air"}, + {pos: [1, 8, 3], state: "minecraft:air"}, + {pos: [1, 8, 4], state: "minecraft:air"}, + {pos: [2, 8, 0], state: "minecraft:air"}, + {pos: [2, 8, 1], state: "minecraft:air"}, + {pos: [2, 8, 2], state: "minecraft:air"}, + {pos: [2, 8, 3], state: "minecraft:air"}, + {pos: [2, 8, 4], state: "minecraft:air"}, + {pos: [3, 8, 0], state: "minecraft:air"}, + {pos: [3, 8, 1], state: "minecraft:air"}, + {pos: [3, 8, 2], state: "minecraft:air"}, + {pos: [3, 8, 3], state: "minecraft:air"}, + {pos: [3, 8, 4], state: "minecraft:air"}, + {pos: [4, 8, 0], state: "minecraft:air"}, + {pos: [4, 8, 1], state: "minecraft:air"}, + {pos: [4, 8, 2], state: "minecraft:air"}, + {pos: [4, 8, 3], state: "minecraft:air"}, + {pos: [4, 8, 4], state: "minecraft:air"}, + {pos: [0, 9, 0], state: "minecraft:air"}, + {pos: [0, 9, 1], state: "minecraft:air"}, + {pos: [0, 9, 2], state: "minecraft:air"}, + {pos: [0, 9, 3], state: "minecraft:air"}, + {pos: [0, 9, 4], state: "minecraft:air"}, + {pos: [1, 9, 0], state: "minecraft:air"}, + {pos: [1, 9, 1], state: "minecraft:air"}, + {pos: [1, 9, 2], state: "minecraft:air"}, + {pos: [1, 9, 3], state: "minecraft:air"}, + {pos: [1, 9, 4], state: "minecraft:air"}, + {pos: [2, 9, 0], state: "minecraft:air"}, + {pos: [2, 9, 1], state: "minecraft:air"}, + {pos: [2, 9, 2], state: "minecraft:air"}, + {pos: [2, 9, 3], state: "minecraft:air"}, + {pos: [2, 9, 4], state: "minecraft:air"}, + {pos: [3, 9, 0], state: "minecraft:air"}, + {pos: [3, 9, 1], state: "minecraft:air"}, + {pos: [3, 9, 2], state: "minecraft:air"}, + {pos: [3, 9, 3], state: "minecraft:air"}, + {pos: [3, 9, 4], state: "minecraft:air"}, + {pos: [4, 9, 0], state: "minecraft:air"}, + {pos: [4, 9, 1], state: "minecraft:air"}, + {pos: [4, 9, 2], state: "minecraft:air"}, + {pos: [4, 9, 3], state: "minecraft:air"}, + {pos: [4, 9, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "ae2:drive", + "advancedperipherals:me_bridge{orientation:up_east}", + "ae2:controller{state:online,type:block}", + "ae2:cable_bus{light_level:0,waterlogged:false}", + "ae2:creative_energy_cell", + "computercraft:computer_advanced{facing:north,state:blinking}", + "ae2:cable_bus{light_level:9,waterlogged:false}", + "ae2:64k_crafting_storage{formed:true,powered:true}", + "ae2:pattern_provider{omnidirectional:true}", + "ae2:molecular_assembler{powered:true}" + ] +} From 4da1afd1dd5746fbcefd0f607f92bda5424629fd Mon Sep 17 00:00:00 2001 From: Srendi Date: Tue, 7 May 2024 21:51:13 +0200 Subject: [PATCH 17/61] Added documentation on how to create tests. This is not completely done, but gives a first impression on how to create tests and how to run them --- docs/CREATING_TESTS.MD | 72 +++++++++++++++++++++++++++++++++++++++++ docs/assets/img.png | Bin 0 -> 251100 bytes docs/assets/img_1.png | Bin 0 -> 31616 bytes 3 files changed, 72 insertions(+) create mode 100644 docs/CREATING_TESTS.MD create mode 100644 docs/assets/img.png create mode 100644 docs/assets/img_1.png diff --git a/docs/CREATING_TESTS.MD b/docs/CREATING_TESTS.MD new file mode 100644 index 000000000..bf4bd7951 --- /dev/null +++ b/docs/CREATING_TESTS.MD @@ -0,0 +1,72 @@ +## Creating Game Tests + +Since [#562](https://github.com/IntelligenceModding/AdvancedPeripherals/pull/562), Advanced Peripherals has a testing framework that allows us to write tests for our peripherals. +The testing framework is copied from [ComputerCraft](https://github.com/cc-tweaked/CC-Tweaked) and adapted to Advanced Peripherals. + +### First things first. + +To write a test, you need to have a test world. But this needs to be done in the testing environment. +To run the testing environment, run the gradle task `runTestClient`. This will start a new instance of Minecraft with the testing environment. +That includes the ability to run tests, import and export tests using the `/cctest` and the `/test` command. + +After the tests are created, you can use the gradle task `runTestServer` to start the game test server which then runs all the test. +To test a single test, you can also use `/test run ` in the testing environment. + +### Building your test structure + +Tests should have a base plate made out of andesite. +Every test needs one computer and the peripheral you want to test. For example the environment detector. + +![assets/img.png](assets/img.png) + +Now you need to set a label to the computer, so it can run the lua test script. +`label set .` +For example, peripheraltest as the test type. The test type is the name of the `@GameTestHolder` class. PeripheralTest.kt for this type. +`environment` would be our test name. So the label would be `peripheraltest.environment`. + +The computer needs the id 0 so it can load the default startup.lua and the tests scripts from the resources folder. + +Now to save your test, get a structure block, place it in the lower right corner of the test structure and set the mode to save. +Use the command `/give @p minecraft:structure_block` to get a structure block. + +Set the size for your test and the structure name. The structure name is your test name with the minecraft namespace. `minecraft:peripheraltest.environment` in our case. + +![assets/img_1.png](assets/img_1.png) + +Click on done to save the content of the structure block and then on SAVE to save the structure. +We now have our test structure saved as a .nbt file in the world folder. To export it as a snbt file, use the command `/cctest export` +to export the file to the `src/testMod/resources/data/advancedperipherals/structures` folder, so it can be used by the game test server later. + +### Writing the test + +To write a test, you need to create a new class in the `src/testMod/kotlin/advancedperipherals/test` package or use one of the existing classes. +The class should be annotated with `@GameTestHolder`. +The class should have a function annotated with `@GameTest` that will be executed by the game test server later. +The function needs to have the parameter `GameTestContext` that will be used to interact with the game world. + +A simple game test would look like this. You can see that the context can be used to interact with the world. +You can then use one of the helper functions to interact with the computer. For example, `thenComputerOk()` to check if the script on the computer was executed without any fails. +```kt + @GameTest + fun environment(context: GameTestHelper) = context.sequence { + context.level.setWeatherParameters(6000, 0, false, false); + thenComputerOk(); + } +``` + +Of course, you need a lua script to interact with the peripheral. +The script should be placed in the `src/testMod/resources/data/advancedperipheralstest/computer/tests` folder and should be named after the test name. +`peripheraltest.environment.lua` in our case. + +```lua +detector = peripheral.find("environmentDetector") +test.eq(detector ~= nil, true, "Peripheral not found") + +isRaining = detector.isRaining() +test.eq(false,isRaining, "It should not rain") +``` + +Last but not least, import the script to the computer. You need to do that when you're currently in the test world, and you want to write the script in your IDE. +Luckily, the test framework provides a command for that. +`/cctest import` imports the scripts from the resources folder to the world folder. +You can then find the script in the computer's folder using `ls tests/`. \ No newline at end of file diff --git a/docs/assets/img.png b/docs/assets/img.png new file mode 100644 index 0000000000000000000000000000000000000000..1887d9961c7644c5d13270ed970d0892222384ab GIT binary patch literal 251100 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

ho6(mWe5*}S*>&|<&y5OkPyBSpin-+4*z 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

$P!n;+;Q4FPItz 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

aUD>26t5S;uv2|9RDj>!jbb}{O!1D?GzkMym@sq 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

@hCFw^uo%DtCn8#IKy;fZ+Ur&Y)&K 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 literal 0 HcmV?d00001 From 8099d498baa72e7e23529ff9283fddecc368f72a Mon Sep 17 00:00:00 2001 From: Srendi Date: Wed, 8 May 2024 09:12:30 +0200 Subject: [PATCH 18/61] Some styling changes to the lua scripts --- .../computer/tests/peripheraltest.environment.lua | 4 ++-- .../computer/tests/peripheraltest.mecrafting.lua | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua index 500b323ea..ff0400c66 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua @@ -1,5 +1,5 @@ detector = peripheral.find("environmentDetector") -test.eq(detector ~= nil, true, "Peripheral not found") +test.assert(detector, true, "Peripheral not found") isRaining = detector.isRaining() -test.eq(false,isRaining, "It should not rain") +test.eq(false, isRaining, "It should not rain") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua index d5a5a7107..b44336379 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -6,18 +6,18 @@ isOnline = bridge.isConnected() test.assert(isOnline, "Bridge is not connected/system is not online") validEnergy = bridge.getEnergyUsage() > 24 -test.assert(validEnergy, tostring(bridge.getEnergyUsage()) .. "Consumption does not seem right") +test.assert(validEnergy, tostring(bridge.getEnergyUsage()) .. " Consumption does not seem right") stickFilter = {name="minecraft:stick"} planksFilter = {name="minecraft:oak_planks"} logFilter = {name="minecraft:oak_log"} isItemCrafting = bridge.isItemCrafting(stickFilter) -test.assert(not isItemCrafting, "There shouldn't be a crafting job") +test.assert(isItemCrafting == true, "There shouldn't be a crafting job") -- Should be true. We have a pattern for it. isItemCraftable = bridge.isItemCraftable(stickFilter) -test.assert(isItemCraftable, "Stick should be craftable") +test.assert(isItemCraftable == true, "Stick should be craftable") -- Logs should not be craftable, we don't have a pattern for it isItemCraftable = bridge.getItem(logFilter).isCraftable From 30c10ac95437670285f34c6cb7b214d3ef86ecee Mon Sep 17 00:00:00 2001 From: Srendi Date: Wed, 8 May 2024 19:20:29 +0200 Subject: [PATCH 19/61] Polished andesite --- docs/CREATING_TESTS.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CREATING_TESTS.MD b/docs/CREATING_TESTS.MD index bf4bd7951..28dcca4fe 100644 --- a/docs/CREATING_TESTS.MD +++ b/docs/CREATING_TESTS.MD @@ -14,7 +14,7 @@ To test a single test, you can also use `/test run ` in the testing e ### Building your test structure -Tests should have a base plate made out of andesite. +Tests should have a base plate made out of polished andesite. This is not a standardized design, it is just the way it is done everywhere else. Every test needs one computer and the peripheral you want to test. For example the environment detector. ![assets/img.png](assets/img.png) From 05d7ee52ee01973bec3e66ffa2b89714a595ca3f Mon Sep 17 00:00:00 2001 From: Srendi Date: Wed, 8 May 2024 19:21:23 +0200 Subject: [PATCH 20/61] eq -> assert and space fixing in the docs --- docs/CREATING_TESTS.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CREATING_TESTS.MD b/docs/CREATING_TESTS.MD index 28dcca4fe..87c9f29bc 100644 --- a/docs/CREATING_TESTS.MD +++ b/docs/CREATING_TESTS.MD @@ -60,10 +60,10 @@ The script should be placed in the `src/testMod/resources/data/advancedperiphera ```lua detector = peripheral.find("environmentDetector") -test.eq(detector ~= nil, true, "Peripheral not found") +test.assert(detectorl, true, "Peripheral not found") isRaining = detector.isRaining() -test.eq(false,isRaining, "It should not rain") +test.eq(false, isRaining, "It should not rain") ``` Last but not least, import the script to the computer. You need to do that when you're currently in the test world, and you want to write the script in your IDE. From afcecd55874476735dc4d1007e7b4aba56baa5bd Mon Sep 17 00:00:00 2001 From: Srendi Date: Wed, 8 May 2024 23:40:31 +0200 Subject: [PATCH 21/61] Finished the me crafting test and started implementing a test for me storage related function where I need to fix a bug in AP first --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.mecrafting.lua | 53 +++- .../tests/peripheraltest.mestorage.lua | 9 + .../structures/peripheraltest.mecrafting.snbt | 30 +- .../structures/peripheraltest.mestorage.snbt | 273 ++++++++++++++++++ 5 files changed, 355 insertions(+), 15 deletions(-) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 63f17c26f..b32f51b65 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -22,4 +22,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest(timeoutTicks = 300) + fun meStorage(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua index b44336379..b7378101f 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -8,12 +8,14 @@ test.assert(isOnline, "Bridge is not connected/system is not online") validEnergy = bridge.getEnergyUsage() > 24 test.assert(validEnergy, tostring(bridge.getEnergyUsage()) .. " Consumption does not seem right") -stickFilter = {name="minecraft:stick"} +-- The count is used for the crafting filter +waterFilter = {name="minecraft:water"} +stickFilter = {name="minecraft:stick", count=5} planksFilter = {name="minecraft:oak_planks"} logFilter = {name="minecraft:oak_log"} isItemCrafting = bridge.isItemCrafting(stickFilter) -test.assert(isItemCrafting == true, "There shouldn't be a crafting job") +test.assert(isItemCrafting == false, "There shouldn't be a crafting job") -- Should be true. We have a pattern for it. isItemCraftable = bridge.isItemCraftable(stickFilter) @@ -28,3 +30,50 @@ test.assert(isItemCraftable == false, "Log should not be craftable") isItemCraftable = bridge.getItem(planksFilter).isCraftable test.assert(isItemCraftable == true, "Planks should be craftable") +stickCount = bridge.getItem(stickFilter).amount +test.assert(stickCount == 0, "We should not have sticks") + +craftingSuccessful = bridge.craftItem(stickFilter) +test.assert(craftingSuccessful, "Crafting failed") + +sleep(0.1) + +isItemCrafting = bridge.isItemCrafting(stickFilter) +test.assert(isItemCrafting, "There should be a crafting job") +-- Wait for the crafting to finish +sleep(1) + +-- A filter for 5 sticks should craft 8 sticks since we get 4 sticks per recipe +stickCount = bridge.getItem(stickFilter).amount +test.assert(stickCount == 8, "We should have 8 sticks") + +-- There is no getFluid function, so we need to do it like this +waterCount = bridge.listCraftableFluid()[1].amount +test.assert(waterCount == 0, "We should not have water") + +craftingSuccessful = bridge.craftFluid(waterFilter) +test.assert(craftingSuccessful, "Crafting failed") + +-- We can't test if the amount of the water has increased since we don't have an actual way to craft water in vanilla. +-- We just have the pattern which uses a dummy recipe with one log to craft 1B water. The log ist just transferred to a chest + +-- But we can test if there is a job +-- Well... if we would have a function for that... +-- isFluidCrafting = bridge.isItemCrafting(waterFilter) +-- test.assert(isFluidCrafting, "There should be a crafting job") + +cpus = bridge.getCraftingCPUs() +test.assert(#cpus == 3, "There should be three CPUs") + +cpuOne = nil +for i, cpu in ipairs(cpus) do + if cpu.name == "CPUOne" then + cpuOne = cpu + end +end +test.assert(cpuOne.isBusy == false, "CPU 1 should not be busy") +test.assert(cpuOne.storage == 131072, "CPU 1 should have 131072 bytes of storage") +test.assert(cpuOne.coProcessors == 1, "CPU 1 should have one CO-CPU") +test.assert(cpuOne.name == "CPUOne", "CPU 1 name should be CPUOne") +test.assert(cpuOne.selectionMode == "PLAYER_ONLY", "CPU 1 selectionMode should be PLAYER_ONLY") + diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua new file mode 100644 index 000000000..ddb8dbd1d --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua @@ -0,0 +1,9 @@ +sleep(4) +bridge = peripheral.wrap("bottom") +test.assert(bridge, "Peripheral not found") + +isOnline = bridge.isConnected() +test.assert(isOnline, "Bridge is not connected/system is not online") + +validEnergy = bridge.getEnergyUsage() > 24 +test.assert(validEnergy, tostring(bridge.getEnergyUsage()) .. " Consumption does not seem right") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt index 148fbf2f3..5b346e824 100644 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mecrafting.snbt @@ -30,10 +30,10 @@ {pos: [0, 1, 0], state: "minecraft:air"}, {pos: [0, 1, 1], state: "minecraft:air"}, {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:anvil{facing:west}"}, {pos: [0, 1, 4], state: "minecraft:air"}, {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_planks"}, {"#c": "ae2:i", id: "minecraft:oak_log"}]}}, item1: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, online: 1b}}}, + {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_log"}, {"#c": "ae2:i", id: "minecraft:oak_planks"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "empty"}, online: 1b}}}, {pos: [1, 1, 2], state: "advancedperipherals:me_bridge{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[ME Bridge]"}, Items: [], id: "advancedperipherals:me_bridge"}}, {pos: [1, 1, 3], state: "minecraft:air"}, {pos: [1, 1, 4], state: "minecraft:air"}, @@ -63,7 +63,7 @@ {pos: [1, 2, 3], state: "minecraft:air"}, {pos: [1, 2, 4], state: "minecraft:air"}, {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {blankPattern: [{Count: 60b, Slot: 0, id: "ae2:blank_pattern"}], encodedInputs: [{}, {"#": 1L, "#c": "ae2:i", id: "ae2:white_smart_dense_cable"}], encodedOutputs: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}], filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "PROCESSING", sort_by: "AMOUNT", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, + {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {blankPattern: [{Count: 59b, Slot: 0, id: "ae2:blank_pattern"}], encodedInputs: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}], encodedOutputs: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}], filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "PROCESSING", sort_by: "AMOUNT", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, {pos: [2, 2, 3], state: "minecraft:air"}, {pos: [2, 2, 4], state: "minecraft:air"}, @@ -85,7 +85,7 @@ {pos: [1, 3, 0], state: "minecraft:air"}, {pos: [1, 3, 1], state: "minecraft:air"}, {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "ae2:crafting_accelerator{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, customName: "CPUOne", id: "ae2:crafting_unit", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, {pos: [1, 3, 4], state: "minecraft:air"}, {pos: [2, 3, 0], state: "minecraft:air"}, {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, @@ -110,7 +110,7 @@ {pos: [1, 4, 0], state: "minecraft:air"}, {pos: [1, 4, 1], state: "minecraft:air"}, {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "PLAYER_ONLY", customName: "CPUOne", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, {pos: [1, 4, 4], state: "minecraft:air"}, {pos: [2, 4, 0], state: "minecraft:air"}, {pos: [2, 4, 1], state: "minecraft:air"}, @@ -135,7 +135,7 @@ {pos: [1, 5, 0], state: "minecraft:air"}, {pos: [1, 5, 1], state: "minecraft:air"}, {pos: [1, 5, 2], state: "minecraft:air"}, - {pos: [1, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, customName: "CPUOne", id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, {pos: [1, 5, 4], state: "minecraft:air"}, {pos: [2, 5, 0], state: "minecraft:air"}, {pos: [2, 5, 1], state: "minecraft:air"}, @@ -183,18 +183,18 @@ {pos: [0, 7, 3], state: "minecraft:air"}, {pos: [0, 7, 4], state: "minecraft:air"}, {pos: [1, 7, 0], state: "minecraft:air"}, - {pos: [1, 7, 1], state: "minecraft:air"}, - {pos: [1, 7, 2], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {}], out: {Count: 1b, id: "minecraft:oak_pressure_plate"}, recipe: "minecraft:oak_pressure_plate", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [1, 7, 1], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], id: "minecraft:chest"}}, + {pos: [1, 7, 2], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "SOUTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {}], out: {Count: 1b, id: "minecraft:oak_pressure_plate"}, recipe: "minecraft:oak_pressure_plate", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, {pos: [1, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, {pos: [1, 7, 4], state: "minecraft:air"}, {pos: [2, 7, 0], state: "minecraft:air"}, - {pos: [2, 7, 1], state: "minecraft:air"}, - {pos: [2, 7, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsEast: 0, channelsSouth: 0, channelsWest: 0, connections: ["down", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 7, 1], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "WEST", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:processing_pattern", tag: {in: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}], out: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [2, 7, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsEast: 0, channelsNorth: 0, channelsSouth: 0, channelsWest: 0, connections: ["down", "north", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, {pos: [2, 7, 3], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}], out: {Count: 4b, id: "minecraft:stick"}, recipe: "minecraft:stick", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, {pos: [2, 7, 4], state: "minecraft:air"}, {pos: [3, 7, 0], state: "minecraft:air"}, {pos: [3, 7, 1], state: "minecraft:air"}, - {pos: [3, 7, 2], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {Count: 1b, id: "minecraft:oak_log"}, {}, {}, {}, {}, {}], out: {Count: 4b, id: "minecraft:oak_planks"}, recipe: "minecraft:oak_planks", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [3, 7, 2], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "SOUTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {Count: 1b, id: "minecraft:oak_log"}, {}, {}, {}, {}, {}], out: {Count: 4b, id: "minecraft:oak_planks"}, recipe: "minecraft:oak_planks", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, {pos: [3, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, {pos: [3, 7, 4], state: "minecraft:air"}, {pos: [4, 7, 0], state: "minecraft:air"}, @@ -257,6 +257,7 @@ palette: [ "minecraft:polished_andesite", "minecraft:air", + "minecraft:anvil{facing:west}", "ae2:drive", "advancedperipherals:me_bridge{orientation:up_east}", "ae2:controller{state:online,type:block}", @@ -264,8 +265,11 @@ "ae2:creative_energy_cell", "computercraft:computer_advanced{facing:north,state:blinking}", "ae2:cable_bus{light_level:9,waterlogged:false}", + "ae2:crafting_accelerator{formed:true,powered:true}", "ae2:64k_crafting_storage{formed:true,powered:true}", - "ae2:pattern_provider{omnidirectional:true}", - "ae2:molecular_assembler{powered:true}" + "minecraft:chest{facing:north,type:single,waterlogged:false}", + "ae2:pattern_provider{omnidirectional:false}", + "ae2:molecular_assembler{powered:true}", + "ae2:pattern_provider{omnidirectional:true}" ] } diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt new file mode 100644 index 000000000..5f2106f88 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt @@ -0,0 +1,273 @@ +{ + DataVersion: 3120, + size: [5, 10, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_log"}, {"#c": "ae2:i", id: "minecraft:oak_planks"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "empty"}, online: 1b}}}, + {pos: [1, 1, 2], state: "advancedperipherals:me_bridge{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[ME Bridge]"}, Items: [], id: "advancedperipherals:me_bridge"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "ae2:controller{state:online,type:block}", nbt: {ForgeCaps: {}, id: "ae2:controller", internalCurrentPower: 0.0d, proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [2, 1, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsNorth: 0, channelsUp: 0, channelsWest: 0, connections: ["up", "north", "west"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "ae2:creative_energy_cell", nbt: {ForgeCaps: {}, forward: "WEST", id: "ae2:creative_energy_cell", proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.mestorage", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {blankPattern: [{Count: 59b, Slot: 0, id: "ae2:blank_pattern"}], encodedInputs: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}], encodedOutputs: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}], filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "PROCESSING", sort_by: "AMOUNT", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, + {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, + {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsSouth: 0, channelsUp: 0, connections: ["down", "up", "south"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 4, 3], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsEast: 0, channelsNorth: 0, channelsSouth: 0, channelsWest: 0, connections: ["north", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 4, 4], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [0, 7, 0], state: "minecraft:air"}, + {pos: [0, 7, 1], state: "minecraft:air"}, + {pos: [0, 7, 2], state: "minecraft:air"}, + {pos: [0, 7, 3], state: "minecraft:air"}, + {pos: [0, 7, 4], state: "minecraft:air"}, + {pos: [1, 7, 0], state: "minecraft:air"}, + {pos: [1, 7, 1], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], id: "minecraft:chest"}}, + {pos: [1, 7, 2], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "SOUTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {}], out: {Count: 1b, id: "minecraft:oak_pressure_plate"}, recipe: "minecraft:oak_pressure_plate", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [1, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [1, 7, 4], state: "minecraft:air"}, + {pos: [2, 7, 0], state: "minecraft:air"}, + {pos: [2, 7, 1], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "WEST", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:processing_pattern", tag: {in: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}], out: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [2, 7, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsEast: 0, channelsNorth: 0, channelsSouth: 0, channelsWest: 0, connections: ["down", "north", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 7, 3], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}], out: {Count: 4b, id: "minecraft:stick"}, recipe: "minecraft:stick", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [2, 7, 4], state: "minecraft:air"}, + {pos: [3, 7, 0], state: "minecraft:air"}, + {pos: [3, 7, 1], state: "minecraft:air"}, + {pos: [3, 7, 2], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "SOUTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {Count: 1b, id: "minecraft:oak_log"}, {}, {}, {}, {}, {}], out: {Count: 4b, id: "minecraft:oak_planks"}, recipe: "minecraft:oak_planks", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [3, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 7, 4], state: "minecraft:air"}, + {pos: [4, 7, 0], state: "minecraft:air"}, + {pos: [4, 7, 1], state: "minecraft:air"}, + {pos: [4, 7, 2], state: "minecraft:air"}, + {pos: [4, 7, 3], state: "minecraft:air"}, + {pos: [4, 7, 4], state: "minecraft:air"}, + {pos: [0, 8, 0], state: "minecraft:air"}, + {pos: [0, 8, 1], state: "minecraft:air"}, + {pos: [0, 8, 2], state: "minecraft:air"}, + {pos: [0, 8, 3], state: "minecraft:air"}, + {pos: [0, 8, 4], state: "minecraft:air"}, + {pos: [1, 8, 0], state: "minecraft:air"}, + {pos: [1, 8, 1], state: "minecraft:air"}, + {pos: [1, 8, 2], state: "minecraft:air"}, + {pos: [1, 8, 3], state: "minecraft:air"}, + {pos: [1, 8, 4], state: "minecraft:air"}, + {pos: [2, 8, 0], state: "minecraft:air"}, + {pos: [2, 8, 1], state: "minecraft:air"}, + {pos: [2, 8, 2], state: "minecraft:air"}, + {pos: [2, 8, 3], state: "minecraft:air"}, + {pos: [2, 8, 4], state: "minecraft:air"}, + {pos: [3, 8, 0], state: "minecraft:air"}, + {pos: [3, 8, 1], state: "minecraft:air"}, + {pos: [3, 8, 2], state: "minecraft:air"}, + {pos: [3, 8, 3], state: "minecraft:air"}, + {pos: [3, 8, 4], state: "minecraft:air"}, + {pos: [4, 8, 0], state: "minecraft:air"}, + {pos: [4, 8, 1], state: "minecraft:air"}, + {pos: [4, 8, 2], state: "minecraft:air"}, + {pos: [4, 8, 3], state: "minecraft:air"}, + {pos: [4, 8, 4], state: "minecraft:air"}, + {pos: [0, 9, 0], state: "minecraft:air"}, + {pos: [0, 9, 1], state: "minecraft:air"}, + {pos: [0, 9, 2], state: "minecraft:air"}, + {pos: [0, 9, 3], state: "minecraft:air"}, + {pos: [0, 9, 4], state: "minecraft:air"}, + {pos: [1, 9, 0], state: "minecraft:air"}, + {pos: [1, 9, 1], state: "minecraft:air"}, + {pos: [1, 9, 2], state: "minecraft:air"}, + {pos: [1, 9, 3], state: "minecraft:air"}, + {pos: [1, 9, 4], state: "minecraft:air"}, + {pos: [2, 9, 0], state: "minecraft:air"}, + {pos: [2, 9, 1], state: "minecraft:air"}, + {pos: [2, 9, 2], state: "minecraft:air"}, + {pos: [2, 9, 3], state: "minecraft:air"}, + {pos: [2, 9, 4], state: "minecraft:air"}, + {pos: [3, 9, 0], state: "minecraft:air"}, + {pos: [3, 9, 1], state: "minecraft:air"}, + {pos: [3, 9, 2], state: "minecraft:air"}, + {pos: [3, 9, 3], state: "minecraft:air"}, + {pos: [3, 9, 4], state: "minecraft:air"}, + {pos: [4, 9, 0], state: "minecraft:air"}, + {pos: [4, 9, 1], state: "minecraft:air"}, + {pos: [4, 9, 2], state: "minecraft:air"}, + {pos: [4, 9, 3], state: "minecraft:air"}, + {pos: [4, 9, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "ae2:drive", + "advancedperipherals:me_bridge{orientation:up_east}", + "ae2:controller{state:online,type:block}", + "ae2:cable_bus{light_level:0,waterlogged:false}", + "ae2:creative_energy_cell", + "computercraft:computer_advanced{facing:north,state:blinking}", + "ae2:cable_bus{light_level:9,waterlogged:false}", + "ae2:64k_crafting_storage{formed:true,powered:true}", + "minecraft:chest{facing:north,type:single,waterlogged:false}", + "ae2:pattern_provider{omnidirectional:false}", + "ae2:molecular_assembler{powered:true}", + "ae2:pattern_provider{omnidirectional:true}" + ] +} From 578ccd842665415cdfb20cb7c8f43700b8a2c5cf Mon Sep 17 00:00:00 2001 From: Srendi Date: Thu, 9 May 2024 00:43:29 +0200 Subject: [PATCH 22/61] Finished the me storage test --- .../tests/peripheraltest.mestorage.lua | 65 +++++++++++++++++- .../structures/peripheraltest.mestorage.snbt | 67 +++++++++---------- 2 files changed, 95 insertions(+), 37 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua index ddb8dbd1d..e535e299a 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua @@ -5,5 +5,66 @@ test.assert(bridge, "Peripheral not found") isOnline = bridge.isConnected() test.assert(isOnline, "Bridge is not connected/system is not online") -validEnergy = bridge.getEnergyUsage() > 24 -test.assert(validEnergy, tostring(bridge.getEnergyUsage()) .. " Consumption does not seem right") +energyUsage = bridge.getEnergyUsage() +test.assert(energyUsage > 18, tostring(energyUsage) .. " Consumption does not seem right") + +maxEnergyStorage = bridge.getMaxEnergyStorage() +test.assert(maxEnergyStorage == 1608800, tostring(maxEnergyStorage) .. " Max Energy Storage does not seem right") + +energyStorage = bridge.getEnergyStorage() +test.assert(energyStorage > 1590000, tostring(energyStorage) .. " Energy Storage does not seem right") + +totalItemStorage = bridge.getTotalItemStorage() +test.assert(totalItemStorage == 67264, "Total item storage is not valid") + +totalFluidStorage = bridge.getTotalFluidStorage() +test.assert(totalFluidStorage == 81536, "Total fluid storage is not valid") + +usedItemStorage = bridge.getUsedItemStorage() +test.assert(usedItemStorage == 1120, "Used item storage is not valid") + +usedFluidStorage = bridge.getUsedFluidStorage() +test.assert(usedFluidStorage == 2025, "Used fluid storage is not valid") + +availableItemStorage = bridge.getAvailableItemStorage() +test.assert(availableItemStorage == 66144, "Available item storage is not valid") + +availableFluidStorage = bridge.getAvailableFluidStorage() +test.assert(availableFluidStorage == 79511, "Available fluid storage is not valid") + +cells = bridge.listCells() +test.assert(#cells == 2, "There should be 2 cells") + +itemCell = nil +fluidCell = nil +for _, cell in pairs(cells) do + if cell.cellType == "item" then + itemCell = cell + end +end +for _, cell in pairs(cells) do + if cell.cellType == "fluid" then + fluidCell = cell + end +end + +test.assert(itemCell, "Item cell not found") +test.assert(fluidCell, "Fluid cell not found") + +itemCellBytes = itemCell.totalBytes +test.assert(itemCellBytes == 65536, "Item cell bytes is not valid") + +fluidCellBytes = fluidCell.totalBytes +test.assert(fluidCellBytes == 65536, "Fluid cell bytes is not valid") + +itemCellItem = itemCell.item +test.assert(itemCellItem == "ae2:item_storage_cell_64k", "Item cell item not found") + +fluidCellItem = fluidCell.item +test.assert(fluidCellItem == "ae2:fluid_storage_cell_64k", "Fluid cell item not found") + +itemCellBytesPerType = itemCell.bytesPerType +test.assert(itemCellBytesPerType == 512, "Item cell bytes per type is not valid") + +fluidCellBytesPerType = fluidCell.bytesPerType +test.assert(fluidCellBytesPerType == 512, "Fluid cell bytes per type is not valid") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt index 5f2106f88..211cc3153 100644 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.mestorage.snbt @@ -33,19 +33,19 @@ {pos: [0, 1, 3], state: "minecraft:air"}, {pos: [0, 1, 4], state: "minecraft:air"}, {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_log"}, {"#c": "ae2:i", id: "minecraft:oak_planks"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "empty"}, online: 1b}}}, + {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_log"}, {"#c": "ae2:i", id: "minecraft:oak_planks"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {amts: [L; 1000L, 1000L], ic: 2000L, keys: [{"#c": "ae2:f", id: "minecraft:water"}, {"#c": "ae2:f", id: "minecraft:lava"}]}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "not_empty"}, online: 1b}}}, {pos: [1, 1, 2], state: "advancedperipherals:me_bridge{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[ME Bridge]"}, Items: [], id: "advancedperipherals:me_bridge"}}, {pos: [1, 1, 3], state: "minecraft:air"}, {pos: [1, 1, 4], state: "minecraft:air"}, {pos: [2, 1, 0], state: "minecraft:air"}, {pos: [2, 1, 1], state: "ae2:controller{state:online,type:block}", nbt: {ForgeCaps: {}, id: "ae2:controller", internalCurrentPower: 0.0d, proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, - {pos: [2, 1, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsNorth: 0, channelsUp: 0, channelsWest: 0, connections: ["up", "north", "west"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsNorth: 0, channelsSouth: 0, channelsUp: 0, channelsWest: 0, connections: ["up", "north", "south", "west"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 1, 3], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsNorth: 0, connections: ["north"], missingChannel: 0b, powered: 1b}}, east: {access: "READ_WRITE", filter_on_extract: "YES", fuzzy_mode: "IGNORE_ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:storage_bus", priority: 0, storage_filter: "EXTRACTABLE_ONLY", visual: {missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", south: {access: "READ_WRITE", filter_on_extract: "YES", fuzzy_mode: "IGNORE_ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:storage_bus", priority: 0, storage_filter: "EXTRACTABLE_ONLY", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, + {pos: [2, 1, 4], state: "ae2:sky_stone_tank", nbt: {Amount: 1000, FluidName: "minecraft:lava", ForgeCaps: {}, forward: "WEST", id: "ae2:sky_tank", up: "UP", visual: {}}}, {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "ae2:creative_energy_cell", nbt: {ForgeCaps: {}, forward: "WEST", id: "ae2:creative_energy_cell", proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 1, 1], state: "ae2:dense_energy_cell{fullness:4}", nbt: {ForgeCaps: {}, id: "ae2:dense_energy_cell", internalCurrentPower: 1599133.46875d, proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:chest{facing:west,type:single,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [{Count: 32b, Slot: 0b, id: "ae2:storage_bus"}], id: "minecraft:chest"}}, {pos: [3, 1, 4], state: "minecraft:air"}, {pos: [4, 1, 0], state: "minecraft:air"}, {pos: [4, 1, 1], state: "minecraft:air"}, @@ -63,8 +63,8 @@ {pos: [1, 2, 3], state: "minecraft:air"}, {pos: [1, 2, 4], state: "minecraft:air"}, {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {blankPattern: [{Count: 59b, Slot: 0, id: "ae2:blank_pattern"}], encodedInputs: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}], encodedOutputs: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}], filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "PROCESSING", sort_by: "AMOUNT", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, - {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {blankPattern: [{Count: 59b, Slot: 0, id: "ae2:blank_pattern"}], encodedInputs: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}], encodedOutputs: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}], filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "PROCESSING", sort_by: "AMOUNT", sort_direction: "DESCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, {pos: [2, 2, 3], state: "minecraft:air"}, {pos: [2, 2, 4], state: "minecraft:air"}, {pos: [3, 2, 0], state: "minecraft:air"}, @@ -88,8 +88,8 @@ {pos: [1, 3, 3], state: "minecraft:air"}, {pos: [1, 3, 4], state: "minecraft:air"}, {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, visual: {}}}, - {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 21L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "AMOUNT", sort_direction: "DESCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, {pos: [2, 3, 3], state: "minecraft:air"}, {pos: [2, 3, 4], state: "minecraft:air"}, {pos: [3, 3, 0], state: "minecraft:air"}, @@ -110,17 +110,17 @@ {pos: [1, 4, 0], state: "minecraft:air"}, {pos: [1, 4, 1], state: "minecraft:air"}, {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 4, 3], state: "minecraft:air"}, {pos: [1, 4, 4], state: "minecraft:air"}, {pos: [2, 4, 0], state: "minecraft:air"}, {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsSouth: 0, channelsUp: 0, connections: ["down", "up", "south"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, - {pos: [2, 4, 3], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsEast: 0, channelsNorth: 0, channelsSouth: 0, channelsWest: 0, connections: ["north", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, - {pos: [2, 4, 4], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, {pos: [3, 4, 0], state: "minecraft:air"}, {pos: [3, 4, 1], state: "minecraft:air"}, {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 1b, crafting_scheduling_mode: "ANY", id: "ae2:crafting_storage", inventory: [], proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 4, 3], state: "minecraft:air"}, {pos: [3, 4, 4], state: "minecraft:air"}, {pos: [4, 4, 0], state: "minecraft:air"}, {pos: [4, 4, 1], state: "minecraft:air"}, @@ -135,17 +135,17 @@ {pos: [1, 5, 0], state: "minecraft:air"}, {pos: [1, 5, 1], state: "minecraft:air"}, {pos: [1, 5, 2], state: "minecraft:air"}, - {pos: [1, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [1, 5, 3], state: "minecraft:air"}, {pos: [1, 5, 4], state: "minecraft:air"}, {pos: [2, 5, 0], state: "minecraft:air"}, {pos: [2, 5, 1], state: "minecraft:air"}, - {pos: [2, 5, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 5, 2], state: "minecraft:air"}, {pos: [2, 5, 3], state: "minecraft:air"}, - {pos: [2, 5, 4], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [2, 5, 4], state: "minecraft:air"}, {pos: [3, 5, 0], state: "minecraft:air"}, {pos: [3, 5, 1], state: "minecraft:air"}, {pos: [3, 5, 2], state: "minecraft:air"}, - {pos: [3, 5, 3], state: "ae2:64k_crafting_storage{formed:true,powered:true}", nbt: {ForgeCaps: {}, core: 0b, id: "ae2:crafting_storage", proxy: {g: 21L, k: -1L, p: 0}, visual: {}}}, + {pos: [3, 5, 3], state: "minecraft:air"}, {pos: [3, 5, 4], state: "minecraft:air"}, {pos: [4, 5, 0], state: "minecraft:air"}, {pos: [4, 5, 1], state: "minecraft:air"}, @@ -164,7 +164,7 @@ {pos: [1, 6, 4], state: "minecraft:air"}, {pos: [2, 6, 0], state: "minecraft:air"}, {pos: [2, 6, 1], state: "minecraft:air"}, - {pos: [2, 6, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 6, 2], state: "minecraft:air"}, {pos: [2, 6, 3], state: "minecraft:air"}, {pos: [2, 6, 4], state: "minecraft:air"}, {pos: [3, 6, 0], state: "minecraft:air"}, @@ -183,19 +183,19 @@ {pos: [0, 7, 3], state: "minecraft:air"}, {pos: [0, 7, 4], state: "minecraft:air"}, {pos: [1, 7, 0], state: "minecraft:air"}, - {pos: [1, 7, 1], state: "minecraft:chest{facing:north,type:single,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], id: "minecraft:chest"}}, - {pos: [1, 7, 2], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "SOUTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {}], out: {Count: 1b, id: "minecraft:oak_pressure_plate"}, recipe: "minecraft:oak_pressure_plate", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, - {pos: [1, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [1, 7, 1], state: "minecraft:air"}, + {pos: [1, 7, 2], state: "minecraft:air"}, + {pos: [1, 7, 3], state: "minecraft:air"}, {pos: [1, 7, 4], state: "minecraft:air"}, {pos: [2, 7, 0], state: "minecraft:air"}, - {pos: [2, 7, 1], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "WEST", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:processing_pattern", tag: {in: [{"#": 1L, "#c": "ae2:i", id: "minecraft:oak_log"}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}], out: [{"#": 1000L, "#c": "ae2:f", id: "minecraft:water"}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, - {pos: [2, 7, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 21L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsEast: 0, channelsNorth: 0, channelsSouth: 0, channelsWest: 0, connections: ["down", "north", "south", "west", "east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, - {pos: [2, 7, 3], state: "ae2:pattern_provider{omnidirectional:true}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "NORTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 1b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}, {}, {}, {Count: 1b, id: "minecraft:oak_planks"}], out: {Count: 4b, id: "minecraft:stick"}, recipe: "minecraft:stick", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, + {pos: [2, 7, 1], state: "minecraft:air"}, + {pos: [2, 7, 2], state: "minecraft:air"}, + {pos: [2, 7, 3], state: "minecraft:air"}, {pos: [2, 7, 4], state: "minecraft:air"}, {pos: [3, 7, 0], state: "minecraft:air"}, {pos: [3, 7, 1], state: "minecraft:air"}, - {pos: [3, 7, 2], state: "ae2:pattern_provider{omnidirectional:false}", nbt: {ForgeCaps: {}, blocking_mode: "NO", forward: "SOUTH", id: "ae2:pattern_provider", lock_crafting_mode: "NONE", omniDirectional: 0b, pattern_access_terminal: "YES", patterns: [{Count: 1b, Slot: 0, id: "ae2:crafting_pattern", tag: {in: [{}, {}, {}, {Count: 1b, id: "minecraft:oak_log"}, {}, {}, {}, {}, {}], out: {Count: 4b, id: "minecraft:oak_planks"}, recipe: "minecraft:oak_planks", substitute: 0b, substituteFluids: 1b}}], priority: 0, proxy: {g: 21L, k: -1L, p: 0}, returnInv: [], sendList: [], up: "UP", visual: {}}}, - {pos: [3, 7, 3], state: "ae2:molecular_assembler{powered:true}", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:molecular_assembler", inv: {item0: {}, item1: {}, item10: {}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, proxy: {g: 21L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 7, 2], state: "minecraft:air"}, + {pos: [3, 7, 3], state: "minecraft:air"}, {pos: [3, 7, 4], state: "minecraft:air"}, {pos: [4, 7, 0], state: "minecraft:air"}, {pos: [4, 7, 1], state: "minecraft:air"}, @@ -261,13 +261,10 @@ "advancedperipherals:me_bridge{orientation:up_east}", "ae2:controller{state:online,type:block}", "ae2:cable_bus{light_level:0,waterlogged:false}", - "ae2:creative_energy_cell", + "ae2:sky_stone_tank", + "ae2:dense_energy_cell{fullness:4}", + "minecraft:chest{facing:west,type:single,waterlogged:false}", "computercraft:computer_advanced{facing:north,state:blinking}", - "ae2:cable_bus{light_level:9,waterlogged:false}", - "ae2:64k_crafting_storage{formed:true,powered:true}", - "minecraft:chest{facing:north,type:single,waterlogged:false}", - "ae2:pattern_provider{omnidirectional:false}", - "ae2:molecular_assembler{powered:true}", - "ae2:pattern_provider{omnidirectional:true}" + "ae2:cable_bus{light_level:9,waterlogged:false}" ] } From 233a194fad9bf3b09f6afb76071c7e26154228d7 Mon Sep 17 00:00:00 2001 From: Srendi Date: Sat, 11 May 2024 01:25:38 +0200 Subject: [PATCH 23/61] Added me transfer tests to test the integrity of our item export and import tests --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.mecrafting.lua | 6 + .../tests/peripheraltest.mestorage.lua | 7 + .../tests/peripheraltest.metransfer.lua | 83 ++++++ .../structures/peripheraltest.metransfer.snbt | 275 ++++++++++++++++++ 5 files changed, 376 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index b32f51b65..6b05cd508 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -27,4 +27,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest(timeoutTicks = 300) + fun meTransfer(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua index b7378101f..a9868886d 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -1,3 +1,9 @@ +--- +--- Advanced Peripherals ME Bridge crafting tests +--- Covers `isConnected`, `getEnergyUsage`, `isItemCrafting`, `isItemCraftable`, +--- `getItem`, `craftItem`, `listCraftableFluid`, `craftFluid`, `getCraftingCPUs`, +--- + sleep(4) bridge = peripheral.wrap("bottom") test.assert(bridge, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua index e535e299a..cdac21a34 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua @@ -1,3 +1,10 @@ +--- +--- Advanced Peripherals ME Bridge storage tests +--- Covers `isConnected`, `getEnergyUsage`, `getMaxEnergyStorage`, `getEnergyStorage`, +--- `getTotalItemStorage`, `getTotalFluidStorage`, `getUsedItemStorage`, `getUsedFluidStorage`, +--- `getAvailableItemStorage`, `getAvailableFluidStorage`, `listCells`, +--- + sleep(4) bridge = peripheral.wrap("bottom") test.assert(bridge, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua new file mode 100644 index 000000000..f414733f6 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua @@ -0,0 +1,83 @@ +--- +--- Advanced Peripherals ME Bridge transfer tests +--- Covers `isConnected`, `getEnergyUsage`, `getItem`, `exportItemToPeripheral`, `exportItem`, +--- `importItem`, `importItemFromPeripheral` +--- + +sleep(4) +bridge = peripheral.wrap("meBridge_3") +chest = peripheral.wrap("minecraft:chest_2") +test.assert(bridge, "Peripheral not found") +test.assert(chest, "Chest not found") + +isOnline = bridge.isConnected() +test.assert(isOnline, "Bridge is not connected/system is not online") + +energyUsage = bridge.getEnergyUsage() +test.assert(energyUsage > 17, tostring(energyUsage) .. " Consumption does not seem right") + +planksFilter = {name="minecraft:oak_planks", count=5} +logFilter = {name="minecraft:oak_log", count=8} + +exported, err = bridge.exportItemToPeripheral(planksFilter, peripheral.getName(chest)) +test.assert(exported == 5, "Export failed ".. (err or "")) + +planksItem = bridge.getItem(planksFilter) +test.assert(planksItem.amount == 251, "We should have 251 planks") + +chestPlanks = nil +for slot, item in pairs(chest.list()) do + if item.name == "minecraft:oak_planks" then + chestPlanks = item + end +end + +test.assert(chestPlanks, "Planks not found in chest") +test.assert(chestPlanks.count == 5, "We should have 5 planks in the chest") + +exported, err = bridge.exportItem(planksFilter, "front") +test.assert(exported == 5, "Export failed ".. (err or "")) + +planksItem = bridge.getItem(planksFilter) +test.assert(planksItem.amount == 246, "We should have 246 planks") + +for slot, item in pairs(chest.list()) do + if item.name == "minecraft:oak_planks" then + chestPlanks = item + end +end + +test.assert(chestPlanks, "Planks not found in chest") +test.assert(chestPlanks.count == 10, "We should have 5 planks in the chest") + +imported, err = bridge.importItemFromPeripheral(logFilter, peripheral.getName(chest)) +test.assert(imported == 8, "import failed ".. (err or "")) + +logsItem = bridge.getItem(logFilter) +test.assert(logsItem.amount == 264, "We should have 264 logs") + +chestLogs = nil +for slot, item in pairs(chest.list()) do + if item.name == "minecraft:oak_log" then + chestLogs = item + end +end + +test.assert(chestLogs, "Logs not found in chest") +test.assert(chestLogs.count == 56, "We should have 56 logs in the chest") + +imported, err = bridge.importItem(logFilter, "south") +test.assert(imported == 8, "import failed ".. (err or "")) + +logsItem = bridge.getItem(logFilter) +test.assert(logsItem.amount == 272, "We should have 272 logs") + +chestLogs = nil +for slot, item in pairs(chest.list()) do + if item.name == "minecraft:oak_log" then + chestLogs = item + end +end + +test.assert(chestLogs, "Logs not found in chest") +test.assert(chestLogs.count == 48, "We should have 48 logs in the chest") \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt new file mode 100644 index 000000000..8c10cfb87 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt @@ -0,0 +1,275 @@ +{ + DataVersion: 3120, + size: [5, 10, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_planks"}, {"#c": "ae2:i", id: "minecraft:oak_log"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 1054L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "empty"}, online: 1b}}}, + {pos: [1, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:true,up:true,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, PeirpheralAccess: 1b, PeripheralId: 3, PeripheralType: "computer", id: "computercraft:cable"}}, + {pos: [1, 1, 3], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [1, 1, 4], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:false,up:true,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, PeirpheralAccess: 0b, id: "computercraft:cable"}}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "ae2:controller{state:online,type:block}", nbt: {ForgeCaps: {}, id: "ae2:controller", internalCurrentPower: 0.0d, proxy: {g: 1054L, k: -1L, p: 0}, visual: {}}}, + {pos: [2, 1, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsNorth: 0, channelsUp: 0, connections: ["up", "north"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, + {pos: [2, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:false,up:true,waterlogged:false,west:true}", nbt: {ForgeCaps: {}, PeirpheralAccess: 1b, PeripheralId: 3, PeripheralType: "meBridge", id: "computercraft:cable"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "ae2:creative_energy_cell", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:creative_energy_cell", proxy: {g: 1054L, k: -1L, p: 0}, up: "UP", visual: {}}}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.metransfer", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [1, 2, 3], state: "ae2:sky_stone_tank", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:sky_tank", up: "UP", visual: {}}}, + {pos: [1, 2, 4], state: "computercraft:wired_modem_full{modem:false,peripheral:true}", nbt: {ForgeCaps: {}, PeripheralAccess: 1b, PeripheralId2: 1, PeripheralId5: 2, PeripheralType2: "ae2:sky_tank", PeripheralType5: "minecraft:chest", id: "computercraft:wired_modem_full"}}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "CRAFTING", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsSouth: 0, channelsUp: 0, connections: ["down", "up", "south"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 2, 3], state: "advancedperipherals:me_bridge{orientation:south_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[ME Bridge]"}, Items: [], id: "advancedperipherals:me_bridge"}}, + {pos: [2, 2, 4], state: "minecraft:chest{facing:south,type:single,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [{Count: 64b, Slot: 26b, id: "minecraft:oak_log"}], id: "minecraft:chest"}}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "minecraft:air"}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "minecraft:air"}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "minecraft:air"}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "minecraft:air"}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "minecraft:air"}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [0, 7, 0], state: "minecraft:air"}, + {pos: [0, 7, 1], state: "minecraft:air"}, + {pos: [0, 7, 2], state: "minecraft:air"}, + {pos: [0, 7, 3], state: "minecraft:air"}, + {pos: [0, 7, 4], state: "minecraft:air"}, + {pos: [1, 7, 0], state: "minecraft:air"}, + {pos: [1, 7, 1], state: "minecraft:air"}, + {pos: [1, 7, 2], state: "minecraft:air"}, + {pos: [1, 7, 3], state: "minecraft:air"}, + {pos: [1, 7, 4], state: "minecraft:air"}, + {pos: [2, 7, 0], state: "minecraft:air"}, + {pos: [2, 7, 1], state: "minecraft:air"}, + {pos: [2, 7, 2], state: "minecraft:air"}, + {pos: [2, 7, 3], state: "minecraft:air"}, + {pos: [2, 7, 4], state: "minecraft:air"}, + {pos: [3, 7, 0], state: "minecraft:air"}, + {pos: [3, 7, 1], state: "minecraft:air"}, + {pos: [3, 7, 2], state: "minecraft:air"}, + {pos: [3, 7, 3], state: "minecraft:air"}, + {pos: [3, 7, 4], state: "minecraft:air"}, + {pos: [4, 7, 0], state: "minecraft:air"}, + {pos: [4, 7, 1], state: "minecraft:air"}, + {pos: [4, 7, 2], state: "minecraft:air"}, + {pos: [4, 7, 3], state: "minecraft:air"}, + {pos: [4, 7, 4], state: "minecraft:air"}, + {pos: [0, 8, 0], state: "minecraft:air"}, + {pos: [0, 8, 1], state: "minecraft:air"}, + {pos: [0, 8, 2], state: "minecraft:air"}, + {pos: [0, 8, 3], state: "minecraft:air"}, + {pos: [0, 8, 4], state: "minecraft:air"}, + {pos: [1, 8, 0], state: "minecraft:air"}, + {pos: [1, 8, 1], state: "minecraft:air"}, + {pos: [1, 8, 2], state: "minecraft:air"}, + {pos: [1, 8, 3], state: "minecraft:air"}, + {pos: [1, 8, 4], state: "minecraft:air"}, + {pos: [2, 8, 0], state: "minecraft:air"}, + {pos: [2, 8, 1], state: "minecraft:air"}, + {pos: [2, 8, 2], state: "minecraft:air"}, + {pos: [2, 8, 3], state: "minecraft:air"}, + {pos: [2, 8, 4], state: "minecraft:air"}, + {pos: [3, 8, 0], state: "minecraft:air"}, + {pos: [3, 8, 1], state: "minecraft:air"}, + {pos: [3, 8, 2], state: "minecraft:air"}, + {pos: [3, 8, 3], state: "minecraft:air"}, + {pos: [3, 8, 4], state: "minecraft:air"}, + {pos: [4, 8, 0], state: "minecraft:air"}, + {pos: [4, 8, 1], state: "minecraft:air"}, + {pos: [4, 8, 2], state: "minecraft:air"}, + {pos: [4, 8, 3], state: "minecraft:air"}, + {pos: [4, 8, 4], state: "minecraft:air"}, + {pos: [0, 9, 0], state: "minecraft:air"}, + {pos: [0, 9, 1], state: "minecraft:air"}, + {pos: [0, 9, 2], state: "minecraft:air"}, + {pos: [0, 9, 3], state: "minecraft:air"}, + {pos: [0, 9, 4], state: "minecraft:air"}, + {pos: [1, 9, 0], state: "minecraft:air"}, + {pos: [1, 9, 1], state: "minecraft:air"}, + {pos: [1, 9, 2], state: "minecraft:air"}, + {pos: [1, 9, 3], state: "minecraft:air"}, + {pos: [1, 9, 4], state: "minecraft:air"}, + {pos: [2, 9, 0], state: "minecraft:air"}, + {pos: [2, 9, 1], state: "minecraft:air"}, + {pos: [2, 9, 2], state: "minecraft:air"}, + {pos: [2, 9, 3], state: "minecraft:air"}, + {pos: [2, 9, 4], state: "minecraft:air"}, + {pos: [3, 9, 0], state: "minecraft:air"}, + {pos: [3, 9, 1], state: "minecraft:air"}, + {pos: [3, 9, 2], state: "minecraft:air"}, + {pos: [3, 9, 3], state: "minecraft:air"}, + {pos: [3, 9, 4], state: "minecraft:air"}, + {pos: [4, 9, 0], state: "minecraft:air"}, + {pos: [4, 9, 1], state: "minecraft:air"}, + {pos: [4, 9, 2], state: "minecraft:air"}, + {pos: [4, 9, 3], state: "minecraft:air"}, + {pos: [4, 9, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "ae2:drive", + "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:true,up:true,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:false,up:true,waterlogged:false,west:false}", + "ae2:controller{state:online,type:block}", + "ae2:cable_bus{light_level:0,waterlogged:false}", + "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:false,up:true,waterlogged:false,west:true}", + "ae2:creative_energy_cell", + "computercraft:computer_advanced{facing:north,state:blinking}", + "ae2:sky_stone_tank", + "computercraft:wired_modem_full{modem:false,peripheral:true}", + "ae2:cable_bus{light_level:9,waterlogged:false}", + "advancedperipherals:me_bridge{orientation:south_up}", + "minecraft:chest{facing:south,type:single,waterlogged:false}" + ] +} From feb2c9a3d3012f4b99dae1422c5f355618d176c9 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 11 May 2024 16:52:04 +0200 Subject: [PATCH 24/61] Add game tests for Block Reader peripheral --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.blockreader.lua | 54 +++++++ .../peripheraltest.blockreader.snbt | 140 ++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.blockreader.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 6b05cd508..edc1b0b38 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -32,4 +32,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest + fun blockReader(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua new file mode 100644 index 000000000..89d320f80 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua @@ -0,0 +1,54 @@ +--- +--- Advanced Peripherals Block Reader tests +--- Covers `getBlockName`, `getBlockData`, `getBlockStates`, `isTileEntity` +--- + +function tablelength(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end + +-- Test Block Reader functions on a simple block +test.eq("blockReader", peripheral.getType("left"), "Peripheral should be blockReader") +simpleReader = peripheral.wrap("left") +test.assert(simpleReader, "Peripheral not found") + +test.eq("minecraft:polished_andesite", simpleReader.getBlockName(), "Block Name should be polished_andesite") +test.eq(nil, simpleReader.getBlockData(), "Block Data should be nil") +test.eq(false, simpleReader.isTileEntity(), "Block should not be a TileEntity") +test.eq(0, tablelength(simpleReader.getBlockStates()), "Block State should be empty") + +-- Test Block Reader functions on a stair block +test.eq("blockReader", peripheral.getType("back"), "Peripheral should be blockReader") +stairReader = peripheral.wrap("back") +test.assert(stairReader, "Peripheral not found") + +test.eq("minecraft:polished_andesite_stairs", stairReader.getBlockName(), "Block Name should be polished_andesite") +test.eq(nil, stairReader.getBlockData(), "Block Data should be nil") +test.assert(not stairReader.isTileEntity(), "Block should not be a TileEntity") +test.eq(4, tablelength(stairReader.getBlockStates()), "Block State should not be empty") + +test.eq("east", stairReader.getBlockStates()["facing"], "Stair Facing should be east") +test.eq("bottom", stairReader.getBlockStates()["half"], "Stair Half should be bottom") +test.eq("straight", stairReader.getBlockStates()["shape"], "Stair Shape should be straight") +test.assert(not stairReader.getBlockStates()["waterlogged"], "Stair Waterlogged should be false") + +-- Test Block Reader functions on a sign block +test.eq("blockReader", peripheral.getType("right"), "Peripheral should be blockReader") +signReader = peripheral.wrap("right") +test.assert(signReader, "Peripheral not found") + +test.eq("minecraft:oak_sign", signReader.getBlockName(), "Block Name should be polished_andesite") +test.neq(nil, signReader.getBlockData(), "Block Data should not be nil") +test.assert(signReader.isTileEntity(), "Block should be a TileEntity") +test.eq(2, tablelength(signReader.getBlockStates()), "Block State should not be empty") + +test.eq(4, signReader.getBlockStates()["rotation"], "Sign Rotation should be 4") +test.assert(not signReader.getBlockStates()["waterlogged"], "Sign Waterlogged should be false") + +test.eq("black", signReader.getBlockData()["Color"], "Sign Color should be black") +test.eq("{\"text\":\"this\"}", signReader.getBlockData()["Text1"], "Sign Text1 should be 'this'") +test.eq("{\"text\":\"is a\"}", signReader.getBlockData()["Text2"], "Sign Text2 should be 'is a'") +test.eq("{\"text\":\"test\"}", signReader.getBlockData()["Text3"], "Sign Text3 should be 'test'") +test.eq("{\"text\":\"sign\"}", signReader.getBlockData()["Text4"], "Sign Text4 should be 'sign'") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.blockreader.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.blockreader.snbt new file mode 100644 index 000000000..6cf8472da --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.blockreader.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "advancedperipherals:block_reader{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Block Reader]"}, Items: [], id: "advancedperipherals:block_reader"}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:off}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.blockreader", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "advancedperipherals:block_reader{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Block Reader]"}, Items: [], id: "advancedperipherals:block_reader"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "advancedperipherals:block_reader{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Block Reader]"}, Items: [], id: "advancedperipherals:block_reader"}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:oak_sign{rotation:4,waterlogged:false}", nbt: {Color: "black", ForgeCaps: {}, GlowingText: 0b, Text1: '{"text":"this"}', Text2: '{"text":"is a"}', Text3: '{"text":"test"}', Text4: '{"text":"sign"}', id: "minecraft:sign"}}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:false}"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "minecraft:polished_andesite_stairs{facing:east,half:bottom,shape:straight,waterlogged:false}", + "advancedperipherals:block_reader{orientation:up_east}", + "computercraft:computer_advanced{facing:west,state:off}", + "minecraft:oak_sign{rotation:4,waterlogged:false}" + ] +} From 0e4233097808b2ae83785e5142c8dba2d605a7a4 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 11 May 2024 16:59:36 +0200 Subject: [PATCH 25/61] Fix inconsistency in the code style for assert/eq on isTileEntity --- .../computer/tests/peripheraltest.blockreader.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua index 89d320f80..9778fb572 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua @@ -16,7 +16,7 @@ test.assert(simpleReader, "Peripheral not found") test.eq("minecraft:polished_andesite", simpleReader.getBlockName(), "Block Name should be polished_andesite") test.eq(nil, simpleReader.getBlockData(), "Block Data should be nil") -test.eq(false, simpleReader.isTileEntity(), "Block should not be a TileEntity") +test.assert(not simpleReader.isTileEntity(), "Block should not be a TileEntity") test.eq(0, tablelength(simpleReader.getBlockStates()), "Block State should be empty") -- Test Block Reader functions on a stair block From 7f9af5c36290acde0231a4ae0e6aefe914955148 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 11 May 2024 17:15:45 +0200 Subject: [PATCH 26/61] tablelength -> tableLength --- .../computer/tests/peripheraltest.blockreader.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua index 9778fb572..3d61e5466 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua @@ -3,7 +3,7 @@ --- Covers `getBlockName`, `getBlockData`, `getBlockStates`, `isTileEntity` --- -function tablelength(T) +function tableLength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count @@ -17,7 +17,7 @@ test.assert(simpleReader, "Peripheral not found") test.eq("minecraft:polished_andesite", simpleReader.getBlockName(), "Block Name should be polished_andesite") test.eq(nil, simpleReader.getBlockData(), "Block Data should be nil") test.assert(not simpleReader.isTileEntity(), "Block should not be a TileEntity") -test.eq(0, tablelength(simpleReader.getBlockStates()), "Block State should be empty") +test.eq(0, tableLength(simpleReader.getBlockStates()), "Block State should be empty") -- Test Block Reader functions on a stair block test.eq("blockReader", peripheral.getType("back"), "Peripheral should be blockReader") @@ -27,7 +27,7 @@ test.assert(stairReader, "Peripheral not found") test.eq("minecraft:polished_andesite_stairs", stairReader.getBlockName(), "Block Name should be polished_andesite") test.eq(nil, stairReader.getBlockData(), "Block Data should be nil") test.assert(not stairReader.isTileEntity(), "Block should not be a TileEntity") -test.eq(4, tablelength(stairReader.getBlockStates()), "Block State should not be empty") +test.eq(4, tableLength(stairReader.getBlockStates()), "Block State should not be empty") test.eq("east", stairReader.getBlockStates()["facing"], "Stair Facing should be east") test.eq("bottom", stairReader.getBlockStates()["half"], "Stair Half should be bottom") @@ -42,7 +42,7 @@ test.assert(signReader, "Peripheral not found") test.eq("minecraft:oak_sign", signReader.getBlockName(), "Block Name should be polished_andesite") test.neq(nil, signReader.getBlockData(), "Block Data should not be nil") test.assert(signReader.isTileEntity(), "Block should be a TileEntity") -test.eq(2, tablelength(signReader.getBlockStates()), "Block State should not be empty") +test.eq(2, tableLength(signReader.getBlockStates()), "Block State should not be empty") test.eq(4, signReader.getBlockStates()["rotation"], "Sign Rotation should be 4") test.assert(not signReader.getBlockStates()["waterlogged"], "Sign Waterlogged should be false") From e1a84cd218c35918335024e531aa159ddef15276 Mon Sep 17 00:00:00 2001 From: srendi Date: Tue, 21 May 2024 12:00:56 +0200 Subject: [PATCH 27/61] increase sleep for the `isItemCrafting` function in the mecrafting peripheral test --- .../computer/tests/peripheraltest.mecrafting.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua index a9868886d..ad9d15a7d 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -42,7 +42,7 @@ test.assert(stickCount == 0, "We should not have sticks") craftingSuccessful = bridge.craftItem(stickFilter) test.assert(craftingSuccessful, "Crafting failed") -sleep(0.1) +sleep(0.15) isItemCrafting = bridge.isItemCrafting(stickFilter) test.assert(isItemCrafting, "There should be a crafting job") From 2aedb2ac834551674d3c8ad0fe2f16596a24bd16 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 11 May 2024 18:24:48 +0200 Subject: [PATCH 28/61] Implement tests for NBT Storage peripheral --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.nbtstorage.lua | 38 +++++ .../structures/peripheraltest.nbtstorage.snbt | 138 ++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index edc1b0b38..959cfc8fb 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -37,4 +37,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest + fun nbtStorage(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua new file mode 100644 index 000000000..12017d4b1 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua @@ -0,0 +1,38 @@ +--- +--- Advanced Peripherals NBT Storage tests +--- Covers `read`, `writeJson`, `writeTable` +--- + +TEST_STRING = "Hello, World!" +TEST_NUMBER = 42 +TEST_FLOAT = 3.14 +TEST_VALUE = "AP Game Test" +TEST_JSON_VALUE = "AP Game Test JSON" + +test.eq("nbtStorage", peripheral.getType("left"), "Peripheral should be nbtStorage") +storage = peripheral.wrap("left") +test.assert(storage, "Peripheral not found") + +-- Read data from the test structure and verify it +stored = storage.read() +test.assert(stored, "Storage should not be nil") +test.eq(TEST_STRING, stored["test_string"], ("Stored string should be '%s'"):format(TEST_STRING)) +test.eq(TEST_NUMBER, stored["test_number"], ("Stored number should be %d"):format(TEST_NUMBER)) +test.eq(TEST_FLOAT, stored["test_float"], ("Stored float should be %f"):format(TEST_FLOAT)) + +-- Write a table to the storage and verify it +storage.writeTable({ + test_value = TEST_VALUE, +}) + +stored = storage.read() +test.assert(stored, "Storage should not be nil") +test.eq(TEST_VALUE, stored["test_value"], ("Stored value should be '%s'"):format(TEST_VALUE)) + +-- Write a JSON string to the storage and verify it +success = storage.writeJson(textutils.serializeJSON({test_value = TEST_JSON_VALUE})) +test.assert(success, "Storage writeJson should return true") + +stored = storage.read() +test.assert(stored, "Storage should not be nil") +test.eq(TEST_JSON_VALUE, stored["test_value"], ("Stored value should be '%s'"):format(TEST_JSON_VALUE)) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt new file mode 100644 index 000000000..0f0515b89 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "advancedperipherals:nbt_storage{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[NBT Storage]"}, Items: [], id: "advancedperipherals:nbt_storage", storedData: {test_float: 3.14d, test_number: 42.0d, test_string: "Hello, World!"}}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.nbtstorage", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "advancedperipherals:nbt_storage{orientation:up_east}", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} From 2f09327e752ced17114f15409d4753f536f96ef0 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 11 May 2024 23:46:56 +0200 Subject: [PATCH 29/61] Implement tests for Redstone Integrator peripheral --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.rsintegrator.lua | 35 +++++ .../peripheraltest.rsintegrator.snbt | 142 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 959cfc8fb..7066ee55c 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -42,4 +42,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest + fun rsIntegrator(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua new file mode 100644 index 000000000..16b430a11 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua @@ -0,0 +1,35 @@ +--- +--- Advanced Peripherals Redstone Integrator tests +--- Covers `getInput`, `getOutput`, `getAnalogInput`, +--- `getAnalogOutput`, `setOutput`, `setAnalogOutput` +--- + +test.eq("redstoneIntegrator", peripheral.getType("left"), "Peripheral should be redstoneIntegrator") +test.eq("redstoneIntegrator", peripheral.getType("right"), "Peripheral should be redstoneIntegrator") + +first = peripheral.wrap("left") +test.assert(first, "Peripheral not found") + +second = peripheral.wrap("right") +test.assert(second, "Peripheral not found") + +-- Test input for Redstone Block (full strength) +test.eq(15, second.getAnalogInput("back"), "Analog input should be 15 for Redstone Block") +test.assert(second.getInput("back"), "Digital input should be true for Redstone Block") + +-- Test output on the right integrator +second.setOutput("front", true) +test.assert(second.getOutput("front"), "Digital output should be true") + +-- Test analog input on the left integrator (wired from the right integrator) +test.eq(13, first.getAnalogInput("front"), "Analog input should be 13") + +-- Test analog output on the right integrator +second.setAnalogOutput("front", 10) +test.eq(10, second.getAnalogOutput("front"), "Analog output should be 10") + +-- Test analog input on the left integrator (wired from the right integrator) +test.eq(8, first.getAnalogInput("front"), "Analog input should be 8") + +-- Reset redstone output +second.setOutput("front", false) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt new file mode 100644 index 000000000..0c084d522 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:redstone_wire{east:side,north:none,power:0,south:side,west:none}"}, + {pos: [1, 1, 2], state: "minecraft:redstone_wire{east:side,north:side,power:0,south:side,west:none}"}, + {pos: [1, 1, 3], state: "minecraft:redstone_wire{east:side,north:side,power:0,south:none,west:none}"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "advancedperipherals:redstone_integrator{orientation:west_up}", nbt: {DOWNPower: 0, EASTPower: 0, ForgeCaps: {}, ForgeData: {CustomName: "[Redstone Integrator]"}, Items: [], NORTHPower: 0, SOUTHPower: 0, UPPower: 0, WESTPower: 0, id: "advancedperipherals:redstone_integrator"}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.rsintegrator", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "advancedperipherals:redstone_integrator{orientation:west_up}", nbt: {DOWNPower: 0, EASTPower: 0, ForgeCaps: {}, ForgeData: {CustomName: "[Redstone Integrator]"}, Items: [], NORTHPower: 0, SOUTHPower: 0, UPPower: 0, WESTPower: 0, id: "advancedperipherals:redstone_integrator"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:redstone_block"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:redstone_block", + "minecraft:air", + "minecraft:redstone_wire{east:side,north:none,power:0,south:side,west:none}", + "minecraft:redstone_wire{east:side,north:side,power:0,south:side,west:none}", + "minecraft:redstone_wire{east:side,north:side,power:0,south:none,west:none}", + "advancedperipherals:redstone_integrator{orientation:west_up}", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} From 3f283716b2c5b3d5151c1a32b35e9c5438ca3ad4 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 12 May 2024 01:16:57 +0200 Subject: [PATCH 30/61] Implement tests for Geo Scanner peripheral --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.geoscanner.lua | 80 ++++++ .../structures/peripheraltest.geoscanner.snbt | 243 ++++++++++++++++++ 3 files changed, 328 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 7066ee55c..c093dd97d 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -47,4 +47,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest(timeoutTicks = 300) + fun geoScanner(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua new file mode 100644 index 000000000..1c74c0942 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua @@ -0,0 +1,80 @@ +--- +--- Advanced Peripherals Geo Scanner tests +--- Covers `getFuelLevel`, `getMaxFuelLevel`, `cost`, +--- `scan`, `chunkAnalyze`, `getOperationCooldown` +--- + +function testBlockAt(result, x, y, z, expectedName, expectedTag) + local blockEntry = nil + for _, entry in ipairs(result) do + if entry["x"] == x and entry["y"] == y and entry["z"] == z then + blockEntry = entry + break + end + end + + test.assert(blockEntry, ("Block at %d, %d, %d not found"):format(x, y, z)) + test.eq(expectedName, blockEntry["name"], ("Block at %d, %d, %d has the wrong name"):format(x, y, z)) + + local tagFound = false + for _, tag in ipairs(blockEntry["tags"]) do + if tag == expectedTag then + tagFound = true + break + end + end + test.assert(tagFound, ("Block at %d, %d, %d has the wrong tags"):format(x, y, z)) +end + +scanner = peripheral.find("geoScanner") +test.assert(scanner, "Peripheral not found") + +config = scanner.getConfiguration() +fuelEnabled = scanner.getMaxFuelLevel() > 0 + +-- Test scan costs +test.eq(0, scanner.cost(1), "Scans with a range of 1 should be free") +test.eq(0, scanner.cost(config["scanBlocks"]["maxFreeRadius"]), "Scans with the maximum free radius should be free") +test.assert(scanner.cost(config["scanBlocks"]["maxFreeRadius"] + 1) > 0, "Scans with a radius larger than the maximum free radius should cost fuel") + +test.assert(scanner.cost(config["scanBlocks"]["maxCostRadius"]) > 0, "Scans with the maximum cost radius should cost fuel") +test.assert(scanner.cost(config["scanBlocks"]["maxCostRadius"] + 1) == nil, "Scans with a radius larger than the maximum cost radius should not be possible") + +-- Test scan results +scanResult = scanner.scan(1) +test.assert(scanResult, "Scan result should not be nil") + +currentCooldown = scanner.getOperationCooldown("scanBlocks") +test.assert(currentCooldown > 0 and currentCooldown <= config["scanBlocks"]["cooldown"], "Cooldown should be active after a scan") + +testBlockAt(scanResult, 0, 0, 0, "advancedperipherals:geo_scanner", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 0, -1, 0, "computercraft:computer_advanced", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 0, 1, 0, "minecraft:iron_ore", "minecraft:block/forge:ores/iron") +testBlockAt(scanResult, 0, -1, 1, "minecraft:polished_diorite", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 0, -1, -1, "minecraft:polished_andesite", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 1, -1, 0, "minecraft:polished_granite", "minecraft:block/minecraft:mineable/pickaxe") + +while scanner.getOperationCooldown("scanBlocks") > 0 do + sleep(0.25) +end + +-- Test chunk analysis with ores +chunkResult = scanner.chunkAnalyze() + +currentCooldown = scanner.getOperationCooldown("scanBlocks") +test.assert(currentCooldown > 0 and currentCooldown <= config["scanBlocks"]["cooldown"], "Cooldown should be active after a chunk analysis") + +test.assert(chunkResult, "Chunk analysis result should not be nil") +test.eq(1, chunkResult["minecraft:iron_ore"], "Iron ore count should be 1") +test.eq(2, chunkResult["minecraft:gold_ore"], "Gold ore count should be 2") +test.eq(3, chunkResult["minecraft:diamond_ore"], "Diamond ore count should be 3") + +while scanner.getOperationCooldown("scanBlocks") > 0 do + sleep(0.25) +end + +if fuelEnabled then + scanResult = scanner.scan(config["scanBlocks"]["maxFreeRadius"] + 1) + test.assert(scanResult, "Scan result should not be nil") + test.eq(scanner.getMaxFuelLevel() - scanner.cost(config["scanBlocks"]["maxFreeRadius"] + 1), scanner.getFuelLevel(), "Fuel level should be reduced after a scan") +end diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt new file mode 100644 index 000000000..fd6a9bf08 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt @@ -0,0 +1,243 @@ +{ + DataVersion: 3120, + size: [5, 9, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.geoscanner", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:polished_diorite"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:polished_granite"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "advancedperipherals:geo_scanner{orientation:west_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Geo Scanner]"}, Items: [], energy: 100000000, id: "advancedperipherals:geo_scanner", peripheralSettings: {FUEL_CONSUMING_RATE: 1, cooldowns: {scanBlocks: 1715469234280L}}}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:iron_ore"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:gold_ore"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "minecraft:air"}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "minecraft:gold_ore"}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "minecraft:air"}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "minecraft:air"}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "minecraft:diamond_ore"}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [0, 7, 0], state: "minecraft:air"}, + {pos: [0, 7, 1], state: "minecraft:air"}, + {pos: [0, 7, 2], state: "minecraft:air"}, + {pos: [0, 7, 3], state: "minecraft:air"}, + {pos: [0, 7, 4], state: "minecraft:air"}, + {pos: [1, 7, 0], state: "minecraft:air"}, + {pos: [1, 7, 1], state: "minecraft:air"}, + {pos: [1, 7, 2], state: "minecraft:air"}, + {pos: [1, 7, 3], state: "minecraft:air"}, + {pos: [1, 7, 4], state: "minecraft:air"}, + {pos: [2, 7, 0], state: "minecraft:air"}, + {pos: [2, 7, 1], state: "minecraft:air"}, + {pos: [2, 7, 2], state: "minecraft:diamond_ore"}, + {pos: [2, 7, 3], state: "minecraft:air"}, + {pos: [2, 7, 4], state: "minecraft:air"}, + {pos: [3, 7, 0], state: "minecraft:air"}, + {pos: [3, 7, 1], state: "minecraft:air"}, + {pos: [3, 7, 2], state: "minecraft:air"}, + {pos: [3, 7, 3], state: "minecraft:air"}, + {pos: [3, 7, 4], state: "minecraft:air"}, + {pos: [4, 7, 0], state: "minecraft:air"}, + {pos: [4, 7, 1], state: "minecraft:air"}, + {pos: [4, 7, 2], state: "minecraft:air"}, + {pos: [4, 7, 3], state: "minecraft:air"}, + {pos: [4, 7, 4], state: "minecraft:air"}, + {pos: [0, 8, 0], state: "minecraft:air"}, + {pos: [0, 8, 1], state: "minecraft:air"}, + {pos: [0, 8, 2], state: "minecraft:air"}, + {pos: [0, 8, 3], state: "minecraft:air"}, + {pos: [0, 8, 4], state: "minecraft:air"}, + {pos: [1, 8, 0], state: "minecraft:air"}, + {pos: [1, 8, 1], state: "minecraft:air"}, + {pos: [1, 8, 2], state: "minecraft:air"}, + {pos: [1, 8, 3], state: "minecraft:air"}, + {pos: [1, 8, 4], state: "minecraft:air"}, + {pos: [2, 8, 0], state: "minecraft:air"}, + {pos: [2, 8, 1], state: "minecraft:air"}, + {pos: [2, 8, 2], state: "minecraft:diamond_ore"}, + {pos: [2, 8, 3], state: "minecraft:air"}, + {pos: [2, 8, 4], state: "minecraft:air"}, + {pos: [3, 8, 0], state: "minecraft:air"}, + {pos: [3, 8, 1], state: "minecraft:air"}, + {pos: [3, 8, 2], state: "minecraft:air"}, + {pos: [3, 8, 3], state: "minecraft:air"}, + {pos: [3, 8, 4], state: "minecraft:air"}, + {pos: [4, 8, 0], state: "minecraft:air"}, + {pos: [4, 8, 1], state: "minecraft:air"}, + {pos: [4, 8, 2], state: "minecraft:air"}, + {pos: [4, 8, 3], state: "minecraft:air"}, + {pos: [4, 8, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:polished_diorite", + "minecraft:polished_granite", + "minecraft:iron_ore", + "minecraft:gold_ore", + "minecraft:diamond_ore", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:blinking}", + "advancedperipherals:geo_scanner{orientation:west_up}" + ] +} From 967fbe2b8c318f570ed0ab6c848471cef5fdc2b9 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 12 May 2024 01:20:36 +0200 Subject: [PATCH 31/61] Add missing comment in Geo Scanner test --- .../computer/tests/peripheraltest.geoscanner.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua index 1c74c0942..e965c60e4 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua @@ -73,6 +73,7 @@ while scanner.getOperationCooldown("scanBlocks") > 0 do sleep(0.25) end +-- Test fuel consumption if fuelEnabled then scanResult = scanner.scan(config["scanBlocks"]["maxFreeRadius"] + 1) test.assert(scanResult, "Scan result should not be nil") From a3a834de55bb237f84a7fafcd8f92b5d6f3867b8 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 12 May 2024 17:01:17 +0200 Subject: [PATCH 32/61] Add test for Mana Flowers in the Botania Mod Integration --- .../advancedperipherals/test/ModIntegrTest.kt | 17 +++ .../tests/modintegrtest.botaniaflower.lua | 47 ++++++ .../modintegrtest.botaniaflower.snbt | 142 ++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt new file mode 100644 index 000000000..acc6ddc8d --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -0,0 +1,17 @@ +package de.srendi.advancedperipherals.test + +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenComputerOk +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper + +@GameTestHolder +class ModIntegrTest { + + @GameTest + fun botaniaFlower(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + +} \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua new file mode 100644 index 000000000..0aac5e28d --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua @@ -0,0 +1,47 @@ +--- +--- Advanced Peripherals tests for the Botania integration on Flowers +--- Covers `getMana`, `getMaxMana`, `isFloating`, +--- `isOnEnchantedSoil`, `isEmpty`, `isFull` +--- + +-- Test for Entropinnyum (Flower has full mana store and is on enchanted soil) +test.eq("manaFlower", peripheral.getType("left"), "Peripheral should be manaFlower") +entropinnyum = peripheral.wrap("left") +test.assert(entropinnyum, "Peripheral not found") + +test.eq(entropinnyum.getMaxMana(), entropinnyum.getMana(), "Entropinnyum should have full mana") +test.eq(6500, entropinnyum.getMaxMana(), "Entropinnyum should have a max mana of 6500") +-- test.assert(entropinnyum.isOnEnchantedSoil(), "Entropinnyum should be on enchanted soil") TODO: the function is currently broken +test.assert(not entropinnyum.isFloating(), "Entropinnyum should not be floating") +if entropinnyum.isFull and entropinnyum.isEmpty then + test.assert(entropinnyum.isFull(), "Entropinnyum should be full") + test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") +end + +-- Test for Endoflame (Flower has no mana stored and is on normal soil) +test.eq("manaFlower", peripheral.getType("right"), "Peripheral should be manaFlower") +endoflame = peripheral.wrap("right") +test.assert(endoflame, "Peripheral not found") + +test.eq(0, endoflame.getMana(), "Endoflame should have no mana") +test.eq(300, endoflame.getMaxMana(), "Endoflame should have a max mana of 300") +-- test.assert(not endoflame.isOnEnchantedSoil(), "Endoflame should not be on enchanted soil") TODO: the function is currently broken +test.assert(not endoflame.isFloating(), "Endoflame should not be floating") +if endoflame.isFull and endoflame.isEmpty then + test.assert(not endoflame.isFull(), "Endoflame should not be full") + test.assert(endoflame.isEmpty(), "Endoflame should be empty") +end + +-- Test for Kekimurus (Flower has 1800 mana stored and is floating) +test.eq("manaFlower", peripheral.getType("back"), "Peripheral should be manaFlower") +kekimurus = peripheral.wrap("back") +test.assert(kekimurus, "Peripheral not found") + +test.eq(1800, kekimurus.getMana(), "Kekimurus should have 1800 mana") +test.eq(9001, kekimurus.getMaxMana(), "Kekimurus should have a max mana of 9001") +-- test.assert(not kekimurus.isOnEnchantedSoil(), "Kekimurus should not be on enchanted soil") TODO: the function is currently broken +test.assert(kekimurus.isFloating(), "Kekimurus should be floating") +if kekimurus.isFull and kekimurus.isEmpty then + test.assert(not kekimurus.isFull(), "Kekimurus should not be full") + test.assert(not kekimurus.isEmpty(), "Kekimurus should not be empty") +end diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt new file mode 100644 index 000000000..02829a44b --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "botania:enchanted_soil"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:grass_block{snowy:false}"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "botania:entropinnyum", nbt: {ForgeCaps: {}, id: "botania:entropinnyum", mana: 6500, ticksExisted: 52900}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniaflower", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "botania:endoflame", nbt: {ForgeCaps: {}, burnTime: 0, id: "botania:endoflame", mana: 0, ticksExisted: 9109}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "botania:floating_kekimurus{waterlogged:false}", nbt: {ForgeCaps: {}, floating: {islandType: "GRASS"}, id: "botania:kekimurus", mana: 1800, ticksExisted: 26663}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "botania:enchanted_soil", + "minecraft:grass_block{snowy:false}", + "minecraft:air", + "botania:entropinnyum", + "computercraft:computer_advanced{facing:west,state:blinking}", + "botania:endoflame", + "botania:floating_kekimurus{waterlogged:false}" + ] +} From f8d7c751fcddb6f52040e337aaaa4ee43ed9abb4 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 12 May 2024 17:16:32 +0200 Subject: [PATCH 33/61] Add todo comment for missing getScanCooldown function on Geo Scanner --- .../computer/tests/peripheraltest.geoscanner.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua index e965c60e4..b60f15efe 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua @@ -4,6 +4,8 @@ --- `scan`, `chunkAnalyze`, `getOperationCooldown` --- +-- TODO: replace getOperationCooldown with getScanCooldown once the function is implemented + function testBlockAt(result, x, y, z, expectedName, expectedTag) local blockEntry = nil for _, entry in ipairs(result) do From 0b31b0918c9a13abaf354d221e427ee8dcc2b2e5 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 12 May 2024 17:43:06 +0200 Subject: [PATCH 34/61] Uncomment tests for currently unavailable Botania methods --- .../tests/modintegrtest.botaniaflower.lua | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua index 0aac5e28d..0d27cc1bc 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua @@ -13,10 +13,8 @@ test.eq(entropinnyum.getMaxMana(), entropinnyum.getMana(), "Entropinnyum should test.eq(6500, entropinnyum.getMaxMana(), "Entropinnyum should have a max mana of 6500") -- test.assert(entropinnyum.isOnEnchantedSoil(), "Entropinnyum should be on enchanted soil") TODO: the function is currently broken test.assert(not entropinnyum.isFloating(), "Entropinnyum should not be floating") -if entropinnyum.isFull and entropinnyum.isEmpty then - test.assert(entropinnyum.isFull(), "Entropinnyum should be full") - test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") -end +-- test.assert(entropinnyum.isFull(), "Entropinnyum should be full") TODO: uncomment for 1.20.1 AP versions +-- test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") TODO: uncomment for 1.20.1 AP versions -- Test for Endoflame (Flower has no mana stored and is on normal soil) test.eq("manaFlower", peripheral.getType("right"), "Peripheral should be manaFlower") @@ -27,10 +25,8 @@ test.eq(0, endoflame.getMana(), "Endoflame should have no mana") test.eq(300, endoflame.getMaxMana(), "Endoflame should have a max mana of 300") -- test.assert(not endoflame.isOnEnchantedSoil(), "Endoflame should not be on enchanted soil") TODO: the function is currently broken test.assert(not endoflame.isFloating(), "Endoflame should not be floating") -if endoflame.isFull and endoflame.isEmpty then - test.assert(not endoflame.isFull(), "Endoflame should not be full") - test.assert(endoflame.isEmpty(), "Endoflame should be empty") -end +-- test.assert(not endoflame.isFull(), "Endoflame should not be full") TODO: uncomment for 1.20.1 AP versions +-- test.assert(endoflame.isEmpty(), "Endoflame should be empty") TODO: uncomment for 1.20.1 AP versions -- Test for Kekimurus (Flower has 1800 mana stored and is floating) test.eq("manaFlower", peripheral.getType("back"), "Peripheral should be manaFlower") @@ -41,7 +37,5 @@ test.eq(1800, kekimurus.getMana(), "Kekimurus should have 1800 mana") test.eq(9001, kekimurus.getMaxMana(), "Kekimurus should have a max mana of 9001") -- test.assert(not kekimurus.isOnEnchantedSoil(), "Kekimurus should not be on enchanted soil") TODO: the function is currently broken test.assert(kekimurus.isFloating(), "Kekimurus should be floating") -if kekimurus.isFull and kekimurus.isEmpty then - test.assert(not kekimurus.isFull(), "Kekimurus should not be full") - test.assert(not kekimurus.isEmpty(), "Kekimurus should not be empty") -end +-- test.assert(not kekimurus.isFull(), "Kekimurus should not be full") TODO: uncomment for 1.20.1 AP versions +-- test.assert(not kekimurus.isEmpty(), "Kekimurus should not be empty") TODO: uncomment for 1.20.1 AP versions From 77df4d0c68755d6b1b9e5e16927f3a8de81b42a4 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 12 May 2024 17:52:20 +0200 Subject: [PATCH 35/61] Add test for Mana Pools in the Botania Mod Integration --- .../advancedperipherals/test/ModIntegrTest.kt | 5 + .../tests/modintegrtest.botaniamanapool.lua | 40 +++++ .../modintegrtest.botaniamanapool.snbt | 140 ++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt index acc6ddc8d..f12da5f64 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -14,4 +14,9 @@ class ModIntegrTest { thenComputerOk(); } + @GameTest + fun botaniaManaPool(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua new file mode 100644 index 000000000..a7487ac3a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua @@ -0,0 +1,40 @@ +--- +--- Advanced Peripherals tests for the Botania integration on Mana Pools +--- Covers `getMana`, `getMaxMana`, `getManaNeeded`, +--- `isEmpty`, `isFull` +--- + +-- TODO Add tests for canChargeItem, hasItems and getItems in 1.20.1 AP versions + +-- Test Fabulous Mana Pool (should be empty) +test.eq("manaPool", peripheral.getType("left"), "Peripheral should be manaPool") +fabulous = peripheral.wrap("left") +test.assert(fabulous, "Peripheral not found") + +test.eq(0, fabulous.getMana(), "Mana should be 0") +test.eq(1000000, fabulous.getMaxMana(), "Max mana should be 1000000") +test.eq(1000000, fabulous.getManaNeeded(), "Mana needed should be 1000000") +-- test.assert(fabulous.isEmpty(), "Mana pool should be empty") TODO method currently not implemented +test.assert(not fabulous.isFull(), "Mana pool should not be full") + +-- Test Mana Pool (should have 36000 mana) +test.eq("manaPool", peripheral.getType("right"), "Peripheral should be manaPool") +manaPool = peripheral.wrap("right") +test.assert(manaPool, "Peripheral not found") + +test.eq(36000, manaPool.getMana(), "Mana should be 36000") +test.eq(1000000, manaPool.getMaxMana(), "Max mana should be 1000000") +test.eq(964000, manaPool.getManaNeeded(), "Mana needed should be 964000") +-- test.assert(not manaPool.isEmpty(), "Mana pool should not be empty") TODO method currently not implemented +test.assert(not manaPool.isFull(), "Mana pool should not be full") + +-- Test Creative Mana Pool (should have 1000000 mana) +test.eq("manaPool", peripheral.getType("back"), "Peripheral should be manaPool") +creative = peripheral.wrap("back") +test.assert(creative, "Peripheral not found") + +test.eq(1000000, creative.getMana(), "Mana should be 1000000") +test.eq(1000000, creative.getMaxMana(), "Max mana should be 1000000") +test.eq(0, creative.getManaNeeded(), "Mana needed should be 0") +-- test.assert(not creative.isEmpty(), "Mana pool should not be empty") TODO method currently not implemented +test.assert(creative.isFull(), "Mana pool should be full") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt new file mode 100644 index 000000000..0952833af --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "botania:fabulous_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 0, manaCap: 1000000, outputKey: "", outputting: 0b}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniamanapool", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "botania:mana_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 36000, manaCap: 1000000, outputKey: "", outputting: 0b}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "botania:creative_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 1000000, manaCap: 1000000, outputKey: "", outputting: 1b}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "botania:fabulous_pool{color:none,waterlogged:false}", + "computercraft:computer_advanced{facing:west,state:blinking}", + "botania:mana_pool{color:none,waterlogged:false}", + "botania:creative_pool{color:none,waterlogged:false}" + ] +} From 970fc5fbca257ecf61423f05c8b2c9d566c7780b Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Mon, 13 May 2024 18:39:35 +0200 Subject: [PATCH 36/61] Add test for Mana Spreaders in the Botania Mod Integration --- .../computercraft/gametest/core/TestAPI.java | 13 ++ .../advancedperipherals/test/ModIntegrTest.kt | 5 + .../tests/modintegrtest.botaniaspreader.lua | 66 ++++++++ .../modintegrtest.botaniaspreader.snbt | 142 ++++++++++++++++++ 4 files changed, 226 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java index 5539d9ac1..5ea5e8cfc 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java @@ -12,7 +12,10 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.gametest.api.ComputerState; import dan200.computercraft.gametest.api.TestExtensionsKt; +import dan200.computercraft.shared.computer.core.ServerContext; +import de.srendi.advancedperipherals.common.util.LuaConverter; import net.minecraft.gametest.framework.GameTestSequence; +import net.minecraftforge.server.ServerLifecycleHooks; import java.util.Optional; @@ -80,4 +83,14 @@ public final void ok(Optional marker) throws LuaException { public final void log(String message) { ComputerCraft.log.info("[Computer '{}'] {}", label, message); } + + @LuaFunction + public final Object getComputerPosition() { + return ServerContext.get(ServerLifecycleHooks.getCurrentServer()).registry().getComputers().stream() + .filter(computer -> computer.getLabel() != null && computer.getLabel().equals(label)) + .findFirst() + .map(computer -> LuaConverter.posToObject(computer.getPosition())) + .orElse(null); + } + } diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt index f12da5f64..a05a73829 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -19,4 +19,9 @@ class ModIntegrTest { thenComputerOk(); } + @GameTest + fun botaniaSpreader(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua new file mode 100644 index 000000000..e72424f24 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua @@ -0,0 +1,66 @@ +--- +--- Advanced Peripherals tests for the Botania integration on Mana Spreaders +--- Covers `getMana`, `getMaxMana`, `getVariant`, +--- `isEmpty`, `isFull`, `getBounding` +--- + +-- TODO Add tests for hasLens and getLens in 1.20.1 AP versions + +-- Test basic Mana Spreader that is empty and directed towards a Mana Pool +test.eq("manaSpreader", peripheral.getType("left"), "Peripheral should be manaSpreader") +spreader = peripheral.wrap("left") +test.assert(spreader, "Peripheral not found") + +test.eq(0, spreader.getMana(), "Mana should be 0") +test.eq(1000, spreader.getMaxMana(), "Max mana should be 1000") +test.eq("MANA", spreader.getVariant(), "Variant should be MANA") +-- test.assert(spreader.isEmpty(), "Mana Spreader should be empty") TODO: method returns the wrong value currently +test.assert(not spreader.isFull(), "Mana Spreader should not be full") + +bounding = spreader.getBounding() +computerPos = test.getComputerPosition() +test.assert(bounding, "Spreader binding should be returned") +test.assert(computerPos, "Computer position should be returned") + +test.eq(computerPos.x + 1, bounding.x, "Bounding x should be set to Mana pool (+1 relative to computer)") +test.eq(computerPos.y, bounding.y, "Bounding y should be set to Mana pool (same as computer)") +test.eq(computerPos.z - 1, bounding.z, "Bounding z should be set to Mana pool (-1 relative to computer") + +-- Test Gaia Mana Spreader that is full +test.eq("manaSpreader", peripheral.getType("right"), "Peripheral should be manaSpreader") +gaiaSpreader = peripheral.wrap("right") +test.assert(gaiaSpreader, "Peripheral not found") + +test.eq(6400, gaiaSpreader.getMana(), "Mana should be 6400") +test.eq(6400, gaiaSpreader.getMaxMana(), "Max mana should be 6400") +test.eq("GAIA", gaiaSpreader.getVariant(), "Variant should be GAIA") +-- test.assert(not gaiaSpreader.isEmpty(), "Mana Spreader should not be empty") TODO: method returns the wrong value currently +test.assert(gaiaSpreader.isFull(), "Mana Spreader should be full") + +test.assert(not gaiaSpreader.getBounding(), "Mana Spreader should not be bound to anything") + +-- Test Elven Mana Spreader that has 177 mana +test.eq("manaSpreader", peripheral.getType("back"), "Peripheral should be manaSpreader") +elvenSpreader = peripheral.wrap("back") +test.assert(elvenSpreader, "Peripheral not found") + +test.eq(177, elvenSpreader.getMana(), "Mana should be 177") +test.eq(1000, elvenSpreader.getMaxMana(), "Max mana should be 1000") +test.eq("ELVEN", elvenSpreader.getVariant(), "Variant should be ELVEN") +-- test.assert(not elvenSpreader.isEmpty(), "Mana Spreader should not be empty") TODO: method returns the wrong value currently +test.assert(not elvenSpreader.isFull(), "Mana Spreader should not be full") + +test.assert(not elvenSpreader.getBounding(), "Mana Spreader should not be bound to anything") + +-- Test Pulse Mana Spreader that is empty +test.eq("manaSpreader", peripheral.getType("top"), "Peripheral should be manaSpreader") +pulseSpreader = peripheral.wrap("top") +test.assert(pulseSpreader, "Peripheral not found") + +test.eq(0, pulseSpreader.getMana(), "Mana should be 0") +test.eq(1000, pulseSpreader.getMaxMana(), "Max mana should be 1000") +test.eq("REDSTONE", pulseSpreader.getVariant(), "Variant should be REDSTONE") +-- test.assert(pulseSpreader.isEmpty(), "Mana Spreader should be empty") TODO: method returns the wrong value currently +test.assert(not pulseSpreader.isFull(), "Mana Spreader should not be full") + +test.assert(not pulseSpreader.getBounding(), "Mana Spreader should not be bound to anything") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt new file mode 100644 index 000000000..4e42dbe4a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "botania:mana_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 10, forceClientBindingY: 60, forceClientBindingZ: -9, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 0, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 180.0f, rotationY: -14.036243f, uuid: [I; -1335544995, 1721978540, -1824636534, -1356366853]}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniaspreader", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "botania:gaia_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 6400, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; 488019582, 1505248039, -1662086631, -1403515204]}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "botania:mana_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 0, manaCap: 1000000, outputKey: "", outputting: 0b}}, + {pos: [3, 1, 2], state: "botania:elven_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 177, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; -360645062, -1521991436, -1469095441, -381296848]}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "botania:redstone_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 0, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; 758151075, -302429323, -1148181277, 1481371264]}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "botania:mana_spreader{has_scaffolding:false,waterlogged:false}", + "computercraft:computer_advanced{facing:west,state:blinking}", + "botania:gaia_spreader{has_scaffolding:false,waterlogged:false}", + "botania:mana_pool{color:none,waterlogged:false}", + "botania:elven_spreader{has_scaffolding:false,waterlogged:false}", + "botania:redstone_spreader{has_scaffolding:false,waterlogged:false}" + ] +} From 1e96a64cd70346869fdcb35f232a2d2869dbc6f2 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Mon, 13 May 2024 18:55:55 +0200 Subject: [PATCH 37/61] Add test for Beacons in the Minecraft Mod (lol) Integration --- .../advancedperipherals/test/ModIntegrTest.kt | 5 + .../tests/modintegrtest.minecraftbeacon.lua | 34 + .../modintegrtest.minecraftbeacon.snbt | 707 ++++++++++++++++++ 3 files changed, 746 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt index a05a73829..718cd41d6 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -24,4 +24,9 @@ class ModIntegrTest { thenComputerOk(); } + @GameTest(timeoutTicks = 300) + fun minecraftBeacon(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua new file mode 100644 index 000000000..ee97dc0a4 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua @@ -0,0 +1,34 @@ +--- +--- Advanced Peripherals tests for the Minecraft integration on Beacons +--- Covers `getLevel`, `getPrimaryEffect`, `getSecondaryEffect` +--- + +-- Wait until the beacon structure is formed +sleep(4) + +-- Test left beacon, level 4, primary and secondary effect set to haste +test.eq("beacon", peripheral.getType("left"), "Peripheral should be beacon") +beacon = peripheral.wrap("left") +test.assert(beacon, "Peripheral not found") + +test.eq(4, beacon.getLevel(), "Level should be 4") +test.eq("effect.minecraft.haste", beacon.getPrimaryEffect(), "Primary effect should be haste") +test.eq("effect.minecraft.haste", beacon.getSecondaryEffect(), "Secondary effect should be haste") + +-- Test right beacon, level 4, primary effect set to speed, secondary effect not set +test.eq("beacon", peripheral.getType("right"), "Peripheral should be beacon") +beacon = peripheral.wrap("right") +test.assert(beacon, "Peripheral not found") + +test.eq(4, beacon.getLevel(), "Level should be 4") +test.eq("effect.minecraft.speed", beacon.getPrimaryEffect(), "Primary effect should be haste") +test.eq("none", beacon.getSecondaryEffect(), "Secondary effect should be none") + +-- Test top beacon, level 0, primary and secondary effect not set +test.eq("beacon", peripheral.getType("top"), "Peripheral should be beacon") +beacon = peripheral.wrap("top") +test.assert(beacon, "Peripheral not found") + +test.eq(0, beacon.getLevel(), "Level should be 0") +test.eq("none", beacon.getPrimaryEffect(), "Primary effect should be none") +test.eq("none", beacon.getSecondaryEffect(), "Secondary effect should be none") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt new file mode 100644 index 000000000..64f2fd44a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt @@ -0,0 +1,707 @@ +{ + DataVersion: 3120, + size: [11, 7, 9], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:iron_block"}, + {pos: [0, 1, 1], state: "minecraft:iron_block"}, + {pos: [0, 1, 2], state: "minecraft:iron_block"}, + {pos: [0, 1, 3], state: "minecraft:iron_block"}, + {pos: [0, 1, 4], state: "minecraft:iron_block"}, + {pos: [0, 1, 5], state: "minecraft:iron_block"}, + {pos: [0, 1, 6], state: "minecraft:iron_block"}, + {pos: [0, 1, 7], state: "minecraft:iron_block"}, + {pos: [0, 1, 8], state: "minecraft:iron_block"}, + {pos: [1, 1, 0], state: "minecraft:iron_block"}, + {pos: [1, 1, 1], state: "minecraft:iron_block"}, + {pos: [1, 1, 2], state: "minecraft:iron_block"}, + {pos: [1, 1, 3], state: "minecraft:iron_block"}, + {pos: [1, 1, 4], state: "minecraft:iron_block"}, + {pos: [1, 1, 5], state: "minecraft:iron_block"}, + {pos: [1, 1, 6], state: "minecraft:iron_block"}, + {pos: [1, 1, 7], state: "minecraft:iron_block"}, + {pos: [1, 1, 8], state: "minecraft:iron_block"}, + {pos: [2, 1, 0], state: "minecraft:iron_block"}, + {pos: [2, 1, 1], state: "minecraft:iron_block"}, + {pos: [2, 1, 2], state: "minecraft:iron_block"}, + {pos: [2, 1, 3], state: "minecraft:iron_block"}, + {pos: [2, 1, 4], state: "minecraft:iron_block"}, + {pos: [2, 1, 5], state: "minecraft:iron_block"}, + {pos: [2, 1, 6], state: "minecraft:iron_block"}, + {pos: [2, 1, 7], state: "minecraft:iron_block"}, + {pos: [2, 1, 8], state: "minecraft:iron_block"}, + {pos: [3, 1, 0], state: "minecraft:iron_block"}, + {pos: [3, 1, 1], state: "minecraft:iron_block"}, + {pos: [3, 1, 2], state: "minecraft:iron_block"}, + {pos: [3, 1, 3], state: "minecraft:iron_block"}, + {pos: [3, 1, 4], state: "minecraft:iron_block"}, + {pos: [3, 1, 5], state: "minecraft:iron_block"}, + {pos: [3, 1, 6], state: "minecraft:iron_block"}, + {pos: [3, 1, 7], state: "minecraft:iron_block"}, + {pos: [3, 1, 8], state: "minecraft:iron_block"}, + {pos: [4, 1, 0], state: "minecraft:iron_block"}, + {pos: [4, 1, 1], state: "minecraft:iron_block"}, + {pos: [4, 1, 2], state: "minecraft:iron_block"}, + {pos: [4, 1, 3], state: "minecraft:iron_block"}, + {pos: [4, 1, 4], state: "minecraft:iron_block"}, + {pos: [4, 1, 5], state: "minecraft:iron_block"}, + {pos: [4, 1, 6], state: "minecraft:iron_block"}, + {pos: [4, 1, 7], state: "minecraft:iron_block"}, + {pos: [4, 1, 8], state: "minecraft:iron_block"}, + {pos: [5, 1, 0], state: "minecraft:iron_block"}, + {pos: [5, 1, 1], state: "minecraft:iron_block"}, + {pos: [5, 1, 2], state: "minecraft:iron_block"}, + {pos: [5, 1, 3], state: "minecraft:iron_block"}, + {pos: [5, 1, 4], state: "minecraft:iron_block"}, + {pos: [5, 1, 5], state: "minecraft:iron_block"}, + {pos: [5, 1, 6], state: "minecraft:iron_block"}, + {pos: [5, 1, 7], state: "minecraft:iron_block"}, + {pos: [5, 1, 8], state: "minecraft:iron_block"}, + {pos: [6, 1, 0], state: "minecraft:iron_block"}, + {pos: [6, 1, 1], state: "minecraft:iron_block"}, + {pos: [6, 1, 2], state: "minecraft:iron_block"}, + {pos: [6, 1, 3], state: "minecraft:iron_block"}, + {pos: [6, 1, 4], state: "minecraft:iron_block"}, + {pos: [6, 1, 5], state: "minecraft:iron_block"}, + {pos: [6, 1, 6], state: "minecraft:iron_block"}, + {pos: [6, 1, 7], state: "minecraft:iron_block"}, + {pos: [6, 1, 8], state: "minecraft:iron_block"}, + {pos: [7, 1, 0], state: "minecraft:iron_block"}, + {pos: [7, 1, 1], state: "minecraft:iron_block"}, + {pos: [7, 1, 2], state: "minecraft:iron_block"}, + {pos: [7, 1, 3], state: "minecraft:iron_block"}, + {pos: [7, 1, 4], state: "minecraft:iron_block"}, + {pos: [7, 1, 5], state: "minecraft:iron_block"}, + {pos: [7, 1, 6], state: "minecraft:iron_block"}, + {pos: [7, 1, 7], state: "minecraft:iron_block"}, + {pos: [7, 1, 8], state: "minecraft:iron_block"}, + {pos: [8, 1, 0], state: "minecraft:iron_block"}, + {pos: [8, 1, 1], state: "minecraft:iron_block"}, + {pos: [8, 1, 2], state: "minecraft:iron_block"}, + {pos: [8, 1, 3], state: "minecraft:iron_block"}, + {pos: [8, 1, 4], state: "minecraft:iron_block"}, + {pos: [8, 1, 5], state: "minecraft:iron_block"}, + {pos: [8, 1, 6], state: "minecraft:iron_block"}, + {pos: [8, 1, 7], state: "minecraft:iron_block"}, + {pos: [8, 1, 8], state: "minecraft:iron_block"}, + {pos: [9, 1, 0], state: "minecraft:iron_block"}, + {pos: [9, 1, 1], state: "minecraft:iron_block"}, + {pos: [9, 1, 2], state: "minecraft:iron_block"}, + {pos: [9, 1, 3], state: "minecraft:iron_block"}, + {pos: [9, 1, 4], state: "minecraft:iron_block"}, + {pos: [9, 1, 5], state: "minecraft:iron_block"}, + {pos: [9, 1, 6], state: "minecraft:iron_block"}, + {pos: [9, 1, 7], state: "minecraft:iron_block"}, + {pos: [9, 1, 8], state: "minecraft:iron_block"}, + {pos: [10, 1, 0], state: "minecraft:iron_block"}, + {pos: [10, 1, 1], state: "minecraft:iron_block"}, + {pos: [10, 1, 2], state: "minecraft:iron_block"}, + {pos: [10, 1, 3], state: "minecraft:iron_block"}, + {pos: [10, 1, 4], state: "minecraft:iron_block"}, + {pos: [10, 1, 5], state: "minecraft:iron_block"}, + {pos: [10, 1, 6], state: "minecraft:iron_block"}, + {pos: [10, 1, 7], state: "minecraft:iron_block"}, + {pos: [10, 1, 8], state: "minecraft:iron_block"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [0, 2, 5], state: "minecraft:air"}, + {pos: [0, 2, 6], state: "minecraft:air"}, + {pos: [0, 2, 7], state: "minecraft:air"}, + {pos: [0, 2, 8], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:iron_block"}, + {pos: [1, 2, 2], state: "minecraft:iron_block"}, + {pos: [1, 2, 3], state: "minecraft:iron_block"}, + {pos: [1, 2, 4], state: "minecraft:iron_block"}, + {pos: [1, 2, 5], state: "minecraft:iron_block"}, + {pos: [1, 2, 6], state: "minecraft:iron_block"}, + {pos: [1, 2, 7], state: "minecraft:iron_block"}, + {pos: [1, 2, 8], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:iron_block"}, + {pos: [2, 2, 2], state: "minecraft:iron_block"}, + {pos: [2, 2, 3], state: "minecraft:iron_block"}, + {pos: [2, 2, 4], state: "minecraft:iron_block"}, + {pos: [2, 2, 5], state: "minecraft:iron_block"}, + {pos: [2, 2, 6], state: "minecraft:iron_block"}, + {pos: [2, 2, 7], state: "minecraft:iron_block"}, + {pos: [2, 2, 8], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:iron_block"}, + {pos: [3, 2, 2], state: "minecraft:iron_block"}, + {pos: [3, 2, 3], state: "minecraft:iron_block"}, + {pos: [3, 2, 4], state: "minecraft:iron_block"}, + {pos: [3, 2, 5], state: "minecraft:iron_block"}, + {pos: [3, 2, 6], state: "minecraft:iron_block"}, + {pos: [3, 2, 7], state: "minecraft:iron_block"}, + {pos: [3, 2, 8], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:iron_block"}, + {pos: [4, 2, 2], state: "minecraft:iron_block"}, + {pos: [4, 2, 3], state: "minecraft:iron_block"}, + {pos: [4, 2, 4], state: "minecraft:iron_block"}, + {pos: [4, 2, 5], state: "minecraft:iron_block"}, + {pos: [4, 2, 6], state: "minecraft:iron_block"}, + {pos: [4, 2, 7], state: "minecraft:iron_block"}, + {pos: [4, 2, 8], state: "minecraft:air"}, + {pos: [5, 2, 0], state: "minecraft:air"}, + {pos: [5, 2, 1], state: "minecraft:iron_block"}, + {pos: [5, 2, 2], state: "minecraft:iron_block"}, + {pos: [5, 2, 3], state: "minecraft:iron_block"}, + {pos: [5, 2, 4], state: "minecraft:iron_block"}, + {pos: [5, 2, 5], state: "minecraft:iron_block"}, + {pos: [5, 2, 6], state: "minecraft:iron_block"}, + {pos: [5, 2, 7], state: "minecraft:iron_block"}, + {pos: [5, 2, 8], state: "minecraft:air"}, + {pos: [6, 2, 0], state: "minecraft:air"}, + {pos: [6, 2, 1], state: "minecraft:iron_block"}, + {pos: [6, 2, 2], state: "minecraft:iron_block"}, + {pos: [6, 2, 3], state: "minecraft:iron_block"}, + {pos: [6, 2, 4], state: "minecraft:iron_block"}, + {pos: [6, 2, 5], state: "minecraft:iron_block"}, + {pos: [6, 2, 6], state: "minecraft:iron_block"}, + {pos: [6, 2, 7], state: "minecraft:iron_block"}, + {pos: [6, 2, 8], state: "minecraft:air"}, + {pos: [7, 2, 0], state: "minecraft:air"}, + {pos: [7, 2, 1], state: "minecraft:iron_block"}, + {pos: [7, 2, 2], state: "minecraft:iron_block"}, + {pos: [7, 2, 3], state: "minecraft:iron_block"}, + {pos: [7, 2, 4], state: "minecraft:iron_block"}, + {pos: [7, 2, 5], state: "minecraft:iron_block"}, + {pos: [7, 2, 6], state: "minecraft:iron_block"}, + {pos: [7, 2, 7], state: "minecraft:iron_block"}, + {pos: [7, 2, 8], state: "minecraft:air"}, + {pos: [8, 2, 0], state: "minecraft:air"}, + {pos: [8, 2, 1], state: "minecraft:iron_block"}, + {pos: [8, 2, 2], state: "minecraft:iron_block"}, + {pos: [8, 2, 3], state: "minecraft:iron_block"}, + {pos: [8, 2, 4], state: "minecraft:iron_block"}, + {pos: [8, 2, 5], state: "minecraft:iron_block"}, + {pos: [8, 2, 6], state: "minecraft:iron_block"}, + {pos: [8, 2, 7], state: "minecraft:iron_block"}, + {pos: [8, 2, 8], state: "minecraft:air"}, + {pos: [9, 2, 0], state: "minecraft:air"}, + {pos: [9, 2, 1], state: "minecraft:iron_block"}, + {pos: [9, 2, 2], state: "minecraft:iron_block"}, + {pos: [9, 2, 3], state: "minecraft:iron_block"}, + {pos: [9, 2, 4], state: "minecraft:iron_block"}, + {pos: [9, 2, 5], state: "minecraft:iron_block"}, + {pos: [9, 2, 6], state: "minecraft:iron_block"}, + {pos: [9, 2, 7], state: "minecraft:iron_block"}, + {pos: [9, 2, 8], state: "minecraft:air"}, + {pos: [10, 2, 0], state: "minecraft:air"}, + {pos: [10, 2, 1], state: "minecraft:air"}, + {pos: [10, 2, 2], state: "minecraft:air"}, + {pos: [10, 2, 3], state: "minecraft:air"}, + {pos: [10, 2, 4], state: "minecraft:air"}, + {pos: [10, 2, 5], state: "minecraft:air"}, + {pos: [10, 2, 6], state: "minecraft:air"}, + {pos: [10, 2, 7], state: "minecraft:air"}, + {pos: [10, 2, 8], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [0, 3, 5], state: "minecraft:air"}, + {pos: [0, 3, 6], state: "minecraft:air"}, + {pos: [0, 3, 7], state: "minecraft:air"}, + {pos: [0, 3, 8], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 5], state: "minecraft:air"}, + {pos: [1, 3, 6], state: "minecraft:air"}, + {pos: [1, 3, 7], state: "minecraft:air"}, + {pos: [1, 3, 8], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:iron_block"}, + {pos: [2, 3, 3], state: "minecraft:iron_block"}, + {pos: [2, 3, 4], state: "minecraft:iron_block"}, + {pos: [2, 3, 5], state: "minecraft:iron_block"}, + {pos: [2, 3, 6], state: "minecraft:iron_block"}, + {pos: [2, 3, 7], state: "minecraft:air"}, + {pos: [2, 3, 8], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:iron_block"}, + {pos: [3, 3, 3], state: "minecraft:iron_block"}, + {pos: [3, 3, 4], state: "minecraft:iron_block"}, + {pos: [3, 3, 5], state: "minecraft:iron_block"}, + {pos: [3, 3, 6], state: "minecraft:iron_block"}, + {pos: [3, 3, 7], state: "minecraft:air"}, + {pos: [3, 3, 8], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:iron_block"}, + {pos: [4, 3, 3], state: "minecraft:iron_block"}, + {pos: [4, 3, 4], state: "minecraft:iron_block"}, + {pos: [4, 3, 5], state: "minecraft:iron_block"}, + {pos: [4, 3, 6], state: "minecraft:iron_block"}, + {pos: [4, 3, 7], state: "minecraft:air"}, + {pos: [4, 3, 8], state: "minecraft:air"}, + {pos: [5, 3, 0], state: "minecraft:air"}, + {pos: [5, 3, 1], state: "minecraft:air"}, + {pos: [5, 3, 2], state: "minecraft:iron_block"}, + {pos: [5, 3, 3], state: "minecraft:iron_block"}, + {pos: [5, 3, 4], state: "minecraft:iron_block"}, + {pos: [5, 3, 5], state: "minecraft:iron_block"}, + {pos: [5, 3, 6], state: "minecraft:iron_block"}, + {pos: [5, 3, 7], state: "minecraft:air"}, + {pos: [5, 3, 8], state: "minecraft:air"}, + {pos: [6, 3, 0], state: "minecraft:air"}, + {pos: [6, 3, 1], state: "minecraft:air"}, + {pos: [6, 3, 2], state: "minecraft:iron_block"}, + {pos: [6, 3, 3], state: "minecraft:iron_block"}, + {pos: [6, 3, 4], state: "minecraft:iron_block"}, + {pos: [6, 3, 5], state: "minecraft:iron_block"}, + {pos: [6, 3, 6], state: "minecraft:iron_block"}, + {pos: [6, 3, 7], state: "minecraft:air"}, + {pos: [6, 3, 8], state: "minecraft:air"}, + {pos: [7, 3, 0], state: "minecraft:air"}, + {pos: [7, 3, 1], state: "minecraft:air"}, + {pos: [7, 3, 2], state: "minecraft:iron_block"}, + {pos: [7, 3, 3], state: "minecraft:iron_block"}, + {pos: [7, 3, 4], state: "minecraft:iron_block"}, + {pos: [7, 3, 5], state: "minecraft:iron_block"}, + {pos: [7, 3, 6], state: "minecraft:iron_block"}, + {pos: [7, 3, 7], state: "minecraft:air"}, + {pos: [7, 3, 8], state: "minecraft:air"}, + {pos: [8, 3, 0], state: "minecraft:air"}, + {pos: [8, 3, 1], state: "minecraft:air"}, + {pos: [8, 3, 2], state: "minecraft:iron_block"}, + {pos: [8, 3, 3], state: "minecraft:iron_block"}, + {pos: [8, 3, 4], state: "minecraft:iron_block"}, + {pos: [8, 3, 5], state: "minecraft:iron_block"}, + {pos: [8, 3, 6], state: "minecraft:iron_block"}, + {pos: [8, 3, 7], state: "minecraft:air"}, + {pos: [8, 3, 8], state: "minecraft:air"}, + {pos: [9, 3, 0], state: "minecraft:air"}, + {pos: [9, 3, 1], state: "minecraft:air"}, + {pos: [9, 3, 2], state: "minecraft:air"}, + {pos: [9, 3, 3], state: "minecraft:air"}, + {pos: [9, 3, 4], state: "minecraft:air"}, + {pos: [9, 3, 5], state: "minecraft:air"}, + {pos: [9, 3, 6], state: "minecraft:air"}, + {pos: [9, 3, 7], state: "minecraft:air"}, + {pos: [9, 3, 8], state: "minecraft:air"}, + {pos: [10, 3, 0], state: "minecraft:air"}, + {pos: [10, 3, 1], state: "minecraft:air"}, + {pos: [10, 3, 2], state: "minecraft:air"}, + {pos: [10, 3, 3], state: "minecraft:air"}, + {pos: [10, 3, 4], state: "minecraft:air"}, + {pos: [10, 3, 5], state: "minecraft:air"}, + {pos: [10, 3, 6], state: "minecraft:air"}, + {pos: [10, 3, 7], state: "minecraft:air"}, + {pos: [10, 3, 8], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [0, 4, 5], state: "minecraft:air"}, + {pos: [0, 4, 6], state: "minecraft:air"}, + {pos: [0, 4, 7], state: "minecraft:air"}, + {pos: [0, 4, 8], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 5], state: "minecraft:air"}, + {pos: [1, 4, 6], state: "minecraft:air"}, + {pos: [1, 4, 7], state: "minecraft:air"}, + {pos: [1, 4, 8], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 5], state: "minecraft:air"}, + {pos: [2, 4, 6], state: "minecraft:air"}, + {pos: [2, 4, 7], state: "minecraft:air"}, + {pos: [2, 4, 8], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:iron_block"}, + {pos: [3, 4, 4], state: "minecraft:iron_block"}, + {pos: [3, 4, 5], state: "minecraft:iron_block"}, + {pos: [3, 4, 6], state: "minecraft:air"}, + {pos: [3, 4, 7], state: "minecraft:air"}, + {pos: [3, 4, 8], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:iron_block"}, + {pos: [4, 4, 4], state: "minecraft:iron_block"}, + {pos: [4, 4, 5], state: "minecraft:iron_block"}, + {pos: [4, 4, 6], state: "minecraft:air"}, + {pos: [4, 4, 7], state: "minecraft:air"}, + {pos: [4, 4, 8], state: "minecraft:air"}, + {pos: [5, 4, 0], state: "minecraft:air"}, + {pos: [5, 4, 1], state: "minecraft:air"}, + {pos: [5, 4, 2], state: "minecraft:air"}, + {pos: [5, 4, 3], state: "minecraft:iron_block"}, + {pos: [5, 4, 4], state: "minecraft:iron_block"}, + {pos: [5, 4, 5], state: "minecraft:iron_block"}, + {pos: [5, 4, 6], state: "minecraft:air"}, + {pos: [5, 4, 7], state: "minecraft:air"}, + {pos: [5, 4, 8], state: "minecraft:air"}, + {pos: [6, 4, 0], state: "minecraft:air"}, + {pos: [6, 4, 1], state: "minecraft:air"}, + {pos: [6, 4, 2], state: "minecraft:air"}, + {pos: [6, 4, 3], state: "minecraft:iron_block"}, + {pos: [6, 4, 4], state: "minecraft:iron_block"}, + {pos: [6, 4, 5], state: "minecraft:iron_block"}, + {pos: [6, 4, 6], state: "minecraft:air"}, + {pos: [6, 4, 7], state: "minecraft:air"}, + {pos: [6, 4, 8], state: "minecraft:air"}, + {pos: [7, 4, 0], state: "minecraft:air"}, + {pos: [7, 4, 1], state: "minecraft:air"}, + {pos: [7, 4, 2], state: "minecraft:air"}, + {pos: [7, 4, 3], state: "minecraft:iron_block"}, + {pos: [7, 4, 4], state: "minecraft:iron_block"}, + {pos: [7, 4, 5], state: "minecraft:iron_block"}, + {pos: [7, 4, 6], state: "minecraft:air"}, + {pos: [7, 4, 7], state: "minecraft:air"}, + {pos: [7, 4, 8], state: "minecraft:air"}, + {pos: [8, 4, 0], state: "minecraft:air"}, + {pos: [8, 4, 1], state: "minecraft:air"}, + {pos: [8, 4, 2], state: "minecraft:air"}, + {pos: [8, 4, 3], state: "minecraft:air"}, + {pos: [8, 4, 4], state: "minecraft:air"}, + {pos: [8, 4, 5], state: "minecraft:air"}, + {pos: [8, 4, 6], state: "minecraft:air"}, + {pos: [8, 4, 7], state: "minecraft:air"}, + {pos: [8, 4, 8], state: "minecraft:air"}, + {pos: [9, 4, 0], state: "minecraft:air"}, + {pos: [9, 4, 1], state: "minecraft:air"}, + {pos: [9, 4, 2], state: "minecraft:air"}, + {pos: [9, 4, 3], state: "minecraft:air"}, + {pos: [9, 4, 4], state: "minecraft:air"}, + {pos: [9, 4, 5], state: "minecraft:air"}, + {pos: [9, 4, 6], state: "minecraft:air"}, + {pos: [9, 4, 7], state: "minecraft:air"}, + {pos: [9, 4, 8], state: "minecraft:air"}, + {pos: [10, 4, 0], state: "minecraft:air"}, + {pos: [10, 4, 1], state: "minecraft:air"}, + {pos: [10, 4, 2], state: "minecraft:air"}, + {pos: [10, 4, 3], state: "minecraft:air"}, + {pos: [10, 4, 4], state: "minecraft:air"}, + {pos: [10, 4, 5], state: "minecraft:air"}, + {pos: [10, 4, 6], state: "minecraft:air"}, + {pos: [10, 4, 7], state: "minecraft:air"}, + {pos: [10, 4, 8], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [0, 5, 5], state: "minecraft:air"}, + {pos: [0, 5, 6], state: "minecraft:air"}, + {pos: [0, 5, 7], state: "minecraft:air"}, + {pos: [0, 5, 8], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "minecraft:air"}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 5], state: "minecraft:air"}, + {pos: [1, 5, 6], state: "minecraft:air"}, + {pos: [1, 5, 7], state: "minecraft:air"}, + {pos: [1, 5, 8], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "minecraft:air"}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 5], state: "minecraft:air"}, + {pos: [2, 5, 6], state: "minecraft:air"}, + {pos: [2, 5, 7], state: "minecraft:air"}, + {pos: [2, 5, 8], state: "minecraft:air"}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "minecraft:air"}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [3, 5, 5], state: "minecraft:air"}, + {pos: [3, 5, 6], state: "minecraft:air"}, + {pos: [3, 5, 7], state: "minecraft:air"}, + {pos: [3, 5, 8], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 4, Primary: 1, Secondary: -1, id: "minecraft:beacon"}}, + {pos: [4, 5, 5], state: "minecraft:air"}, + {pos: [4, 5, 6], state: "minecraft:air"}, + {pos: [4, 5, 7], state: "minecraft:air"}, + {pos: [4, 5, 8], state: "minecraft:air"}, + {pos: [5, 5, 0], state: "minecraft:air"}, + {pos: [5, 5, 1], state: "minecraft:air"}, + {pos: [5, 5, 2], state: "minecraft:air"}, + {pos: [5, 5, 3], state: "minecraft:air"}, + {pos: [5, 5, 4], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.minecraftbeacon", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [5, 5, 5], state: "minecraft:air"}, + {pos: [5, 5, 6], state: "minecraft:air"}, + {pos: [5, 5, 7], state: "minecraft:air"}, + {pos: [5, 5, 8], state: "minecraft:air"}, + {pos: [6, 5, 0], state: "minecraft:air"}, + {pos: [6, 5, 1], state: "minecraft:air"}, + {pos: [6, 5, 2], state: "minecraft:air"}, + {pos: [6, 5, 3], state: "minecraft:air"}, + {pos: [6, 5, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 4, Primary: 3, Secondary: 3, id: "minecraft:beacon"}}, + {pos: [6, 5, 5], state: "minecraft:air"}, + {pos: [6, 5, 6], state: "minecraft:air"}, + {pos: [6, 5, 7], state: "minecraft:air"}, + {pos: [6, 5, 8], state: "minecraft:air"}, + {pos: [7, 5, 0], state: "minecraft:air"}, + {pos: [7, 5, 1], state: "minecraft:air"}, + {pos: [7, 5, 2], state: "minecraft:air"}, + {pos: [7, 5, 3], state: "minecraft:air"}, + {pos: [7, 5, 4], state: "minecraft:air"}, + {pos: [7, 5, 5], state: "minecraft:air"}, + {pos: [7, 5, 6], state: "minecraft:air"}, + {pos: [7, 5, 7], state: "minecraft:air"}, + {pos: [7, 5, 8], state: "minecraft:air"}, + {pos: [8, 5, 0], state: "minecraft:air"}, + {pos: [8, 5, 1], state: "minecraft:air"}, + {pos: [8, 5, 2], state: "minecraft:air"}, + {pos: [8, 5, 3], state: "minecraft:air"}, + {pos: [8, 5, 4], state: "minecraft:air"}, + {pos: [8, 5, 5], state: "minecraft:air"}, + {pos: [8, 5, 6], state: "minecraft:air"}, + {pos: [8, 5, 7], state: "minecraft:air"}, + {pos: [8, 5, 8], state: "minecraft:air"}, + {pos: [9, 5, 0], state: "minecraft:air"}, + {pos: [9, 5, 1], state: "minecraft:air"}, + {pos: [9, 5, 2], state: "minecraft:air"}, + {pos: [9, 5, 3], state: "minecraft:air"}, + {pos: [9, 5, 4], state: "minecraft:air"}, + {pos: [9, 5, 5], state: "minecraft:air"}, + {pos: [9, 5, 6], state: "minecraft:air"}, + {pos: [9, 5, 7], state: "minecraft:air"}, + {pos: [9, 5, 8], state: "minecraft:air"}, + {pos: [10, 5, 0], state: "minecraft:air"}, + {pos: [10, 5, 1], state: "minecraft:air"}, + {pos: [10, 5, 2], state: "minecraft:air"}, + {pos: [10, 5, 3], state: "minecraft:air"}, + {pos: [10, 5, 4], state: "minecraft:air"}, + {pos: [10, 5, 5], state: "minecraft:air"}, + {pos: [10, 5, 6], state: "minecraft:air"}, + {pos: [10, 5, 7], state: "minecraft:air"}, + {pos: [10, 5, 8], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [0, 6, 5], state: "minecraft:air"}, + {pos: [0, 6, 6], state: "minecraft:air"}, + {pos: [0, 6, 7], state: "minecraft:air"}, + {pos: [0, 6, 8], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 5], state: "minecraft:air"}, + {pos: [1, 6, 6], state: "minecraft:air"}, + {pos: [1, 6, 7], state: "minecraft:air"}, + {pos: [1, 6, 8], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "minecraft:air"}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 5], state: "minecraft:air"}, + {pos: [2, 6, 6], state: "minecraft:air"}, + {pos: [2, 6, 7], state: "minecraft:air"}, + {pos: [2, 6, 8], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 5], state: "minecraft:air"}, + {pos: [3, 6, 6], state: "minecraft:air"}, + {pos: [3, 6, 7], state: "minecraft:air"}, + {pos: [3, 6, 8], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 5], state: "minecraft:air"}, + {pos: [4, 6, 6], state: "minecraft:air"}, + {pos: [4, 6, 7], state: "minecraft:air"}, + {pos: [4, 6, 8], state: "minecraft:air"}, + {pos: [5, 6, 0], state: "minecraft:air"}, + {pos: [5, 6, 1], state: "minecraft:air"}, + {pos: [5, 6, 2], state: "minecraft:air"}, + {pos: [5, 6, 3], state: "minecraft:air"}, + {pos: [5, 6, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 0, Primary: -1, Secondary: -1, id: "minecraft:beacon"}}, + {pos: [5, 6, 5], state: "minecraft:air"}, + {pos: [5, 6, 6], state: "minecraft:air"}, + {pos: [5, 6, 7], state: "minecraft:air"}, + {pos: [5, 6, 8], state: "minecraft:air"}, + {pos: [6, 6, 0], state: "minecraft:air"}, + {pos: [6, 6, 1], state: "minecraft:air"}, + {pos: [6, 6, 2], state: "minecraft:air"}, + {pos: [6, 6, 3], state: "minecraft:air"}, + {pos: [6, 6, 4], state: "minecraft:air"}, + {pos: [6, 6, 5], state: "minecraft:air"}, + {pos: [6, 6, 6], state: "minecraft:air"}, + {pos: [6, 6, 7], state: "minecraft:air"}, + {pos: [6, 6, 8], state: "minecraft:air"}, + {pos: [7, 6, 0], state: "minecraft:air"}, + {pos: [7, 6, 1], state: "minecraft:air"}, + {pos: [7, 6, 2], state: "minecraft:air"}, + {pos: [7, 6, 3], state: "minecraft:air"}, + {pos: [7, 6, 4], state: "minecraft:air"}, + {pos: [7, 6, 5], state: "minecraft:air"}, + {pos: [7, 6, 6], state: "minecraft:air"}, + {pos: [7, 6, 7], state: "minecraft:air"}, + {pos: [7, 6, 8], state: "minecraft:air"}, + {pos: [8, 6, 0], state: "minecraft:air"}, + {pos: [8, 6, 1], state: "minecraft:air"}, + {pos: [8, 6, 2], state: "minecraft:air"}, + {pos: [8, 6, 3], state: "minecraft:air"}, + {pos: [8, 6, 4], state: "minecraft:air"}, + {pos: [8, 6, 5], state: "minecraft:air"}, + {pos: [8, 6, 6], state: "minecraft:air"}, + {pos: [8, 6, 7], state: "minecraft:air"}, + {pos: [8, 6, 8], state: "minecraft:air"}, + {pos: [9, 6, 0], state: "minecraft:air"}, + {pos: [9, 6, 1], state: "minecraft:air"}, + {pos: [9, 6, 2], state: "minecraft:air"}, + {pos: [9, 6, 3], state: "minecraft:air"}, + {pos: [9, 6, 4], state: "minecraft:air"}, + {pos: [9, 6, 5], state: "minecraft:air"}, + {pos: [9, 6, 6], state: "minecraft:air"}, + {pos: [9, 6, 7], state: "minecraft:air"}, + {pos: [9, 6, 8], state: "minecraft:air"}, + {pos: [10, 6, 0], state: "minecraft:air"}, + {pos: [10, 6, 1], state: "minecraft:air"}, + {pos: [10, 6, 2], state: "minecraft:air"}, + {pos: [10, 6, 3], state: "minecraft:air"}, + {pos: [10, 6, 4], state: "minecraft:air"}, + {pos: [10, 6, 5], state: "minecraft:air"}, + {pos: [10, 6, 6], state: "minecraft:air"}, + {pos: [10, 6, 7], state: "minecraft:air"}, + {pos: [10, 6, 8], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:iron_block", + "minecraft:air", + "minecraft:beacon", + "computercraft:computer_advanced{facing:north,state:blinking}" + ] +} From 043daa725af98ba5847125a33632a08cade7042f Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 18 May 2024 18:56:51 +0200 Subject: [PATCH 38/61] Add test for Note Blocks in the Minecraft Mod Integration --- .../gametest/core/TestEvents.java | 21 +++ .../computercraft/gametest/core/TestMod.java | 5 +- .../advancedperipherals/test/ModIntegrTest.kt | 57 ++++++- .../modintegrtest.minecraftnoteblock.lua | 24 +++ .../modintegrtest.minecraftnoteblock.snbt | 139 +++++++++++++++++ ...t.minecraftnoteblock_triggering_allay.snbt | 140 ++++++++++++++++++ 6 files changed, 380 insertions(+), 6 deletions(-) create mode 100644 src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java b/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java new file mode 100644 index 000000000..af5bfe9a1 --- /dev/null +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java @@ -0,0 +1,21 @@ +package dan200.computercraft.gametest.core; + +import net.minecraft.core.BlockPos; +import net.minecraftforge.event.level.NoteBlockEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.HashMap; +import java.util.Map; + +@Mod.EventBusSubscriber(modid = TestMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class TestEvents { + public static final Map triggeredNoteBlocks = new HashMap<>(); + + @SubscribeEvent + public static void onNoteBlockTrigger(NoteBlockEvent.Play event) { + if (event.getLevel().isClientSide()) return; + triggeredNoteBlocks.put(event.getPos(), triggeredNoteBlocks.getOrDefault(event.getPos(), 0) + 1); + } + +} diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java index 8cd8c760d..116ecd458 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java @@ -32,8 +32,11 @@ import java.util.Locale; import java.util.function.Consumer; -@Mod("advancedperipheralstest") +@Mod(TestMod.MOD_ID) public class TestMod { + + public static final String MOD_ID = "advancedperipheralstest"; + public TestMod() { TestHooks.init(); diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt index 718cd41d6..8ea1206f6 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -1,10 +1,14 @@ package de.srendi.advancedperipherals.test -import dan200.computercraft.gametest.api.GameTestHolder -import dan200.computercraft.gametest.api.sequence -import dan200.computercraft.gametest.api.thenComputerOk -import net.minecraft.gametest.framework.GameTest -import net.minecraft.gametest.framework.GameTestHelper +import dan200.computercraft.gametest.api.* +import dan200.computercraft.gametest.core.TestEvents +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.* +import net.minecraft.world.InteractionHand +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.animal.allay.Allay +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items @GameTestHolder class ModIntegrTest { @@ -29,4 +33,47 @@ class ModIntegrTest { thenComputerOk(); } + @GameTest + fun minecraftNoteBlock(context: GameTestHelper) = context.sequence { + thenExecute { TestEvents.triggeredNoteBlocks.clear() } + thenComputerOk() + thenExecute { + val successBlock = BlockPos(2, 2, 1) + val failBlock = BlockPos(2, 2, 3) + + if (TestEvents.triggeredNoteBlocks.getOrDefault(context.absolutePos(successBlock), 0) != 1) + context.fail("Note Block should have played one time", successBlock) + + if (TestEvents.triggeredNoteBlocks.getOrDefault(context.absolutePos(failBlock), 0) != 0) + context.fail("Note Block should not have played", failBlock) + } + } + + @GameTest(timeoutTicks = 300) + fun minecraftNoteBlock_Triggering_Allay(context: GameTestHelper) = context.sequence { + // test if playNote triggers an allay + // related issue: https://github.com/IntelligenceModding/AdvancedPeripherals/issues/603 + + val item = Items.DIAMOND + var allay: Allay? = null + thenExecute { + allay = context.spawn(EntityType.ALLAY, 2, 3, 2) + allay?.setItemInHand(InteractionHand.MAIN_HAND, ItemStack(item)) + + context.spawnItem(item, 2f, 3f, 2f) + } + + thenWaitUntil { context.assertEntityNotPresent(EntityType.ITEM) } + thenWaitUntil { + if (allay?.inventory?.getItem(0)?.count != 1) + context.fail("Expected Allay to pick up item") + } + thenOnComputer { callPeripheral("left", "playNote") } + thenWaitUntil { context.assertEntityPresent(EntityType.ITEM) } + thenWaitUntil { + if (allay?.inventory?.getItem(0)?.count != 0) + context.fail("Expected Allay to drop item") + } + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua new file mode 100644 index 000000000..088ac2687 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua @@ -0,0 +1,24 @@ +--- +--- Advanced Peripherals tests for the Minecraft integration on Note Blocks +--- Covers `playNote`, `getNote`, `changeNoteBy`, `changeNote` +--- + +test.eq("noteBlock", peripheral.getType("left"), "Peripheral should be noteBlock") +noteBlock = peripheral.wrap("left") +test.assert(noteBlock, "Peripheral not found") + +test.eq(4, noteBlock.getNote(), "Note should be 4") +test.eq(24, noteBlock.changeNoteBy(24), "Note should be 24 after setting it to 24") +test.eq(24, noteBlock.getNote(), "Note should be 24") +test.eq(0, noteBlock.changeNote(), "Note should be 0 after cycling it") +test.eq(0, noteBlock.getNote(), "Note should be 0") +test.eq(1, noteBlock.changeNote(), "Note should be 1 after cycling it") +test.eq(1, noteBlock.getNote(), "Note should be 1") +noteBlock.playNote() + +-- this note block has a block above it, so it should not play a note +test.eq("noteBlock", peripheral.getType("right"), "Peripheral should be noteBlock") +silentNoteBlock = peripheral.wrap("right") +test.assert(silentNoteBlock, "Peripheral not found") + +silentNoteBlock.playNote() \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt new file mode 100644 index 000000000..e32bcfbcf --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:note_block{instrument:basedrum,note:4,powered:false}"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.minecraftnoteblock", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:note_block{instrument:basedrum,note:0,powered:false}"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:note_block{instrument:basedrum,note:4,powered:false}", + "minecraft:note_block{instrument:basedrum,note:0,powered:false}", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt new file mode 100644 index 000000000..5344fa82e --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:glass"}, + {pos: [0, 1, 1], state: "minecraft:glass"}, + {pos: [0, 1, 2], state: "minecraft:glass"}, + {pos: [0, 1, 3], state: "minecraft:glass"}, + {pos: [0, 1, 4], state: "minecraft:glass"}, + {pos: [1, 1, 0], state: "minecraft:glass"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:glass"}, + {pos: [2, 1, 0], state: "minecraft:glass"}, + {pos: [2, 1, 1], state: "minecraft:note_block{instrument:basedrum,note:4,powered:false}"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 1, ForgeCaps: {}, Label: "modintegrtest.minecraftnoteblock_triggering_allay", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:glass"}, + {pos: [3, 1, 0], state: "minecraft:glass"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:glass"}, + {pos: [4, 1, 0], state: "minecraft:glass"}, + {pos: [4, 1, 1], state: "minecraft:glass"}, + {pos: [4, 1, 2], state: "minecraft:glass"}, + {pos: [4, 1, 3], state: "minecraft:glass"}, + {pos: [4, 1, 4], state: "minecraft:glass"}, + {pos: [0, 2, 0], state: "minecraft:glass"}, + {pos: [0, 2, 1], state: "minecraft:glass"}, + {pos: [0, 2, 2], state: "minecraft:glass"}, + {pos: [0, 2, 3], state: "minecraft:glass"}, + {pos: [0, 2, 4], state: "minecraft:glass"}, + {pos: [1, 2, 0], state: "minecraft:glass"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:glass"}, + {pos: [2, 2, 0], state: "minecraft:glass"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:glass"}, + {pos: [3, 2, 0], state: "minecraft:glass"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:glass"}, + {pos: [4, 2, 0], state: "minecraft:glass"}, + {pos: [4, 2, 1], state: "minecraft:glass"}, + {pos: [4, 2, 2], state: "minecraft:glass"}, + {pos: [4, 2, 3], state: "minecraft:glass"}, + {pos: [4, 2, 4], state: "minecraft:glass"}, + {pos: [0, 3, 0], state: "minecraft:glass"}, + {pos: [0, 3, 1], state: "minecraft:glass"}, + {pos: [0, 3, 2], state: "minecraft:glass"}, + {pos: [0, 3, 3], state: "minecraft:glass"}, + {pos: [0, 3, 4], state: "minecraft:glass"}, + {pos: [1, 3, 0], state: "minecraft:glass"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:glass"}, + {pos: [2, 3, 0], state: "minecraft:glass"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:glass"}, + {pos: [3, 3, 0], state: "minecraft:glass"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:glass"}, + {pos: [4, 3, 0], state: "minecraft:glass"}, + {pos: [4, 3, 1], state: "minecraft:glass"}, + {pos: [4, 3, 2], state: "minecraft:glass"}, + {pos: [4, 3, 3], state: "minecraft:glass"}, + {pos: [4, 3, 4], state: "minecraft:glass"}, + {pos: [0, 4, 0], state: "minecraft:glass"}, + {pos: [0, 4, 1], state: "minecraft:glass"}, + {pos: [0, 4, 2], state: "minecraft:glass"}, + {pos: [0, 4, 3], state: "minecraft:glass"}, + {pos: [0, 4, 4], state: "minecraft:glass"}, + {pos: [1, 4, 0], state: "minecraft:glass"}, + {pos: [1, 4, 1], state: "minecraft:glass"}, + {pos: [1, 4, 2], state: "minecraft:glass"}, + {pos: [1, 4, 3], state: "minecraft:glass"}, + {pos: [1, 4, 4], state: "minecraft:glass"}, + {pos: [2, 4, 0], state: "minecraft:glass"}, + {pos: [2, 4, 1], state: "minecraft:glass"}, + {pos: [2, 4, 2], state: "minecraft:glass"}, + {pos: [2, 4, 3], state: "minecraft:glass"}, + {pos: [2, 4, 4], state: "minecraft:glass"}, + {pos: [3, 4, 0], state: "minecraft:glass"}, + {pos: [3, 4, 1], state: "minecraft:glass"}, + {pos: [3, 4, 2], state: "minecraft:glass"}, + {pos: [3, 4, 3], state: "minecraft:glass"}, + {pos: [3, 4, 4], state: "minecraft:glass"}, + {pos: [4, 4, 0], state: "minecraft:glass"}, + {pos: [4, 4, 1], state: "minecraft:glass"}, + {pos: [4, 4, 2], state: "minecraft:glass"}, + {pos: [4, 4, 3], state: "minecraft:glass"}, + {pos: [4, 4, 4], state: "minecraft:glass"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:glass", + "minecraft:note_block{instrument:basedrum,note:4,powered:false}", + "minecraft:note_block{instrument:basedrum,note:0,powered:false}", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} From f8e6df98c110f5ee5f588d49a23f4aa8f6fffbc2 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 18 May 2024 18:59:27 +0200 Subject: [PATCH 39/61] Fix style for object key accessors --- .../computer/tests/peripheraltest.geoscanner.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua index b60f15efe..455d37b85 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua @@ -9,7 +9,7 @@ function testBlockAt(result, x, y, z, expectedName, expectedTag) local blockEntry = nil for _, entry in ipairs(result) do - if entry["x"] == x and entry["y"] == y and entry["z"] == z then + if entry.x == x and entry.y == y and entry.z == z then blockEntry = entry break end From 1954f8e6f07fc0af92458fa3ab5fc12181c2cd2d Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 18 May 2024 19:48:24 +0200 Subject: [PATCH 40/61] Fix RS Integrator test flakiness --- .../kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt | 2 +- .../computer/tests/peripheraltest.rsintegrator.lua | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index c093dd97d..928892033 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -42,7 +42,7 @@ class PeripheralTest { thenComputerOk(); } - @GameTest + @GameTest(timeoutTicks = 300) fun rsIntegrator(context: GameTestHelper) = context.sequence { thenComputerOk(); } diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua index 16b430a11..36c4c0d8b 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua @@ -19,6 +19,7 @@ test.assert(second.getInput("back"), "Digital input should be true for Redstone -- Test output on the right integrator second.setOutput("front", true) +sleep(1) test.assert(second.getOutput("front"), "Digital output should be true") -- Test analog input on the left integrator (wired from the right integrator) @@ -26,6 +27,7 @@ test.eq(13, first.getAnalogInput("front"), "Analog input should be 13") -- Test analog output on the right integrator second.setAnalogOutput("front", 10) +sleep(1) test.eq(10, second.getAnalogOutput("front"), "Analog output should be 10") -- Test analog input on the left integrator (wired from the right integrator) From 62ee0aaf8db8b904e976aacef8df78b07f5c9984 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Tue, 21 May 2024 16:45:16 +0200 Subject: [PATCH 41/61] Readd test for isOnEnchantedSoil on Botania Flowers now that the method works correctly --- .../computer/tests/modintegrtest.botaniaflower.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua index 0d27cc1bc..911e8144a 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua @@ -11,7 +11,7 @@ test.assert(entropinnyum, "Peripheral not found") test.eq(entropinnyum.getMaxMana(), entropinnyum.getMana(), "Entropinnyum should have full mana") test.eq(6500, entropinnyum.getMaxMana(), "Entropinnyum should have a max mana of 6500") --- test.assert(entropinnyum.isOnEnchantedSoil(), "Entropinnyum should be on enchanted soil") TODO: the function is currently broken +test.assert(entropinnyum.isOnEnchantedSoil(), "Entropinnyum should be on enchanted soil") test.assert(not entropinnyum.isFloating(), "Entropinnyum should not be floating") -- test.assert(entropinnyum.isFull(), "Entropinnyum should be full") TODO: uncomment for 1.20.1 AP versions -- test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") TODO: uncomment for 1.20.1 AP versions @@ -23,7 +23,7 @@ test.assert(endoflame, "Peripheral not found") test.eq(0, endoflame.getMana(), "Endoflame should have no mana") test.eq(300, endoflame.getMaxMana(), "Endoflame should have a max mana of 300") --- test.assert(not endoflame.isOnEnchantedSoil(), "Endoflame should not be on enchanted soil") TODO: the function is currently broken +test.assert(not endoflame.isOnEnchantedSoil(), "Endoflame should not be on enchanted soil") test.assert(not endoflame.isFloating(), "Endoflame should not be floating") -- test.assert(not endoflame.isFull(), "Endoflame should not be full") TODO: uncomment for 1.20.1 AP versions -- test.assert(endoflame.isEmpty(), "Endoflame should be empty") TODO: uncomment for 1.20.1 AP versions @@ -35,7 +35,7 @@ test.assert(kekimurus, "Peripheral not found") test.eq(1800, kekimurus.getMana(), "Kekimurus should have 1800 mana") test.eq(9001, kekimurus.getMaxMana(), "Kekimurus should have a max mana of 9001") --- test.assert(not kekimurus.isOnEnchantedSoil(), "Kekimurus should not be on enchanted soil") TODO: the function is currently broken +test.assert(not kekimurus.isOnEnchantedSoil(), "Kekimurus should not be on enchanted soil") test.assert(kekimurus.isFloating(), "Kekimurus should be floating") -- test.assert(not kekimurus.isFull(), "Kekimurus should not be full") TODO: uncomment for 1.20.1 AP versions -- test.assert(not kekimurus.isEmpty(), "Kekimurus should not be empty") TODO: uncomment for 1.20.1 AP versions From 0a0e10d5b819587fe7b613b0e82df70f8d61cfd7 Mon Sep 17 00:00:00 2001 From: Srendi Date: Tue, 21 May 2024 17:19:03 +0200 Subject: [PATCH 42/61] Revert "Implement game tests for more peripherals" --- .../computercraft/gametest/core/TestAPI.java | 13 - .../gametest/core/TestEvents.java | 21 - .../computercraft/gametest/core/TestMod.java | 5 +- .../advancedperipherals/test/ModIntegrTest.kt | 79 -- .../test/PeripheralTest.kt | 15 - .../tests/modintegrtest.botaniaflower.lua | 41 - .../tests/modintegrtest.botaniamanapool.lua | 40 - .../tests/modintegrtest.botaniaspreader.lua | 66 -- .../tests/modintegrtest.minecraftbeacon.lua | 34 - .../modintegrtest.minecraftnoteblock.lua | 24 - .../tests/peripheraltest.geoscanner.lua | 83 -- .../tests/peripheraltest.nbtstorage.lua | 38 - .../tests/peripheraltest.rsintegrator.lua | 37 - .../modintegrtest.botaniaflower.snbt | 142 ---- .../modintegrtest.botaniamanapool.snbt | 140 ---- .../modintegrtest.botaniaspreader.snbt | 142 ---- .../modintegrtest.minecraftbeacon.snbt | 707 ------------------ .../modintegrtest.minecraftnoteblock.snbt | 139 ---- ...t.minecraftnoteblock_triggering_allay.snbt | 140 ---- .../structures/peripheraltest.geoscanner.snbt | 243 ------ .../structures/peripheraltest.nbtstorage.snbt | 138 ---- .../peripheraltest.rsintegrator.snbt | 142 ---- 22 files changed, 1 insertion(+), 2428 deletions(-) delete mode 100644 src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java delete mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt delete mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java index 5ea5e8cfc..5539d9ac1 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java @@ -12,10 +12,7 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.gametest.api.ComputerState; import dan200.computercraft.gametest.api.TestExtensionsKt; -import dan200.computercraft.shared.computer.core.ServerContext; -import de.srendi.advancedperipherals.common.util.LuaConverter; import net.minecraft.gametest.framework.GameTestSequence; -import net.minecraftforge.server.ServerLifecycleHooks; import java.util.Optional; @@ -83,14 +80,4 @@ public final void ok(Optional marker) throws LuaException { public final void log(String message) { ComputerCraft.log.info("[Computer '{}'] {}", label, message); } - - @LuaFunction - public final Object getComputerPosition() { - return ServerContext.get(ServerLifecycleHooks.getCurrentServer()).registry().getComputers().stream() - .filter(computer -> computer.getLabel() != null && computer.getLabel().equals(label)) - .findFirst() - .map(computer -> LuaConverter.posToObject(computer.getPosition())) - .orElse(null); - } - } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java b/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java deleted file mode 100644 index af5bfe9a1..000000000 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java +++ /dev/null @@ -1,21 +0,0 @@ -package dan200.computercraft.gametest.core; - -import net.minecraft.core.BlockPos; -import net.minecraftforge.event.level.NoteBlockEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -import java.util.HashMap; -import java.util.Map; - -@Mod.EventBusSubscriber(modid = TestMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) -public class TestEvents { - public static final Map triggeredNoteBlocks = new HashMap<>(); - - @SubscribeEvent - public static void onNoteBlockTrigger(NoteBlockEvent.Play event) { - if (event.getLevel().isClientSide()) return; - triggeredNoteBlocks.put(event.getPos(), triggeredNoteBlocks.getOrDefault(event.getPos(), 0) + 1); - } - -} diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java index 116ecd458..8cd8c760d 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java @@ -32,11 +32,8 @@ import java.util.Locale; import java.util.function.Consumer; -@Mod(TestMod.MOD_ID) +@Mod("advancedperipheralstest") public class TestMod { - - public static final String MOD_ID = "advancedperipheralstest"; - public TestMod() { TestHooks.init(); diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt deleted file mode 100644 index 8ea1206f6..000000000 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -package de.srendi.advancedperipherals.test - -import dan200.computercraft.gametest.api.* -import dan200.computercraft.gametest.core.TestEvents -import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.* -import net.minecraft.world.InteractionHand -import net.minecraft.world.entity.EntityType -import net.minecraft.world.entity.animal.allay.Allay -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items - -@GameTestHolder -class ModIntegrTest { - - @GameTest - fun botaniaFlower(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - - @GameTest - fun botaniaManaPool(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - - @GameTest - fun botaniaSpreader(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - - @GameTest(timeoutTicks = 300) - fun minecraftBeacon(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - - @GameTest - fun minecraftNoteBlock(context: GameTestHelper) = context.sequence { - thenExecute { TestEvents.triggeredNoteBlocks.clear() } - thenComputerOk() - thenExecute { - val successBlock = BlockPos(2, 2, 1) - val failBlock = BlockPos(2, 2, 3) - - if (TestEvents.triggeredNoteBlocks.getOrDefault(context.absolutePos(successBlock), 0) != 1) - context.fail("Note Block should have played one time", successBlock) - - if (TestEvents.triggeredNoteBlocks.getOrDefault(context.absolutePos(failBlock), 0) != 0) - context.fail("Note Block should not have played", failBlock) - } - } - - @GameTest(timeoutTicks = 300) - fun minecraftNoteBlock_Triggering_Allay(context: GameTestHelper) = context.sequence { - // test if playNote triggers an allay - // related issue: https://github.com/IntelligenceModding/AdvancedPeripherals/issues/603 - - val item = Items.DIAMOND - var allay: Allay? = null - thenExecute { - allay = context.spawn(EntityType.ALLAY, 2, 3, 2) - allay?.setItemInHand(InteractionHand.MAIN_HAND, ItemStack(item)) - - context.spawnItem(item, 2f, 3f, 2f) - } - - thenWaitUntil { context.assertEntityNotPresent(EntityType.ITEM) } - thenWaitUntil { - if (allay?.inventory?.getItem(0)?.count != 1) - context.fail("Expected Allay to pick up item") - } - thenOnComputer { callPeripheral("left", "playNote") } - thenWaitUntil { context.assertEntityPresent(EntityType.ITEM) } - thenWaitUntil { - if (allay?.inventory?.getItem(0)?.count != 0) - context.fail("Expected Allay to drop item") - } - } - -} \ No newline at end of file diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 928892033..edc1b0b38 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -37,19 +37,4 @@ class PeripheralTest { thenComputerOk(); } - @GameTest - fun nbtStorage(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - - @GameTest(timeoutTicks = 300) - fun rsIntegrator(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - - @GameTest(timeoutTicks = 300) - fun geoScanner(context: GameTestHelper) = context.sequence { - thenComputerOk(); - } - } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua deleted file mode 100644 index 911e8144a..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua +++ /dev/null @@ -1,41 +0,0 @@ ---- ---- Advanced Peripherals tests for the Botania integration on Flowers ---- Covers `getMana`, `getMaxMana`, `isFloating`, ---- `isOnEnchantedSoil`, `isEmpty`, `isFull` ---- - --- Test for Entropinnyum (Flower has full mana store and is on enchanted soil) -test.eq("manaFlower", peripheral.getType("left"), "Peripheral should be manaFlower") -entropinnyum = peripheral.wrap("left") -test.assert(entropinnyum, "Peripheral not found") - -test.eq(entropinnyum.getMaxMana(), entropinnyum.getMana(), "Entropinnyum should have full mana") -test.eq(6500, entropinnyum.getMaxMana(), "Entropinnyum should have a max mana of 6500") -test.assert(entropinnyum.isOnEnchantedSoil(), "Entropinnyum should be on enchanted soil") -test.assert(not entropinnyum.isFloating(), "Entropinnyum should not be floating") --- test.assert(entropinnyum.isFull(), "Entropinnyum should be full") TODO: uncomment for 1.20.1 AP versions --- test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") TODO: uncomment for 1.20.1 AP versions - --- Test for Endoflame (Flower has no mana stored and is on normal soil) -test.eq("manaFlower", peripheral.getType("right"), "Peripheral should be manaFlower") -endoflame = peripheral.wrap("right") -test.assert(endoflame, "Peripheral not found") - -test.eq(0, endoflame.getMana(), "Endoflame should have no mana") -test.eq(300, endoflame.getMaxMana(), "Endoflame should have a max mana of 300") -test.assert(not endoflame.isOnEnchantedSoil(), "Endoflame should not be on enchanted soil") -test.assert(not endoflame.isFloating(), "Endoflame should not be floating") --- test.assert(not endoflame.isFull(), "Endoflame should not be full") TODO: uncomment for 1.20.1 AP versions --- test.assert(endoflame.isEmpty(), "Endoflame should be empty") TODO: uncomment for 1.20.1 AP versions - --- Test for Kekimurus (Flower has 1800 mana stored and is floating) -test.eq("manaFlower", peripheral.getType("back"), "Peripheral should be manaFlower") -kekimurus = peripheral.wrap("back") -test.assert(kekimurus, "Peripheral not found") - -test.eq(1800, kekimurus.getMana(), "Kekimurus should have 1800 mana") -test.eq(9001, kekimurus.getMaxMana(), "Kekimurus should have a max mana of 9001") -test.assert(not kekimurus.isOnEnchantedSoil(), "Kekimurus should not be on enchanted soil") -test.assert(kekimurus.isFloating(), "Kekimurus should be floating") --- test.assert(not kekimurus.isFull(), "Kekimurus should not be full") TODO: uncomment for 1.20.1 AP versions --- test.assert(not kekimurus.isEmpty(), "Kekimurus should not be empty") TODO: uncomment for 1.20.1 AP versions diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua deleted file mode 100644 index a7487ac3a..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua +++ /dev/null @@ -1,40 +0,0 @@ ---- ---- Advanced Peripherals tests for the Botania integration on Mana Pools ---- Covers `getMana`, `getMaxMana`, `getManaNeeded`, ---- `isEmpty`, `isFull` ---- - --- TODO Add tests for canChargeItem, hasItems and getItems in 1.20.1 AP versions - --- Test Fabulous Mana Pool (should be empty) -test.eq("manaPool", peripheral.getType("left"), "Peripheral should be manaPool") -fabulous = peripheral.wrap("left") -test.assert(fabulous, "Peripheral not found") - -test.eq(0, fabulous.getMana(), "Mana should be 0") -test.eq(1000000, fabulous.getMaxMana(), "Max mana should be 1000000") -test.eq(1000000, fabulous.getManaNeeded(), "Mana needed should be 1000000") --- test.assert(fabulous.isEmpty(), "Mana pool should be empty") TODO method currently not implemented -test.assert(not fabulous.isFull(), "Mana pool should not be full") - --- Test Mana Pool (should have 36000 mana) -test.eq("manaPool", peripheral.getType("right"), "Peripheral should be manaPool") -manaPool = peripheral.wrap("right") -test.assert(manaPool, "Peripheral not found") - -test.eq(36000, manaPool.getMana(), "Mana should be 36000") -test.eq(1000000, manaPool.getMaxMana(), "Max mana should be 1000000") -test.eq(964000, manaPool.getManaNeeded(), "Mana needed should be 964000") --- test.assert(not manaPool.isEmpty(), "Mana pool should not be empty") TODO method currently not implemented -test.assert(not manaPool.isFull(), "Mana pool should not be full") - --- Test Creative Mana Pool (should have 1000000 mana) -test.eq("manaPool", peripheral.getType("back"), "Peripheral should be manaPool") -creative = peripheral.wrap("back") -test.assert(creative, "Peripheral not found") - -test.eq(1000000, creative.getMana(), "Mana should be 1000000") -test.eq(1000000, creative.getMaxMana(), "Max mana should be 1000000") -test.eq(0, creative.getManaNeeded(), "Mana needed should be 0") --- test.assert(not creative.isEmpty(), "Mana pool should not be empty") TODO method currently not implemented -test.assert(creative.isFull(), "Mana pool should be full") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua deleted file mode 100644 index e72424f24..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua +++ /dev/null @@ -1,66 +0,0 @@ ---- ---- Advanced Peripherals tests for the Botania integration on Mana Spreaders ---- Covers `getMana`, `getMaxMana`, `getVariant`, ---- `isEmpty`, `isFull`, `getBounding` ---- - --- TODO Add tests for hasLens and getLens in 1.20.1 AP versions - --- Test basic Mana Spreader that is empty and directed towards a Mana Pool -test.eq("manaSpreader", peripheral.getType("left"), "Peripheral should be manaSpreader") -spreader = peripheral.wrap("left") -test.assert(spreader, "Peripheral not found") - -test.eq(0, spreader.getMana(), "Mana should be 0") -test.eq(1000, spreader.getMaxMana(), "Max mana should be 1000") -test.eq("MANA", spreader.getVariant(), "Variant should be MANA") --- test.assert(spreader.isEmpty(), "Mana Spreader should be empty") TODO: method returns the wrong value currently -test.assert(not spreader.isFull(), "Mana Spreader should not be full") - -bounding = spreader.getBounding() -computerPos = test.getComputerPosition() -test.assert(bounding, "Spreader binding should be returned") -test.assert(computerPos, "Computer position should be returned") - -test.eq(computerPos.x + 1, bounding.x, "Bounding x should be set to Mana pool (+1 relative to computer)") -test.eq(computerPos.y, bounding.y, "Bounding y should be set to Mana pool (same as computer)") -test.eq(computerPos.z - 1, bounding.z, "Bounding z should be set to Mana pool (-1 relative to computer") - --- Test Gaia Mana Spreader that is full -test.eq("manaSpreader", peripheral.getType("right"), "Peripheral should be manaSpreader") -gaiaSpreader = peripheral.wrap("right") -test.assert(gaiaSpreader, "Peripheral not found") - -test.eq(6400, gaiaSpreader.getMana(), "Mana should be 6400") -test.eq(6400, gaiaSpreader.getMaxMana(), "Max mana should be 6400") -test.eq("GAIA", gaiaSpreader.getVariant(), "Variant should be GAIA") --- test.assert(not gaiaSpreader.isEmpty(), "Mana Spreader should not be empty") TODO: method returns the wrong value currently -test.assert(gaiaSpreader.isFull(), "Mana Spreader should be full") - -test.assert(not gaiaSpreader.getBounding(), "Mana Spreader should not be bound to anything") - --- Test Elven Mana Spreader that has 177 mana -test.eq("manaSpreader", peripheral.getType("back"), "Peripheral should be manaSpreader") -elvenSpreader = peripheral.wrap("back") -test.assert(elvenSpreader, "Peripheral not found") - -test.eq(177, elvenSpreader.getMana(), "Mana should be 177") -test.eq(1000, elvenSpreader.getMaxMana(), "Max mana should be 1000") -test.eq("ELVEN", elvenSpreader.getVariant(), "Variant should be ELVEN") --- test.assert(not elvenSpreader.isEmpty(), "Mana Spreader should not be empty") TODO: method returns the wrong value currently -test.assert(not elvenSpreader.isFull(), "Mana Spreader should not be full") - -test.assert(not elvenSpreader.getBounding(), "Mana Spreader should not be bound to anything") - --- Test Pulse Mana Spreader that is empty -test.eq("manaSpreader", peripheral.getType("top"), "Peripheral should be manaSpreader") -pulseSpreader = peripheral.wrap("top") -test.assert(pulseSpreader, "Peripheral not found") - -test.eq(0, pulseSpreader.getMana(), "Mana should be 0") -test.eq(1000, pulseSpreader.getMaxMana(), "Max mana should be 1000") -test.eq("REDSTONE", pulseSpreader.getVariant(), "Variant should be REDSTONE") --- test.assert(pulseSpreader.isEmpty(), "Mana Spreader should be empty") TODO: method returns the wrong value currently -test.assert(not pulseSpreader.isFull(), "Mana Spreader should not be full") - -test.assert(not pulseSpreader.getBounding(), "Mana Spreader should not be bound to anything") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua deleted file mode 100644 index ee97dc0a4..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua +++ /dev/null @@ -1,34 +0,0 @@ ---- ---- Advanced Peripherals tests for the Minecraft integration on Beacons ---- Covers `getLevel`, `getPrimaryEffect`, `getSecondaryEffect` ---- - --- Wait until the beacon structure is formed -sleep(4) - --- Test left beacon, level 4, primary and secondary effect set to haste -test.eq("beacon", peripheral.getType("left"), "Peripheral should be beacon") -beacon = peripheral.wrap("left") -test.assert(beacon, "Peripheral not found") - -test.eq(4, beacon.getLevel(), "Level should be 4") -test.eq("effect.minecraft.haste", beacon.getPrimaryEffect(), "Primary effect should be haste") -test.eq("effect.minecraft.haste", beacon.getSecondaryEffect(), "Secondary effect should be haste") - --- Test right beacon, level 4, primary effect set to speed, secondary effect not set -test.eq("beacon", peripheral.getType("right"), "Peripheral should be beacon") -beacon = peripheral.wrap("right") -test.assert(beacon, "Peripheral not found") - -test.eq(4, beacon.getLevel(), "Level should be 4") -test.eq("effect.minecraft.speed", beacon.getPrimaryEffect(), "Primary effect should be haste") -test.eq("none", beacon.getSecondaryEffect(), "Secondary effect should be none") - --- Test top beacon, level 0, primary and secondary effect not set -test.eq("beacon", peripheral.getType("top"), "Peripheral should be beacon") -beacon = peripheral.wrap("top") -test.assert(beacon, "Peripheral not found") - -test.eq(0, beacon.getLevel(), "Level should be 0") -test.eq("none", beacon.getPrimaryEffect(), "Primary effect should be none") -test.eq("none", beacon.getSecondaryEffect(), "Secondary effect should be none") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua deleted file mode 100644 index 088ac2687..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua +++ /dev/null @@ -1,24 +0,0 @@ ---- ---- Advanced Peripherals tests for the Minecraft integration on Note Blocks ---- Covers `playNote`, `getNote`, `changeNoteBy`, `changeNote` ---- - -test.eq("noteBlock", peripheral.getType("left"), "Peripheral should be noteBlock") -noteBlock = peripheral.wrap("left") -test.assert(noteBlock, "Peripheral not found") - -test.eq(4, noteBlock.getNote(), "Note should be 4") -test.eq(24, noteBlock.changeNoteBy(24), "Note should be 24 after setting it to 24") -test.eq(24, noteBlock.getNote(), "Note should be 24") -test.eq(0, noteBlock.changeNote(), "Note should be 0 after cycling it") -test.eq(0, noteBlock.getNote(), "Note should be 0") -test.eq(1, noteBlock.changeNote(), "Note should be 1 after cycling it") -test.eq(1, noteBlock.getNote(), "Note should be 1") -noteBlock.playNote() - --- this note block has a block above it, so it should not play a note -test.eq("noteBlock", peripheral.getType("right"), "Peripheral should be noteBlock") -silentNoteBlock = peripheral.wrap("right") -test.assert(silentNoteBlock, "Peripheral not found") - -silentNoteBlock.playNote() \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua deleted file mode 100644 index 455d37b85..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua +++ /dev/null @@ -1,83 +0,0 @@ ---- ---- Advanced Peripherals Geo Scanner tests ---- Covers `getFuelLevel`, `getMaxFuelLevel`, `cost`, ---- `scan`, `chunkAnalyze`, `getOperationCooldown` ---- - --- TODO: replace getOperationCooldown with getScanCooldown once the function is implemented - -function testBlockAt(result, x, y, z, expectedName, expectedTag) - local blockEntry = nil - for _, entry in ipairs(result) do - if entry.x == x and entry.y == y and entry.z == z then - blockEntry = entry - break - end - end - - test.assert(blockEntry, ("Block at %d, %d, %d not found"):format(x, y, z)) - test.eq(expectedName, blockEntry["name"], ("Block at %d, %d, %d has the wrong name"):format(x, y, z)) - - local tagFound = false - for _, tag in ipairs(blockEntry["tags"]) do - if tag == expectedTag then - tagFound = true - break - end - end - test.assert(tagFound, ("Block at %d, %d, %d has the wrong tags"):format(x, y, z)) -end - -scanner = peripheral.find("geoScanner") -test.assert(scanner, "Peripheral not found") - -config = scanner.getConfiguration() -fuelEnabled = scanner.getMaxFuelLevel() > 0 - --- Test scan costs -test.eq(0, scanner.cost(1), "Scans with a range of 1 should be free") -test.eq(0, scanner.cost(config["scanBlocks"]["maxFreeRadius"]), "Scans with the maximum free radius should be free") -test.assert(scanner.cost(config["scanBlocks"]["maxFreeRadius"] + 1) > 0, "Scans with a radius larger than the maximum free radius should cost fuel") - -test.assert(scanner.cost(config["scanBlocks"]["maxCostRadius"]) > 0, "Scans with the maximum cost radius should cost fuel") -test.assert(scanner.cost(config["scanBlocks"]["maxCostRadius"] + 1) == nil, "Scans with a radius larger than the maximum cost radius should not be possible") - --- Test scan results -scanResult = scanner.scan(1) -test.assert(scanResult, "Scan result should not be nil") - -currentCooldown = scanner.getOperationCooldown("scanBlocks") -test.assert(currentCooldown > 0 and currentCooldown <= config["scanBlocks"]["cooldown"], "Cooldown should be active after a scan") - -testBlockAt(scanResult, 0, 0, 0, "advancedperipherals:geo_scanner", "minecraft:block/minecraft:mineable/pickaxe") -testBlockAt(scanResult, 0, -1, 0, "computercraft:computer_advanced", "minecraft:block/minecraft:mineable/pickaxe") -testBlockAt(scanResult, 0, 1, 0, "minecraft:iron_ore", "minecraft:block/forge:ores/iron") -testBlockAt(scanResult, 0, -1, 1, "minecraft:polished_diorite", "minecraft:block/minecraft:mineable/pickaxe") -testBlockAt(scanResult, 0, -1, -1, "minecraft:polished_andesite", "minecraft:block/minecraft:mineable/pickaxe") -testBlockAt(scanResult, 1, -1, 0, "minecraft:polished_granite", "minecraft:block/minecraft:mineable/pickaxe") - -while scanner.getOperationCooldown("scanBlocks") > 0 do - sleep(0.25) -end - --- Test chunk analysis with ores -chunkResult = scanner.chunkAnalyze() - -currentCooldown = scanner.getOperationCooldown("scanBlocks") -test.assert(currentCooldown > 0 and currentCooldown <= config["scanBlocks"]["cooldown"], "Cooldown should be active after a chunk analysis") - -test.assert(chunkResult, "Chunk analysis result should not be nil") -test.eq(1, chunkResult["minecraft:iron_ore"], "Iron ore count should be 1") -test.eq(2, chunkResult["minecraft:gold_ore"], "Gold ore count should be 2") -test.eq(3, chunkResult["minecraft:diamond_ore"], "Diamond ore count should be 3") - -while scanner.getOperationCooldown("scanBlocks") > 0 do - sleep(0.25) -end - --- Test fuel consumption -if fuelEnabled then - scanResult = scanner.scan(config["scanBlocks"]["maxFreeRadius"] + 1) - test.assert(scanResult, "Scan result should not be nil") - test.eq(scanner.getMaxFuelLevel() - scanner.cost(config["scanBlocks"]["maxFreeRadius"] + 1), scanner.getFuelLevel(), "Fuel level should be reduced after a scan") -end diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua deleted file mode 100644 index 12017d4b1..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua +++ /dev/null @@ -1,38 +0,0 @@ ---- ---- Advanced Peripherals NBT Storage tests ---- Covers `read`, `writeJson`, `writeTable` ---- - -TEST_STRING = "Hello, World!" -TEST_NUMBER = 42 -TEST_FLOAT = 3.14 -TEST_VALUE = "AP Game Test" -TEST_JSON_VALUE = "AP Game Test JSON" - -test.eq("nbtStorage", peripheral.getType("left"), "Peripheral should be nbtStorage") -storage = peripheral.wrap("left") -test.assert(storage, "Peripheral not found") - --- Read data from the test structure and verify it -stored = storage.read() -test.assert(stored, "Storage should not be nil") -test.eq(TEST_STRING, stored["test_string"], ("Stored string should be '%s'"):format(TEST_STRING)) -test.eq(TEST_NUMBER, stored["test_number"], ("Stored number should be %d"):format(TEST_NUMBER)) -test.eq(TEST_FLOAT, stored["test_float"], ("Stored float should be %f"):format(TEST_FLOAT)) - --- Write a table to the storage and verify it -storage.writeTable({ - test_value = TEST_VALUE, -}) - -stored = storage.read() -test.assert(stored, "Storage should not be nil") -test.eq(TEST_VALUE, stored["test_value"], ("Stored value should be '%s'"):format(TEST_VALUE)) - --- Write a JSON string to the storage and verify it -success = storage.writeJson(textutils.serializeJSON({test_value = TEST_JSON_VALUE})) -test.assert(success, "Storage writeJson should return true") - -stored = storage.read() -test.assert(stored, "Storage should not be nil") -test.eq(TEST_JSON_VALUE, stored["test_value"], ("Stored value should be '%s'"):format(TEST_JSON_VALUE)) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua deleted file mode 100644 index 36c4c0d8b..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua +++ /dev/null @@ -1,37 +0,0 @@ ---- ---- Advanced Peripherals Redstone Integrator tests ---- Covers `getInput`, `getOutput`, `getAnalogInput`, ---- `getAnalogOutput`, `setOutput`, `setAnalogOutput` ---- - -test.eq("redstoneIntegrator", peripheral.getType("left"), "Peripheral should be redstoneIntegrator") -test.eq("redstoneIntegrator", peripheral.getType("right"), "Peripheral should be redstoneIntegrator") - -first = peripheral.wrap("left") -test.assert(first, "Peripheral not found") - -second = peripheral.wrap("right") -test.assert(second, "Peripheral not found") - --- Test input for Redstone Block (full strength) -test.eq(15, second.getAnalogInput("back"), "Analog input should be 15 for Redstone Block") -test.assert(second.getInput("back"), "Digital input should be true for Redstone Block") - --- Test output on the right integrator -second.setOutput("front", true) -sleep(1) -test.assert(second.getOutput("front"), "Digital output should be true") - --- Test analog input on the left integrator (wired from the right integrator) -test.eq(13, first.getAnalogInput("front"), "Analog input should be 13") - --- Test analog output on the right integrator -second.setAnalogOutput("front", 10) -sleep(1) -test.eq(10, second.getAnalogOutput("front"), "Analog output should be 10") - --- Test analog input on the left integrator (wired from the right integrator) -test.eq(8, first.getAnalogInput("front"), "Analog input should be 8") - --- Reset redstone output -second.setOutput("front", false) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt deleted file mode 100644 index 02829a44b..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt +++ /dev/null @@ -1,142 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "botania:enchanted_soil"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:grass_block{snowy:false}"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "botania:entropinnyum", nbt: {ForgeCaps: {}, id: "botania:entropinnyum", mana: 6500, ticksExisted: 52900}}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniaflower", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "botania:endoflame", nbt: {ForgeCaps: {}, burnTime: 0, id: "botania:endoflame", mana: 0, ticksExisted: 9109}}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "botania:floating_kekimurus{waterlogged:false}", nbt: {ForgeCaps: {}, floating: {islandType: "GRASS"}, id: "botania:kekimurus", mana: 1800, ticksExisted: 26663}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "botania:enchanted_soil", - "minecraft:grass_block{snowy:false}", - "minecraft:air", - "botania:entropinnyum", - "computercraft:computer_advanced{facing:west,state:blinking}", - "botania:endoflame", - "botania:floating_kekimurus{waterlogged:false}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt deleted file mode 100644 index 0952833af..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt +++ /dev/null @@ -1,140 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "botania:fabulous_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 0, manaCap: 1000000, outputKey: "", outputting: 0b}}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniamanapool", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "botania:mana_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 36000, manaCap: 1000000, outputKey: "", outputting: 0b}}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "botania:creative_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 1000000, manaCap: 1000000, outputKey: "", outputting: 1b}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "botania:fabulous_pool{color:none,waterlogged:false}", - "computercraft:computer_advanced{facing:west,state:blinking}", - "botania:mana_pool{color:none,waterlogged:false}", - "botania:creative_pool{color:none,waterlogged:false}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt deleted file mode 100644 index 4e42dbe4a..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt +++ /dev/null @@ -1,142 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "botania:mana_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 10, forceClientBindingY: 60, forceClientBindingZ: -9, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 0, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 180.0f, rotationY: -14.036243f, uuid: [I; -1335544995, 1721978540, -1824636534, -1356366853]}}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniaspreader", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "botania:gaia_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 6400, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; 488019582, 1505248039, -1662086631, -1403515204]}}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "botania:mana_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 0, manaCap: 1000000, outputKey: "", outputting: 0b}}, - {pos: [3, 1, 2], state: "botania:elven_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 177, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; -360645062, -1521991436, -1469095441, -381296848]}}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "botania:redstone_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 0, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; 758151075, -302429323, -1148181277, 1481371264]}}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "botania:mana_spreader{has_scaffolding:false,waterlogged:false}", - "computercraft:computer_advanced{facing:west,state:blinking}", - "botania:gaia_spreader{has_scaffolding:false,waterlogged:false}", - "botania:mana_pool{color:none,waterlogged:false}", - "botania:elven_spreader{has_scaffolding:false,waterlogged:false}", - "botania:redstone_spreader{has_scaffolding:false,waterlogged:false}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt deleted file mode 100644 index 64f2fd44a..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt +++ /dev/null @@ -1,707 +0,0 @@ -{ - DataVersion: 3120, - size: [11, 7, 9], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [5, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [6, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [7, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [8, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [9, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 5], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 6], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 7], state: "minecraft:polished_andesite"}, - {pos: [10, 0, 8], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:iron_block"}, - {pos: [0, 1, 1], state: "minecraft:iron_block"}, - {pos: [0, 1, 2], state: "minecraft:iron_block"}, - {pos: [0, 1, 3], state: "minecraft:iron_block"}, - {pos: [0, 1, 4], state: "minecraft:iron_block"}, - {pos: [0, 1, 5], state: "minecraft:iron_block"}, - {pos: [0, 1, 6], state: "minecraft:iron_block"}, - {pos: [0, 1, 7], state: "minecraft:iron_block"}, - {pos: [0, 1, 8], state: "minecraft:iron_block"}, - {pos: [1, 1, 0], state: "minecraft:iron_block"}, - {pos: [1, 1, 1], state: "minecraft:iron_block"}, - {pos: [1, 1, 2], state: "minecraft:iron_block"}, - {pos: [1, 1, 3], state: "minecraft:iron_block"}, - {pos: [1, 1, 4], state: "minecraft:iron_block"}, - {pos: [1, 1, 5], state: "minecraft:iron_block"}, - {pos: [1, 1, 6], state: "minecraft:iron_block"}, - {pos: [1, 1, 7], state: "minecraft:iron_block"}, - {pos: [1, 1, 8], state: "minecraft:iron_block"}, - {pos: [2, 1, 0], state: "minecraft:iron_block"}, - {pos: [2, 1, 1], state: "minecraft:iron_block"}, - {pos: [2, 1, 2], state: "minecraft:iron_block"}, - {pos: [2, 1, 3], state: "minecraft:iron_block"}, - {pos: [2, 1, 4], state: "minecraft:iron_block"}, - {pos: [2, 1, 5], state: "minecraft:iron_block"}, - {pos: [2, 1, 6], state: "minecraft:iron_block"}, - {pos: [2, 1, 7], state: "minecraft:iron_block"}, - {pos: [2, 1, 8], state: "minecraft:iron_block"}, - {pos: [3, 1, 0], state: "minecraft:iron_block"}, - {pos: [3, 1, 1], state: "minecraft:iron_block"}, - {pos: [3, 1, 2], state: "minecraft:iron_block"}, - {pos: [3, 1, 3], state: "minecraft:iron_block"}, - {pos: [3, 1, 4], state: "minecraft:iron_block"}, - {pos: [3, 1, 5], state: "minecraft:iron_block"}, - {pos: [3, 1, 6], state: "minecraft:iron_block"}, - {pos: [3, 1, 7], state: "minecraft:iron_block"}, - {pos: [3, 1, 8], state: "minecraft:iron_block"}, - {pos: [4, 1, 0], state: "minecraft:iron_block"}, - {pos: [4, 1, 1], state: "minecraft:iron_block"}, - {pos: [4, 1, 2], state: "minecraft:iron_block"}, - {pos: [4, 1, 3], state: "minecraft:iron_block"}, - {pos: [4, 1, 4], state: "minecraft:iron_block"}, - {pos: [4, 1, 5], state: "minecraft:iron_block"}, - {pos: [4, 1, 6], state: "minecraft:iron_block"}, - {pos: [4, 1, 7], state: "minecraft:iron_block"}, - {pos: [4, 1, 8], state: "minecraft:iron_block"}, - {pos: [5, 1, 0], state: "minecraft:iron_block"}, - {pos: [5, 1, 1], state: "minecraft:iron_block"}, - {pos: [5, 1, 2], state: "minecraft:iron_block"}, - {pos: [5, 1, 3], state: "minecraft:iron_block"}, - {pos: [5, 1, 4], state: "minecraft:iron_block"}, - {pos: [5, 1, 5], state: "minecraft:iron_block"}, - {pos: [5, 1, 6], state: "minecraft:iron_block"}, - {pos: [5, 1, 7], state: "minecraft:iron_block"}, - {pos: [5, 1, 8], state: "minecraft:iron_block"}, - {pos: [6, 1, 0], state: "minecraft:iron_block"}, - {pos: [6, 1, 1], state: "minecraft:iron_block"}, - {pos: [6, 1, 2], state: "minecraft:iron_block"}, - {pos: [6, 1, 3], state: "minecraft:iron_block"}, - {pos: [6, 1, 4], state: "minecraft:iron_block"}, - {pos: [6, 1, 5], state: "minecraft:iron_block"}, - {pos: [6, 1, 6], state: "minecraft:iron_block"}, - {pos: [6, 1, 7], state: "minecraft:iron_block"}, - {pos: [6, 1, 8], state: "minecraft:iron_block"}, - {pos: [7, 1, 0], state: "minecraft:iron_block"}, - {pos: [7, 1, 1], state: "minecraft:iron_block"}, - {pos: [7, 1, 2], state: "minecraft:iron_block"}, - {pos: [7, 1, 3], state: "minecraft:iron_block"}, - {pos: [7, 1, 4], state: "minecraft:iron_block"}, - {pos: [7, 1, 5], state: "minecraft:iron_block"}, - {pos: [7, 1, 6], state: "minecraft:iron_block"}, - {pos: [7, 1, 7], state: "minecraft:iron_block"}, - {pos: [7, 1, 8], state: "minecraft:iron_block"}, - {pos: [8, 1, 0], state: "minecraft:iron_block"}, - {pos: [8, 1, 1], state: "minecraft:iron_block"}, - {pos: [8, 1, 2], state: "minecraft:iron_block"}, - {pos: [8, 1, 3], state: "minecraft:iron_block"}, - {pos: [8, 1, 4], state: "minecraft:iron_block"}, - {pos: [8, 1, 5], state: "minecraft:iron_block"}, - {pos: [8, 1, 6], state: "minecraft:iron_block"}, - {pos: [8, 1, 7], state: "minecraft:iron_block"}, - {pos: [8, 1, 8], state: "minecraft:iron_block"}, - {pos: [9, 1, 0], state: "minecraft:iron_block"}, - {pos: [9, 1, 1], state: "minecraft:iron_block"}, - {pos: [9, 1, 2], state: "minecraft:iron_block"}, - {pos: [9, 1, 3], state: "minecraft:iron_block"}, - {pos: [9, 1, 4], state: "minecraft:iron_block"}, - {pos: [9, 1, 5], state: "minecraft:iron_block"}, - {pos: [9, 1, 6], state: "minecraft:iron_block"}, - {pos: [9, 1, 7], state: "minecraft:iron_block"}, - {pos: [9, 1, 8], state: "minecraft:iron_block"}, - {pos: [10, 1, 0], state: "minecraft:iron_block"}, - {pos: [10, 1, 1], state: "minecraft:iron_block"}, - {pos: [10, 1, 2], state: "minecraft:iron_block"}, - {pos: [10, 1, 3], state: "minecraft:iron_block"}, - {pos: [10, 1, 4], state: "minecraft:iron_block"}, - {pos: [10, 1, 5], state: "minecraft:iron_block"}, - {pos: [10, 1, 6], state: "minecraft:iron_block"}, - {pos: [10, 1, 7], state: "minecraft:iron_block"}, - {pos: [10, 1, 8], state: "minecraft:iron_block"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [0, 2, 5], state: "minecraft:air"}, - {pos: [0, 2, 6], state: "minecraft:air"}, - {pos: [0, 2, 7], state: "minecraft:air"}, - {pos: [0, 2, 8], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:iron_block"}, - {pos: [1, 2, 2], state: "minecraft:iron_block"}, - {pos: [1, 2, 3], state: "minecraft:iron_block"}, - {pos: [1, 2, 4], state: "minecraft:iron_block"}, - {pos: [1, 2, 5], state: "minecraft:iron_block"}, - {pos: [1, 2, 6], state: "minecraft:iron_block"}, - {pos: [1, 2, 7], state: "minecraft:iron_block"}, - {pos: [1, 2, 8], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:iron_block"}, - {pos: [2, 2, 2], state: "minecraft:iron_block"}, - {pos: [2, 2, 3], state: "minecraft:iron_block"}, - {pos: [2, 2, 4], state: "minecraft:iron_block"}, - {pos: [2, 2, 5], state: "minecraft:iron_block"}, - {pos: [2, 2, 6], state: "minecraft:iron_block"}, - {pos: [2, 2, 7], state: "minecraft:iron_block"}, - {pos: [2, 2, 8], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:iron_block"}, - {pos: [3, 2, 2], state: "minecraft:iron_block"}, - {pos: [3, 2, 3], state: "minecraft:iron_block"}, - {pos: [3, 2, 4], state: "minecraft:iron_block"}, - {pos: [3, 2, 5], state: "minecraft:iron_block"}, - {pos: [3, 2, 6], state: "minecraft:iron_block"}, - {pos: [3, 2, 7], state: "minecraft:iron_block"}, - {pos: [3, 2, 8], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:iron_block"}, - {pos: [4, 2, 2], state: "minecraft:iron_block"}, - {pos: [4, 2, 3], state: "minecraft:iron_block"}, - {pos: [4, 2, 4], state: "minecraft:iron_block"}, - {pos: [4, 2, 5], state: "minecraft:iron_block"}, - {pos: [4, 2, 6], state: "minecraft:iron_block"}, - {pos: [4, 2, 7], state: "minecraft:iron_block"}, - {pos: [4, 2, 8], state: "minecraft:air"}, - {pos: [5, 2, 0], state: "minecraft:air"}, - {pos: [5, 2, 1], state: "minecraft:iron_block"}, - {pos: [5, 2, 2], state: "minecraft:iron_block"}, - {pos: [5, 2, 3], state: "minecraft:iron_block"}, - {pos: [5, 2, 4], state: "minecraft:iron_block"}, - {pos: [5, 2, 5], state: "minecraft:iron_block"}, - {pos: [5, 2, 6], state: "minecraft:iron_block"}, - {pos: [5, 2, 7], state: "minecraft:iron_block"}, - {pos: [5, 2, 8], state: "minecraft:air"}, - {pos: [6, 2, 0], state: "minecraft:air"}, - {pos: [6, 2, 1], state: "minecraft:iron_block"}, - {pos: [6, 2, 2], state: "minecraft:iron_block"}, - {pos: [6, 2, 3], state: "minecraft:iron_block"}, - {pos: [6, 2, 4], state: "minecraft:iron_block"}, - {pos: [6, 2, 5], state: "minecraft:iron_block"}, - {pos: [6, 2, 6], state: "minecraft:iron_block"}, - {pos: [6, 2, 7], state: "minecraft:iron_block"}, - {pos: [6, 2, 8], state: "minecraft:air"}, - {pos: [7, 2, 0], state: "minecraft:air"}, - {pos: [7, 2, 1], state: "minecraft:iron_block"}, - {pos: [7, 2, 2], state: "minecraft:iron_block"}, - {pos: [7, 2, 3], state: "minecraft:iron_block"}, - {pos: [7, 2, 4], state: "minecraft:iron_block"}, - {pos: [7, 2, 5], state: "minecraft:iron_block"}, - {pos: [7, 2, 6], state: "minecraft:iron_block"}, - {pos: [7, 2, 7], state: "minecraft:iron_block"}, - {pos: [7, 2, 8], state: "minecraft:air"}, - {pos: [8, 2, 0], state: "minecraft:air"}, - {pos: [8, 2, 1], state: "minecraft:iron_block"}, - {pos: [8, 2, 2], state: "minecraft:iron_block"}, - {pos: [8, 2, 3], state: "minecraft:iron_block"}, - {pos: [8, 2, 4], state: "minecraft:iron_block"}, - {pos: [8, 2, 5], state: "minecraft:iron_block"}, - {pos: [8, 2, 6], state: "minecraft:iron_block"}, - {pos: [8, 2, 7], state: "minecraft:iron_block"}, - {pos: [8, 2, 8], state: "minecraft:air"}, - {pos: [9, 2, 0], state: "minecraft:air"}, - {pos: [9, 2, 1], state: "minecraft:iron_block"}, - {pos: [9, 2, 2], state: "minecraft:iron_block"}, - {pos: [9, 2, 3], state: "minecraft:iron_block"}, - {pos: [9, 2, 4], state: "minecraft:iron_block"}, - {pos: [9, 2, 5], state: "minecraft:iron_block"}, - {pos: [9, 2, 6], state: "minecraft:iron_block"}, - {pos: [9, 2, 7], state: "minecraft:iron_block"}, - {pos: [9, 2, 8], state: "minecraft:air"}, - {pos: [10, 2, 0], state: "minecraft:air"}, - {pos: [10, 2, 1], state: "minecraft:air"}, - {pos: [10, 2, 2], state: "minecraft:air"}, - {pos: [10, 2, 3], state: "minecraft:air"}, - {pos: [10, 2, 4], state: "minecraft:air"}, - {pos: [10, 2, 5], state: "minecraft:air"}, - {pos: [10, 2, 6], state: "minecraft:air"}, - {pos: [10, 2, 7], state: "minecraft:air"}, - {pos: [10, 2, 8], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [0, 3, 5], state: "minecraft:air"}, - {pos: [0, 3, 6], state: "minecraft:air"}, - {pos: [0, 3, 7], state: "minecraft:air"}, - {pos: [0, 3, 8], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 5], state: "minecraft:air"}, - {pos: [1, 3, 6], state: "minecraft:air"}, - {pos: [1, 3, 7], state: "minecraft:air"}, - {pos: [1, 3, 8], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:iron_block"}, - {pos: [2, 3, 3], state: "minecraft:iron_block"}, - {pos: [2, 3, 4], state: "minecraft:iron_block"}, - {pos: [2, 3, 5], state: "minecraft:iron_block"}, - {pos: [2, 3, 6], state: "minecraft:iron_block"}, - {pos: [2, 3, 7], state: "minecraft:air"}, - {pos: [2, 3, 8], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:iron_block"}, - {pos: [3, 3, 3], state: "minecraft:iron_block"}, - {pos: [3, 3, 4], state: "minecraft:iron_block"}, - {pos: [3, 3, 5], state: "minecraft:iron_block"}, - {pos: [3, 3, 6], state: "minecraft:iron_block"}, - {pos: [3, 3, 7], state: "minecraft:air"}, - {pos: [3, 3, 8], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:iron_block"}, - {pos: [4, 3, 3], state: "minecraft:iron_block"}, - {pos: [4, 3, 4], state: "minecraft:iron_block"}, - {pos: [4, 3, 5], state: "minecraft:iron_block"}, - {pos: [4, 3, 6], state: "minecraft:iron_block"}, - {pos: [4, 3, 7], state: "minecraft:air"}, - {pos: [4, 3, 8], state: "minecraft:air"}, - {pos: [5, 3, 0], state: "minecraft:air"}, - {pos: [5, 3, 1], state: "minecraft:air"}, - {pos: [5, 3, 2], state: "minecraft:iron_block"}, - {pos: [5, 3, 3], state: "minecraft:iron_block"}, - {pos: [5, 3, 4], state: "minecraft:iron_block"}, - {pos: [5, 3, 5], state: "minecraft:iron_block"}, - {pos: [5, 3, 6], state: "minecraft:iron_block"}, - {pos: [5, 3, 7], state: "minecraft:air"}, - {pos: [5, 3, 8], state: "minecraft:air"}, - {pos: [6, 3, 0], state: "minecraft:air"}, - {pos: [6, 3, 1], state: "minecraft:air"}, - {pos: [6, 3, 2], state: "minecraft:iron_block"}, - {pos: [6, 3, 3], state: "minecraft:iron_block"}, - {pos: [6, 3, 4], state: "minecraft:iron_block"}, - {pos: [6, 3, 5], state: "minecraft:iron_block"}, - {pos: [6, 3, 6], state: "minecraft:iron_block"}, - {pos: [6, 3, 7], state: "minecraft:air"}, - {pos: [6, 3, 8], state: "minecraft:air"}, - {pos: [7, 3, 0], state: "minecraft:air"}, - {pos: [7, 3, 1], state: "minecraft:air"}, - {pos: [7, 3, 2], state: "minecraft:iron_block"}, - {pos: [7, 3, 3], state: "minecraft:iron_block"}, - {pos: [7, 3, 4], state: "minecraft:iron_block"}, - {pos: [7, 3, 5], state: "minecraft:iron_block"}, - {pos: [7, 3, 6], state: "minecraft:iron_block"}, - {pos: [7, 3, 7], state: "minecraft:air"}, - {pos: [7, 3, 8], state: "minecraft:air"}, - {pos: [8, 3, 0], state: "minecraft:air"}, - {pos: [8, 3, 1], state: "minecraft:air"}, - {pos: [8, 3, 2], state: "minecraft:iron_block"}, - {pos: [8, 3, 3], state: "minecraft:iron_block"}, - {pos: [8, 3, 4], state: "minecraft:iron_block"}, - {pos: [8, 3, 5], state: "minecraft:iron_block"}, - {pos: [8, 3, 6], state: "minecraft:iron_block"}, - {pos: [8, 3, 7], state: "minecraft:air"}, - {pos: [8, 3, 8], state: "minecraft:air"}, - {pos: [9, 3, 0], state: "minecraft:air"}, - {pos: [9, 3, 1], state: "minecraft:air"}, - {pos: [9, 3, 2], state: "minecraft:air"}, - {pos: [9, 3, 3], state: "minecraft:air"}, - {pos: [9, 3, 4], state: "minecraft:air"}, - {pos: [9, 3, 5], state: "minecraft:air"}, - {pos: [9, 3, 6], state: "minecraft:air"}, - {pos: [9, 3, 7], state: "minecraft:air"}, - {pos: [9, 3, 8], state: "minecraft:air"}, - {pos: [10, 3, 0], state: "minecraft:air"}, - {pos: [10, 3, 1], state: "minecraft:air"}, - {pos: [10, 3, 2], state: "minecraft:air"}, - {pos: [10, 3, 3], state: "minecraft:air"}, - {pos: [10, 3, 4], state: "minecraft:air"}, - {pos: [10, 3, 5], state: "minecraft:air"}, - {pos: [10, 3, 6], state: "minecraft:air"}, - {pos: [10, 3, 7], state: "minecraft:air"}, - {pos: [10, 3, 8], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [0, 4, 5], state: "minecraft:air"}, - {pos: [0, 4, 6], state: "minecraft:air"}, - {pos: [0, 4, 7], state: "minecraft:air"}, - {pos: [0, 4, 8], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 5], state: "minecraft:air"}, - {pos: [1, 4, 6], state: "minecraft:air"}, - {pos: [1, 4, 7], state: "minecraft:air"}, - {pos: [1, 4, 8], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 5], state: "minecraft:air"}, - {pos: [2, 4, 6], state: "minecraft:air"}, - {pos: [2, 4, 7], state: "minecraft:air"}, - {pos: [2, 4, 8], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:iron_block"}, - {pos: [3, 4, 4], state: "minecraft:iron_block"}, - {pos: [3, 4, 5], state: "minecraft:iron_block"}, - {pos: [3, 4, 6], state: "minecraft:air"}, - {pos: [3, 4, 7], state: "minecraft:air"}, - {pos: [3, 4, 8], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:iron_block"}, - {pos: [4, 4, 4], state: "minecraft:iron_block"}, - {pos: [4, 4, 5], state: "minecraft:iron_block"}, - {pos: [4, 4, 6], state: "minecraft:air"}, - {pos: [4, 4, 7], state: "minecraft:air"}, - {pos: [4, 4, 8], state: "minecraft:air"}, - {pos: [5, 4, 0], state: "minecraft:air"}, - {pos: [5, 4, 1], state: "minecraft:air"}, - {pos: [5, 4, 2], state: "minecraft:air"}, - {pos: [5, 4, 3], state: "minecraft:iron_block"}, - {pos: [5, 4, 4], state: "minecraft:iron_block"}, - {pos: [5, 4, 5], state: "minecraft:iron_block"}, - {pos: [5, 4, 6], state: "minecraft:air"}, - {pos: [5, 4, 7], state: "minecraft:air"}, - {pos: [5, 4, 8], state: "minecraft:air"}, - {pos: [6, 4, 0], state: "minecraft:air"}, - {pos: [6, 4, 1], state: "minecraft:air"}, - {pos: [6, 4, 2], state: "minecraft:air"}, - {pos: [6, 4, 3], state: "minecraft:iron_block"}, - {pos: [6, 4, 4], state: "minecraft:iron_block"}, - {pos: [6, 4, 5], state: "minecraft:iron_block"}, - {pos: [6, 4, 6], state: "minecraft:air"}, - {pos: [6, 4, 7], state: "minecraft:air"}, - {pos: [6, 4, 8], state: "minecraft:air"}, - {pos: [7, 4, 0], state: "minecraft:air"}, - {pos: [7, 4, 1], state: "minecraft:air"}, - {pos: [7, 4, 2], state: "minecraft:air"}, - {pos: [7, 4, 3], state: "minecraft:iron_block"}, - {pos: [7, 4, 4], state: "minecraft:iron_block"}, - {pos: [7, 4, 5], state: "minecraft:iron_block"}, - {pos: [7, 4, 6], state: "minecraft:air"}, - {pos: [7, 4, 7], state: "minecraft:air"}, - {pos: [7, 4, 8], state: "minecraft:air"}, - {pos: [8, 4, 0], state: "minecraft:air"}, - {pos: [8, 4, 1], state: "minecraft:air"}, - {pos: [8, 4, 2], state: "minecraft:air"}, - {pos: [8, 4, 3], state: "minecraft:air"}, - {pos: [8, 4, 4], state: "minecraft:air"}, - {pos: [8, 4, 5], state: "minecraft:air"}, - {pos: [8, 4, 6], state: "minecraft:air"}, - {pos: [8, 4, 7], state: "minecraft:air"}, - {pos: [8, 4, 8], state: "minecraft:air"}, - {pos: [9, 4, 0], state: "minecraft:air"}, - {pos: [9, 4, 1], state: "minecraft:air"}, - {pos: [9, 4, 2], state: "minecraft:air"}, - {pos: [9, 4, 3], state: "minecraft:air"}, - {pos: [9, 4, 4], state: "minecraft:air"}, - {pos: [9, 4, 5], state: "minecraft:air"}, - {pos: [9, 4, 6], state: "minecraft:air"}, - {pos: [9, 4, 7], state: "minecraft:air"}, - {pos: [9, 4, 8], state: "minecraft:air"}, - {pos: [10, 4, 0], state: "minecraft:air"}, - {pos: [10, 4, 1], state: "minecraft:air"}, - {pos: [10, 4, 2], state: "minecraft:air"}, - {pos: [10, 4, 3], state: "minecraft:air"}, - {pos: [10, 4, 4], state: "minecraft:air"}, - {pos: [10, 4, 5], state: "minecraft:air"}, - {pos: [10, 4, 6], state: "minecraft:air"}, - {pos: [10, 4, 7], state: "minecraft:air"}, - {pos: [10, 4, 8], state: "minecraft:air"}, - {pos: [0, 5, 0], state: "minecraft:air"}, - {pos: [0, 5, 1], state: "minecraft:air"}, - {pos: [0, 5, 2], state: "minecraft:air"}, - {pos: [0, 5, 3], state: "minecraft:air"}, - {pos: [0, 5, 4], state: "minecraft:air"}, - {pos: [0, 5, 5], state: "minecraft:air"}, - {pos: [0, 5, 6], state: "minecraft:air"}, - {pos: [0, 5, 7], state: "minecraft:air"}, - {pos: [0, 5, 8], state: "minecraft:air"}, - {pos: [1, 5, 0], state: "minecraft:air"}, - {pos: [1, 5, 1], state: "minecraft:air"}, - {pos: [1, 5, 2], state: "minecraft:air"}, - {pos: [1, 5, 3], state: "minecraft:air"}, - {pos: [1, 5, 4], state: "minecraft:air"}, - {pos: [1, 5, 5], state: "minecraft:air"}, - {pos: [1, 5, 6], state: "minecraft:air"}, - {pos: [1, 5, 7], state: "minecraft:air"}, - {pos: [1, 5, 8], state: "minecraft:air"}, - {pos: [2, 5, 0], state: "minecraft:air"}, - {pos: [2, 5, 1], state: "minecraft:air"}, - {pos: [2, 5, 2], state: "minecraft:air"}, - {pos: [2, 5, 3], state: "minecraft:air"}, - {pos: [2, 5, 4], state: "minecraft:air"}, - {pos: [2, 5, 5], state: "minecraft:air"}, - {pos: [2, 5, 6], state: "minecraft:air"}, - {pos: [2, 5, 7], state: "minecraft:air"}, - {pos: [2, 5, 8], state: "minecraft:air"}, - {pos: [3, 5, 0], state: "minecraft:air"}, - {pos: [3, 5, 1], state: "minecraft:air"}, - {pos: [3, 5, 2], state: "minecraft:air"}, - {pos: [3, 5, 3], state: "minecraft:air"}, - {pos: [3, 5, 4], state: "minecraft:air"}, - {pos: [3, 5, 5], state: "minecraft:air"}, - {pos: [3, 5, 6], state: "minecraft:air"}, - {pos: [3, 5, 7], state: "minecraft:air"}, - {pos: [3, 5, 8], state: "minecraft:air"}, - {pos: [4, 5, 0], state: "minecraft:air"}, - {pos: [4, 5, 1], state: "minecraft:air"}, - {pos: [4, 5, 2], state: "minecraft:air"}, - {pos: [4, 5, 3], state: "minecraft:air"}, - {pos: [4, 5, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 4, Primary: 1, Secondary: -1, id: "minecraft:beacon"}}, - {pos: [4, 5, 5], state: "minecraft:air"}, - {pos: [4, 5, 6], state: "minecraft:air"}, - {pos: [4, 5, 7], state: "minecraft:air"}, - {pos: [4, 5, 8], state: "minecraft:air"}, - {pos: [5, 5, 0], state: "minecraft:air"}, - {pos: [5, 5, 1], state: "minecraft:air"}, - {pos: [5, 5, 2], state: "minecraft:air"}, - {pos: [5, 5, 3], state: "minecraft:air"}, - {pos: [5, 5, 4], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.minecraftbeacon", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [5, 5, 5], state: "minecraft:air"}, - {pos: [5, 5, 6], state: "minecraft:air"}, - {pos: [5, 5, 7], state: "minecraft:air"}, - {pos: [5, 5, 8], state: "minecraft:air"}, - {pos: [6, 5, 0], state: "minecraft:air"}, - {pos: [6, 5, 1], state: "minecraft:air"}, - {pos: [6, 5, 2], state: "minecraft:air"}, - {pos: [6, 5, 3], state: "minecraft:air"}, - {pos: [6, 5, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 4, Primary: 3, Secondary: 3, id: "minecraft:beacon"}}, - {pos: [6, 5, 5], state: "minecraft:air"}, - {pos: [6, 5, 6], state: "minecraft:air"}, - {pos: [6, 5, 7], state: "minecraft:air"}, - {pos: [6, 5, 8], state: "minecraft:air"}, - {pos: [7, 5, 0], state: "minecraft:air"}, - {pos: [7, 5, 1], state: "minecraft:air"}, - {pos: [7, 5, 2], state: "minecraft:air"}, - {pos: [7, 5, 3], state: "minecraft:air"}, - {pos: [7, 5, 4], state: "minecraft:air"}, - {pos: [7, 5, 5], state: "minecraft:air"}, - {pos: [7, 5, 6], state: "minecraft:air"}, - {pos: [7, 5, 7], state: "minecraft:air"}, - {pos: [7, 5, 8], state: "minecraft:air"}, - {pos: [8, 5, 0], state: "minecraft:air"}, - {pos: [8, 5, 1], state: "minecraft:air"}, - {pos: [8, 5, 2], state: "minecraft:air"}, - {pos: [8, 5, 3], state: "minecraft:air"}, - {pos: [8, 5, 4], state: "minecraft:air"}, - {pos: [8, 5, 5], state: "minecraft:air"}, - {pos: [8, 5, 6], state: "minecraft:air"}, - {pos: [8, 5, 7], state: "minecraft:air"}, - {pos: [8, 5, 8], state: "minecraft:air"}, - {pos: [9, 5, 0], state: "minecraft:air"}, - {pos: [9, 5, 1], state: "minecraft:air"}, - {pos: [9, 5, 2], state: "minecraft:air"}, - {pos: [9, 5, 3], state: "minecraft:air"}, - {pos: [9, 5, 4], state: "minecraft:air"}, - {pos: [9, 5, 5], state: "minecraft:air"}, - {pos: [9, 5, 6], state: "minecraft:air"}, - {pos: [9, 5, 7], state: "minecraft:air"}, - {pos: [9, 5, 8], state: "minecraft:air"}, - {pos: [10, 5, 0], state: "minecraft:air"}, - {pos: [10, 5, 1], state: "minecraft:air"}, - {pos: [10, 5, 2], state: "minecraft:air"}, - {pos: [10, 5, 3], state: "minecraft:air"}, - {pos: [10, 5, 4], state: "minecraft:air"}, - {pos: [10, 5, 5], state: "minecraft:air"}, - {pos: [10, 5, 6], state: "minecraft:air"}, - {pos: [10, 5, 7], state: "minecraft:air"}, - {pos: [10, 5, 8], state: "minecraft:air"}, - {pos: [0, 6, 0], state: "minecraft:air"}, - {pos: [0, 6, 1], state: "minecraft:air"}, - {pos: [0, 6, 2], state: "minecraft:air"}, - {pos: [0, 6, 3], state: "minecraft:air"}, - {pos: [0, 6, 4], state: "minecraft:air"}, - {pos: [0, 6, 5], state: "minecraft:air"}, - {pos: [0, 6, 6], state: "minecraft:air"}, - {pos: [0, 6, 7], state: "minecraft:air"}, - {pos: [0, 6, 8], state: "minecraft:air"}, - {pos: [1, 6, 0], state: "minecraft:air"}, - {pos: [1, 6, 1], state: "minecraft:air"}, - {pos: [1, 6, 2], state: "minecraft:air"}, - {pos: [1, 6, 3], state: "minecraft:air"}, - {pos: [1, 6, 4], state: "minecraft:air"}, - {pos: [1, 6, 5], state: "minecraft:air"}, - {pos: [1, 6, 6], state: "minecraft:air"}, - {pos: [1, 6, 7], state: "minecraft:air"}, - {pos: [1, 6, 8], state: "minecraft:air"}, - {pos: [2, 6, 0], state: "minecraft:air"}, - {pos: [2, 6, 1], state: "minecraft:air"}, - {pos: [2, 6, 2], state: "minecraft:air"}, - {pos: [2, 6, 3], state: "minecraft:air"}, - {pos: [2, 6, 4], state: "minecraft:air"}, - {pos: [2, 6, 5], state: "minecraft:air"}, - {pos: [2, 6, 6], state: "minecraft:air"}, - {pos: [2, 6, 7], state: "minecraft:air"}, - {pos: [2, 6, 8], state: "minecraft:air"}, - {pos: [3, 6, 0], state: "minecraft:air"}, - {pos: [3, 6, 1], state: "minecraft:air"}, - {pos: [3, 6, 2], state: "minecraft:air"}, - {pos: [3, 6, 3], state: "minecraft:air"}, - {pos: [3, 6, 4], state: "minecraft:air"}, - {pos: [3, 6, 5], state: "minecraft:air"}, - {pos: [3, 6, 6], state: "minecraft:air"}, - {pos: [3, 6, 7], state: "minecraft:air"}, - {pos: [3, 6, 8], state: "minecraft:air"}, - {pos: [4, 6, 0], state: "minecraft:air"}, - {pos: [4, 6, 1], state: "minecraft:air"}, - {pos: [4, 6, 2], state: "minecraft:air"}, - {pos: [4, 6, 3], state: "minecraft:air"}, - {pos: [4, 6, 4], state: "minecraft:air"}, - {pos: [4, 6, 5], state: "minecraft:air"}, - {pos: [4, 6, 6], state: "minecraft:air"}, - {pos: [4, 6, 7], state: "minecraft:air"}, - {pos: [4, 6, 8], state: "minecraft:air"}, - {pos: [5, 6, 0], state: "minecraft:air"}, - {pos: [5, 6, 1], state: "minecraft:air"}, - {pos: [5, 6, 2], state: "minecraft:air"}, - {pos: [5, 6, 3], state: "minecraft:air"}, - {pos: [5, 6, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 0, Primary: -1, Secondary: -1, id: "minecraft:beacon"}}, - {pos: [5, 6, 5], state: "minecraft:air"}, - {pos: [5, 6, 6], state: "minecraft:air"}, - {pos: [5, 6, 7], state: "minecraft:air"}, - {pos: [5, 6, 8], state: "minecraft:air"}, - {pos: [6, 6, 0], state: "minecraft:air"}, - {pos: [6, 6, 1], state: "minecraft:air"}, - {pos: [6, 6, 2], state: "minecraft:air"}, - {pos: [6, 6, 3], state: "minecraft:air"}, - {pos: [6, 6, 4], state: "minecraft:air"}, - {pos: [6, 6, 5], state: "minecraft:air"}, - {pos: [6, 6, 6], state: "minecraft:air"}, - {pos: [6, 6, 7], state: "minecraft:air"}, - {pos: [6, 6, 8], state: "minecraft:air"}, - {pos: [7, 6, 0], state: "minecraft:air"}, - {pos: [7, 6, 1], state: "minecraft:air"}, - {pos: [7, 6, 2], state: "minecraft:air"}, - {pos: [7, 6, 3], state: "minecraft:air"}, - {pos: [7, 6, 4], state: "minecraft:air"}, - {pos: [7, 6, 5], state: "minecraft:air"}, - {pos: [7, 6, 6], state: "minecraft:air"}, - {pos: [7, 6, 7], state: "minecraft:air"}, - {pos: [7, 6, 8], state: "minecraft:air"}, - {pos: [8, 6, 0], state: "minecraft:air"}, - {pos: [8, 6, 1], state: "minecraft:air"}, - {pos: [8, 6, 2], state: "minecraft:air"}, - {pos: [8, 6, 3], state: "minecraft:air"}, - {pos: [8, 6, 4], state: "minecraft:air"}, - {pos: [8, 6, 5], state: "minecraft:air"}, - {pos: [8, 6, 6], state: "minecraft:air"}, - {pos: [8, 6, 7], state: "minecraft:air"}, - {pos: [8, 6, 8], state: "minecraft:air"}, - {pos: [9, 6, 0], state: "minecraft:air"}, - {pos: [9, 6, 1], state: "minecraft:air"}, - {pos: [9, 6, 2], state: "minecraft:air"}, - {pos: [9, 6, 3], state: "minecraft:air"}, - {pos: [9, 6, 4], state: "minecraft:air"}, - {pos: [9, 6, 5], state: "minecraft:air"}, - {pos: [9, 6, 6], state: "minecraft:air"}, - {pos: [9, 6, 7], state: "minecraft:air"}, - {pos: [9, 6, 8], state: "minecraft:air"}, - {pos: [10, 6, 0], state: "minecraft:air"}, - {pos: [10, 6, 1], state: "minecraft:air"}, - {pos: [10, 6, 2], state: "minecraft:air"}, - {pos: [10, 6, 3], state: "minecraft:air"}, - {pos: [10, 6, 4], state: "minecraft:air"}, - {pos: [10, 6, 5], state: "minecraft:air"}, - {pos: [10, 6, 6], state: "minecraft:air"}, - {pos: [10, 6, 7], state: "minecraft:air"}, - {pos: [10, 6, 8], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:iron_block", - "minecraft:air", - "minecraft:beacon", - "computercraft:computer_advanced{facing:north,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt deleted file mode 100644 index e32bcfbcf..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt +++ /dev/null @@ -1,139 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:note_block{instrument:basedrum,note:4,powered:false}"}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.minecraftnoteblock", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:note_block{instrument:basedrum,note:0,powered:false}"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:note_block{instrument:basedrum,note:4,powered:false}", - "minecraft:note_block{instrument:basedrum,note:0,powered:false}", - "minecraft:air", - "computercraft:computer_advanced{facing:west,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt deleted file mode 100644 index 5344fa82e..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt +++ /dev/null @@ -1,140 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:glass"}, - {pos: [0, 1, 1], state: "minecraft:glass"}, - {pos: [0, 1, 2], state: "minecraft:glass"}, - {pos: [0, 1, 3], state: "minecraft:glass"}, - {pos: [0, 1, 4], state: "minecraft:glass"}, - {pos: [1, 1, 0], state: "minecraft:glass"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:glass"}, - {pos: [2, 1, 0], state: "minecraft:glass"}, - {pos: [2, 1, 1], state: "minecraft:note_block{instrument:basedrum,note:4,powered:false}"}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 1, ForgeCaps: {}, Label: "modintegrtest.minecraftnoteblock_triggering_allay", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:glass"}, - {pos: [3, 1, 0], state: "minecraft:glass"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:glass"}, - {pos: [4, 1, 0], state: "minecraft:glass"}, - {pos: [4, 1, 1], state: "minecraft:glass"}, - {pos: [4, 1, 2], state: "minecraft:glass"}, - {pos: [4, 1, 3], state: "minecraft:glass"}, - {pos: [4, 1, 4], state: "minecraft:glass"}, - {pos: [0, 2, 0], state: "minecraft:glass"}, - {pos: [0, 2, 1], state: "minecraft:glass"}, - {pos: [0, 2, 2], state: "minecraft:glass"}, - {pos: [0, 2, 3], state: "minecraft:glass"}, - {pos: [0, 2, 4], state: "minecraft:glass"}, - {pos: [1, 2, 0], state: "minecraft:glass"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:glass"}, - {pos: [2, 2, 0], state: "minecraft:glass"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:glass"}, - {pos: [3, 2, 0], state: "minecraft:glass"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:glass"}, - {pos: [4, 2, 0], state: "minecraft:glass"}, - {pos: [4, 2, 1], state: "minecraft:glass"}, - {pos: [4, 2, 2], state: "minecraft:glass"}, - {pos: [4, 2, 3], state: "minecraft:glass"}, - {pos: [4, 2, 4], state: "minecraft:glass"}, - {pos: [0, 3, 0], state: "minecraft:glass"}, - {pos: [0, 3, 1], state: "minecraft:glass"}, - {pos: [0, 3, 2], state: "minecraft:glass"}, - {pos: [0, 3, 3], state: "minecraft:glass"}, - {pos: [0, 3, 4], state: "minecraft:glass"}, - {pos: [1, 3, 0], state: "minecraft:glass"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:glass"}, - {pos: [2, 3, 0], state: "minecraft:glass"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:glass"}, - {pos: [3, 3, 0], state: "minecraft:glass"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:glass"}, - {pos: [4, 3, 0], state: "minecraft:glass"}, - {pos: [4, 3, 1], state: "minecraft:glass"}, - {pos: [4, 3, 2], state: "minecraft:glass"}, - {pos: [4, 3, 3], state: "minecraft:glass"}, - {pos: [4, 3, 4], state: "minecraft:glass"}, - {pos: [0, 4, 0], state: "minecraft:glass"}, - {pos: [0, 4, 1], state: "minecraft:glass"}, - {pos: [0, 4, 2], state: "minecraft:glass"}, - {pos: [0, 4, 3], state: "minecraft:glass"}, - {pos: [0, 4, 4], state: "minecraft:glass"}, - {pos: [1, 4, 0], state: "minecraft:glass"}, - {pos: [1, 4, 1], state: "minecraft:glass"}, - {pos: [1, 4, 2], state: "minecraft:glass"}, - {pos: [1, 4, 3], state: "minecraft:glass"}, - {pos: [1, 4, 4], state: "minecraft:glass"}, - {pos: [2, 4, 0], state: "minecraft:glass"}, - {pos: [2, 4, 1], state: "minecraft:glass"}, - {pos: [2, 4, 2], state: "minecraft:glass"}, - {pos: [2, 4, 3], state: "minecraft:glass"}, - {pos: [2, 4, 4], state: "minecraft:glass"}, - {pos: [3, 4, 0], state: "minecraft:glass"}, - {pos: [3, 4, 1], state: "minecraft:glass"}, - {pos: [3, 4, 2], state: "minecraft:glass"}, - {pos: [3, 4, 3], state: "minecraft:glass"}, - {pos: [3, 4, 4], state: "minecraft:glass"}, - {pos: [4, 4, 0], state: "minecraft:glass"}, - {pos: [4, 4, 1], state: "minecraft:glass"}, - {pos: [4, 4, 2], state: "minecraft:glass"}, - {pos: [4, 4, 3], state: "minecraft:glass"}, - {pos: [4, 4, 4], state: "minecraft:glass"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:glass", - "minecraft:note_block{instrument:basedrum,note:4,powered:false}", - "minecraft:note_block{instrument:basedrum,note:0,powered:false}", - "minecraft:air", - "computercraft:computer_advanced{facing:west,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt deleted file mode 100644 index fd6a9bf08..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt +++ /dev/null @@ -1,243 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 9, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.geoscanner", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:polished_diorite"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:polished_granite"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "advancedperipherals:geo_scanner{orientation:west_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Geo Scanner]"}, Items: [], energy: 100000000, id: "advancedperipherals:geo_scanner", peripheralSettings: {FUEL_CONSUMING_RATE: 1, cooldowns: {scanBlocks: 1715469234280L}}}}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:iron_ore"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:gold_ore"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"}, - {pos: [0, 5, 0], state: "minecraft:air"}, - {pos: [0, 5, 1], state: "minecraft:air"}, - {pos: [0, 5, 2], state: "minecraft:air"}, - {pos: [0, 5, 3], state: "minecraft:air"}, - {pos: [0, 5, 4], state: "minecraft:air"}, - {pos: [1, 5, 0], state: "minecraft:air"}, - {pos: [1, 5, 1], state: "minecraft:air"}, - {pos: [1, 5, 2], state: "minecraft:air"}, - {pos: [1, 5, 3], state: "minecraft:air"}, - {pos: [1, 5, 4], state: "minecraft:air"}, - {pos: [2, 5, 0], state: "minecraft:air"}, - {pos: [2, 5, 1], state: "minecraft:air"}, - {pos: [2, 5, 2], state: "minecraft:gold_ore"}, - {pos: [2, 5, 3], state: "minecraft:air"}, - {pos: [2, 5, 4], state: "minecraft:air"}, - {pos: [3, 5, 0], state: "minecraft:air"}, - {pos: [3, 5, 1], state: "minecraft:air"}, - {pos: [3, 5, 2], state: "minecraft:air"}, - {pos: [3, 5, 3], state: "minecraft:air"}, - {pos: [3, 5, 4], state: "minecraft:air"}, - {pos: [4, 5, 0], state: "minecraft:air"}, - {pos: [4, 5, 1], state: "minecraft:air"}, - {pos: [4, 5, 2], state: "minecraft:air"}, - {pos: [4, 5, 3], state: "minecraft:air"}, - {pos: [4, 5, 4], state: "minecraft:air"}, - {pos: [0, 6, 0], state: "minecraft:air"}, - {pos: [0, 6, 1], state: "minecraft:air"}, - {pos: [0, 6, 2], state: "minecraft:air"}, - {pos: [0, 6, 3], state: "minecraft:air"}, - {pos: [0, 6, 4], state: "minecraft:air"}, - {pos: [1, 6, 0], state: "minecraft:air"}, - {pos: [1, 6, 1], state: "minecraft:air"}, - {pos: [1, 6, 2], state: "minecraft:air"}, - {pos: [1, 6, 3], state: "minecraft:air"}, - {pos: [1, 6, 4], state: "minecraft:air"}, - {pos: [2, 6, 0], state: "minecraft:air"}, - {pos: [2, 6, 1], state: "minecraft:air"}, - {pos: [2, 6, 2], state: "minecraft:diamond_ore"}, - {pos: [2, 6, 3], state: "minecraft:air"}, - {pos: [2, 6, 4], state: "minecraft:air"}, - {pos: [3, 6, 0], state: "minecraft:air"}, - {pos: [3, 6, 1], state: "minecraft:air"}, - {pos: [3, 6, 2], state: "minecraft:air"}, - {pos: [3, 6, 3], state: "minecraft:air"}, - {pos: [3, 6, 4], state: "minecraft:air"}, - {pos: [4, 6, 0], state: "minecraft:air"}, - {pos: [4, 6, 1], state: "minecraft:air"}, - {pos: [4, 6, 2], state: "minecraft:air"}, - {pos: [4, 6, 3], state: "minecraft:air"}, - {pos: [4, 6, 4], state: "minecraft:air"}, - {pos: [0, 7, 0], state: "minecraft:air"}, - {pos: [0, 7, 1], state: "minecraft:air"}, - {pos: [0, 7, 2], state: "minecraft:air"}, - {pos: [0, 7, 3], state: "minecraft:air"}, - {pos: [0, 7, 4], state: "minecraft:air"}, - {pos: [1, 7, 0], state: "minecraft:air"}, - {pos: [1, 7, 1], state: "minecraft:air"}, - {pos: [1, 7, 2], state: "minecraft:air"}, - {pos: [1, 7, 3], state: "minecraft:air"}, - {pos: [1, 7, 4], state: "minecraft:air"}, - {pos: [2, 7, 0], state: "minecraft:air"}, - {pos: [2, 7, 1], state: "minecraft:air"}, - {pos: [2, 7, 2], state: "minecraft:diamond_ore"}, - {pos: [2, 7, 3], state: "minecraft:air"}, - {pos: [2, 7, 4], state: "minecraft:air"}, - {pos: [3, 7, 0], state: "minecraft:air"}, - {pos: [3, 7, 1], state: "minecraft:air"}, - {pos: [3, 7, 2], state: "minecraft:air"}, - {pos: [3, 7, 3], state: "minecraft:air"}, - {pos: [3, 7, 4], state: "minecraft:air"}, - {pos: [4, 7, 0], state: "minecraft:air"}, - {pos: [4, 7, 1], state: "minecraft:air"}, - {pos: [4, 7, 2], state: "minecraft:air"}, - {pos: [4, 7, 3], state: "minecraft:air"}, - {pos: [4, 7, 4], state: "minecraft:air"}, - {pos: [0, 8, 0], state: "minecraft:air"}, - {pos: [0, 8, 1], state: "minecraft:air"}, - {pos: [0, 8, 2], state: "minecraft:air"}, - {pos: [0, 8, 3], state: "minecraft:air"}, - {pos: [0, 8, 4], state: "minecraft:air"}, - {pos: [1, 8, 0], state: "minecraft:air"}, - {pos: [1, 8, 1], state: "minecraft:air"}, - {pos: [1, 8, 2], state: "minecraft:air"}, - {pos: [1, 8, 3], state: "minecraft:air"}, - {pos: [1, 8, 4], state: "minecraft:air"}, - {pos: [2, 8, 0], state: "minecraft:air"}, - {pos: [2, 8, 1], state: "minecraft:air"}, - {pos: [2, 8, 2], state: "minecraft:diamond_ore"}, - {pos: [2, 8, 3], state: "minecraft:air"}, - {pos: [2, 8, 4], state: "minecraft:air"}, - {pos: [3, 8, 0], state: "minecraft:air"}, - {pos: [3, 8, 1], state: "minecraft:air"}, - {pos: [3, 8, 2], state: "minecraft:air"}, - {pos: [3, 8, 3], state: "minecraft:air"}, - {pos: [3, 8, 4], state: "minecraft:air"}, - {pos: [4, 8, 0], state: "minecraft:air"}, - {pos: [4, 8, 1], state: "minecraft:air"}, - {pos: [4, 8, 2], state: "minecraft:air"}, - {pos: [4, 8, 3], state: "minecraft:air"}, - {pos: [4, 8, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:polished_diorite", - "minecraft:polished_granite", - "minecraft:iron_ore", - "minecraft:gold_ore", - "minecraft:diamond_ore", - "minecraft:air", - "computercraft:computer_advanced{facing:west,state:blinking}", - "advancedperipherals:geo_scanner{orientation:west_up}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt deleted file mode 100644 index 0f0515b89..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt +++ /dev/null @@ -1,138 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:air"}, - {pos: [1, 1, 2], state: "minecraft:air"}, - {pos: [1, 1, 3], state: "minecraft:air"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "advancedperipherals:nbt_storage{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[NBT Storage]"}, Items: [], id: "advancedperipherals:nbt_storage", storedData: {test_float: 3.14d, test_number: 42.0d, test_string: "Hello, World!"}}}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.nbtstorage", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "minecraft:air"}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:air"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:air", - "advancedperipherals:nbt_storage{orientation:up_east}", - "computercraft:computer_advanced{facing:west,state:blinking}" - ] -} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt deleted file mode 100644 index 0c084d522..000000000 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt +++ /dev/null @@ -1,142 +0,0 @@ -{ - DataVersion: 3120, - size: [5, 5, 5], - data: [ - {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, - {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, - {pos: [0, 1, 0], state: "minecraft:air"}, - {pos: [0, 1, 1], state: "minecraft:air"}, - {pos: [0, 1, 2], state: "minecraft:air"}, - {pos: [0, 1, 3], state: "minecraft:air"}, - {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "minecraft:redstone_wire{east:side,north:none,power:0,south:side,west:none}"}, - {pos: [1, 1, 2], state: "minecraft:redstone_wire{east:side,north:side,power:0,south:side,west:none}"}, - {pos: [1, 1, 3], state: "minecraft:redstone_wire{east:side,north:side,power:0,south:none,west:none}"}, - {pos: [1, 1, 4], state: "minecraft:air"}, - {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "advancedperipherals:redstone_integrator{orientation:west_up}", nbt: {DOWNPower: 0, EASTPower: 0, ForgeCaps: {}, ForgeData: {CustomName: "[Redstone Integrator]"}, Items: [], NORTHPower: 0, SOUTHPower: 0, UPPower: 0, WESTPower: 0, id: "advancedperipherals:redstone_integrator"}}, - {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.rsintegrator", On: 1b, id: "computercraft:computer_advanced"}}, - {pos: [2, 1, 3], state: "advancedperipherals:redstone_integrator{orientation:west_up}", nbt: {DOWNPower: 0, EASTPower: 0, ForgeCaps: {}, ForgeData: {CustomName: "[Redstone Integrator]"}, Items: [], NORTHPower: 0, SOUTHPower: 0, UPPower: 0, WESTPower: 0, id: "advancedperipherals:redstone_integrator"}}, - {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "minecraft:air"}, - {pos: [3, 1, 1], state: "minecraft:air"}, - {pos: [3, 1, 2], state: "minecraft:air"}, - {pos: [3, 1, 3], state: "minecraft:redstone_block"}, - {pos: [3, 1, 4], state: "minecraft:air"}, - {pos: [4, 1, 0], state: "minecraft:air"}, - {pos: [4, 1, 1], state: "minecraft:air"}, - {pos: [4, 1, 2], state: "minecraft:air"}, - {pos: [4, 1, 3], state: "minecraft:air"}, - {pos: [4, 1, 4], state: "minecraft:air"}, - {pos: [0, 2, 0], state: "minecraft:air"}, - {pos: [0, 2, 1], state: "minecraft:air"}, - {pos: [0, 2, 2], state: "minecraft:air"}, - {pos: [0, 2, 3], state: "minecraft:air"}, - {pos: [0, 2, 4], state: "minecraft:air"}, - {pos: [1, 2, 0], state: "minecraft:air"}, - {pos: [1, 2, 1], state: "minecraft:air"}, - {pos: [1, 2, 2], state: "minecraft:air"}, - {pos: [1, 2, 3], state: "minecraft:air"}, - {pos: [1, 2, 4], state: "minecraft:air"}, - {pos: [2, 2, 0], state: "minecraft:air"}, - {pos: [2, 2, 1], state: "minecraft:air"}, - {pos: [2, 2, 2], state: "minecraft:air"}, - {pos: [2, 2, 3], state: "minecraft:air"}, - {pos: [2, 2, 4], state: "minecraft:air"}, - {pos: [3, 2, 0], state: "minecraft:air"}, - {pos: [3, 2, 1], state: "minecraft:air"}, - {pos: [3, 2, 2], state: "minecraft:air"}, - {pos: [3, 2, 3], state: "minecraft:air"}, - {pos: [3, 2, 4], state: "minecraft:air"}, - {pos: [4, 2, 0], state: "minecraft:air"}, - {pos: [4, 2, 1], state: "minecraft:air"}, - {pos: [4, 2, 2], state: "minecraft:air"}, - {pos: [4, 2, 3], state: "minecraft:air"}, - {pos: [4, 2, 4], state: "minecraft:air"}, - {pos: [0, 3, 0], state: "minecraft:air"}, - {pos: [0, 3, 1], state: "minecraft:air"}, - {pos: [0, 3, 2], state: "minecraft:air"}, - {pos: [0, 3, 3], state: "minecraft:air"}, - {pos: [0, 3, 4], state: "minecraft:air"}, - {pos: [1, 3, 0], state: "minecraft:air"}, - {pos: [1, 3, 1], state: "minecraft:air"}, - {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, - {pos: [1, 3, 4], state: "minecraft:air"}, - {pos: [2, 3, 0], state: "minecraft:air"}, - {pos: [2, 3, 1], state: "minecraft:air"}, - {pos: [2, 3, 2], state: "minecraft:air"}, - {pos: [2, 3, 3], state: "minecraft:air"}, - {pos: [2, 3, 4], state: "minecraft:air"}, - {pos: [3, 3, 0], state: "minecraft:air"}, - {pos: [3, 3, 1], state: "minecraft:air"}, - {pos: [3, 3, 2], state: "minecraft:air"}, - {pos: [3, 3, 3], state: "minecraft:air"}, - {pos: [3, 3, 4], state: "minecraft:air"}, - {pos: [4, 3, 0], state: "minecraft:air"}, - {pos: [4, 3, 1], state: "minecraft:air"}, - {pos: [4, 3, 2], state: "minecraft:air"}, - {pos: [4, 3, 3], state: "minecraft:air"}, - {pos: [4, 3, 4], state: "minecraft:air"}, - {pos: [0, 4, 0], state: "minecraft:air"}, - {pos: [0, 4, 1], state: "minecraft:air"}, - {pos: [0, 4, 2], state: "minecraft:air"}, - {pos: [0, 4, 3], state: "minecraft:air"}, - {pos: [0, 4, 4], state: "minecraft:air"}, - {pos: [1, 4, 0], state: "minecraft:air"}, - {pos: [1, 4, 1], state: "minecraft:air"}, - {pos: [1, 4, 2], state: "minecraft:air"}, - {pos: [1, 4, 3], state: "minecraft:air"}, - {pos: [1, 4, 4], state: "minecraft:air"}, - {pos: [2, 4, 0], state: "minecraft:air"}, - {pos: [2, 4, 1], state: "minecraft:air"}, - {pos: [2, 4, 2], state: "minecraft:air"}, - {pos: [2, 4, 3], state: "minecraft:air"}, - {pos: [2, 4, 4], state: "minecraft:air"}, - {pos: [3, 4, 0], state: "minecraft:air"}, - {pos: [3, 4, 1], state: "minecraft:air"}, - {pos: [3, 4, 2], state: "minecraft:air"}, - {pos: [3, 4, 3], state: "minecraft:air"}, - {pos: [3, 4, 4], state: "minecraft:air"}, - {pos: [4, 4, 0], state: "minecraft:air"}, - {pos: [4, 4, 1], state: "minecraft:air"}, - {pos: [4, 4, 2], state: "minecraft:air"}, - {pos: [4, 4, 3], state: "minecraft:air"}, - {pos: [4, 4, 4], state: "minecraft:air"} - ], - entities: [], - palette: [ - "minecraft:polished_andesite", - "minecraft:redstone_block", - "minecraft:air", - "minecraft:redstone_wire{east:side,north:none,power:0,south:side,west:none}", - "minecraft:redstone_wire{east:side,north:side,power:0,south:side,west:none}", - "minecraft:redstone_wire{east:side,north:side,power:0,south:none,west:none}", - "advancedperipherals:redstone_integrator{orientation:west_up}", - "computercraft:computer_advanced{facing:west,state:blinking}" - ] -} From dca02be29dd3c750038dfda7d700f87474ec81a7 Mon Sep 17 00:00:00 2001 From: Srendi Date: Tue, 21 May 2024 17:35:01 +0200 Subject: [PATCH 43/61] Revert "Revert "Implement game tests for more peripherals"" --- .../computercraft/gametest/core/TestAPI.java | 13 + .../gametest/core/TestEvents.java | 21 + .../computercraft/gametest/core/TestMod.java | 5 +- .../advancedperipherals/test/ModIntegrTest.kt | 79 ++ .../test/PeripheralTest.kt | 15 + .../tests/modintegrtest.botaniaflower.lua | 41 + .../tests/modintegrtest.botaniamanapool.lua | 40 + .../tests/modintegrtest.botaniaspreader.lua | 66 ++ .../tests/modintegrtest.minecraftbeacon.lua | 34 + .../modintegrtest.minecraftnoteblock.lua | 24 + .../tests/peripheraltest.geoscanner.lua | 83 ++ .../tests/peripheraltest.nbtstorage.lua | 38 + .../tests/peripheraltest.rsintegrator.lua | 37 + .../modintegrtest.botaniaflower.snbt | 142 ++++ .../modintegrtest.botaniamanapool.snbt | 140 ++++ .../modintegrtest.botaniaspreader.snbt | 142 ++++ .../modintegrtest.minecraftbeacon.snbt | 707 ++++++++++++++++++ .../modintegrtest.minecraftnoteblock.snbt | 139 ++++ ...t.minecraftnoteblock_triggering_allay.snbt | 140 ++++ .../structures/peripheraltest.geoscanner.snbt | 243 ++++++ .../structures/peripheraltest.nbtstorage.snbt | 138 ++++ .../peripheraltest.rsintegrator.snbt | 142 ++++ 22 files changed, 2428 insertions(+), 1 deletion(-) create mode 100644 src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java index 5539d9ac1..5ea5e8cfc 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java @@ -12,7 +12,10 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.gametest.api.ComputerState; import dan200.computercraft.gametest.api.TestExtensionsKt; +import dan200.computercraft.shared.computer.core.ServerContext; +import de.srendi.advancedperipherals.common.util.LuaConverter; import net.minecraft.gametest.framework.GameTestSequence; +import net.minecraftforge.server.ServerLifecycleHooks; import java.util.Optional; @@ -80,4 +83,14 @@ public final void ok(Optional marker) throws LuaException { public final void log(String message) { ComputerCraft.log.info("[Computer '{}'] {}", label, message); } + + @LuaFunction + public final Object getComputerPosition() { + return ServerContext.get(ServerLifecycleHooks.getCurrentServer()).registry().getComputers().stream() + .filter(computer -> computer.getLabel() != null && computer.getLabel().equals(label)) + .findFirst() + .map(computer -> LuaConverter.posToObject(computer.getPosition())) + .orElse(null); + } + } diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java b/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java new file mode 100644 index 000000000..af5bfe9a1 --- /dev/null +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestEvents.java @@ -0,0 +1,21 @@ +package dan200.computercraft.gametest.core; + +import net.minecraft.core.BlockPos; +import net.minecraftforge.event.level.NoteBlockEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.HashMap; +import java.util.Map; + +@Mod.EventBusSubscriber(modid = TestMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class TestEvents { + public static final Map triggeredNoteBlocks = new HashMap<>(); + + @SubscribeEvent + public static void onNoteBlockTrigger(NoteBlockEvent.Play event) { + if (event.getLevel().isClientSide()) return; + triggeredNoteBlocks.put(event.getPos(), triggeredNoteBlocks.getOrDefault(event.getPos(), 0) + 1); + } + +} diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java index 8cd8c760d..116ecd458 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java @@ -32,8 +32,11 @@ import java.util.Locale; import java.util.function.Consumer; -@Mod("advancedperipheralstest") +@Mod(TestMod.MOD_ID) public class TestMod { + + public static final String MOD_ID = "advancedperipheralstest"; + public TestMod() { TestHooks.init(); diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt new file mode 100644 index 000000000..8ea1206f6 --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -0,0 +1,79 @@ +package de.srendi.advancedperipherals.test + +import dan200.computercraft.gametest.api.* +import dan200.computercraft.gametest.core.TestEvents +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.* +import net.minecraft.world.InteractionHand +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.animal.allay.Allay +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items + +@GameTestHolder +class ModIntegrTest { + + @GameTest + fun botaniaFlower(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + + @GameTest + fun botaniaManaPool(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + + @GameTest + fun botaniaSpreader(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + + @GameTest(timeoutTicks = 300) + fun minecraftBeacon(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + + @GameTest + fun minecraftNoteBlock(context: GameTestHelper) = context.sequence { + thenExecute { TestEvents.triggeredNoteBlocks.clear() } + thenComputerOk() + thenExecute { + val successBlock = BlockPos(2, 2, 1) + val failBlock = BlockPos(2, 2, 3) + + if (TestEvents.triggeredNoteBlocks.getOrDefault(context.absolutePos(successBlock), 0) != 1) + context.fail("Note Block should have played one time", successBlock) + + if (TestEvents.triggeredNoteBlocks.getOrDefault(context.absolutePos(failBlock), 0) != 0) + context.fail("Note Block should not have played", failBlock) + } + } + + @GameTest(timeoutTicks = 300) + fun minecraftNoteBlock_Triggering_Allay(context: GameTestHelper) = context.sequence { + // test if playNote triggers an allay + // related issue: https://github.com/IntelligenceModding/AdvancedPeripherals/issues/603 + + val item = Items.DIAMOND + var allay: Allay? = null + thenExecute { + allay = context.spawn(EntityType.ALLAY, 2, 3, 2) + allay?.setItemInHand(InteractionHand.MAIN_HAND, ItemStack(item)) + + context.spawnItem(item, 2f, 3f, 2f) + } + + thenWaitUntil { context.assertEntityNotPresent(EntityType.ITEM) } + thenWaitUntil { + if (allay?.inventory?.getItem(0)?.count != 1) + context.fail("Expected Allay to pick up item") + } + thenOnComputer { callPeripheral("left", "playNote") } + thenWaitUntil { context.assertEntityPresent(EntityType.ITEM) } + thenWaitUntil { + if (allay?.inventory?.getItem(0)?.count != 0) + context.fail("Expected Allay to drop item") + } + } + +} \ No newline at end of file diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index edc1b0b38..928892033 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -37,4 +37,19 @@ class PeripheralTest { thenComputerOk(); } + @GameTest + fun nbtStorage(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + + @GameTest(timeoutTicks = 300) + fun rsIntegrator(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + + @GameTest(timeoutTicks = 300) + fun geoScanner(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua new file mode 100644 index 000000000..911e8144a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua @@ -0,0 +1,41 @@ +--- +--- Advanced Peripherals tests for the Botania integration on Flowers +--- Covers `getMana`, `getMaxMana`, `isFloating`, +--- `isOnEnchantedSoil`, `isEmpty`, `isFull` +--- + +-- Test for Entropinnyum (Flower has full mana store and is on enchanted soil) +test.eq("manaFlower", peripheral.getType("left"), "Peripheral should be manaFlower") +entropinnyum = peripheral.wrap("left") +test.assert(entropinnyum, "Peripheral not found") + +test.eq(entropinnyum.getMaxMana(), entropinnyum.getMana(), "Entropinnyum should have full mana") +test.eq(6500, entropinnyum.getMaxMana(), "Entropinnyum should have a max mana of 6500") +test.assert(entropinnyum.isOnEnchantedSoil(), "Entropinnyum should be on enchanted soil") +test.assert(not entropinnyum.isFloating(), "Entropinnyum should not be floating") +-- test.assert(entropinnyum.isFull(), "Entropinnyum should be full") TODO: uncomment for 1.20.1 AP versions +-- test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") TODO: uncomment for 1.20.1 AP versions + +-- Test for Endoflame (Flower has no mana stored and is on normal soil) +test.eq("manaFlower", peripheral.getType("right"), "Peripheral should be manaFlower") +endoflame = peripheral.wrap("right") +test.assert(endoflame, "Peripheral not found") + +test.eq(0, endoflame.getMana(), "Endoflame should have no mana") +test.eq(300, endoflame.getMaxMana(), "Endoflame should have a max mana of 300") +test.assert(not endoflame.isOnEnchantedSoil(), "Endoflame should not be on enchanted soil") +test.assert(not endoflame.isFloating(), "Endoflame should not be floating") +-- test.assert(not endoflame.isFull(), "Endoflame should not be full") TODO: uncomment for 1.20.1 AP versions +-- test.assert(endoflame.isEmpty(), "Endoflame should be empty") TODO: uncomment for 1.20.1 AP versions + +-- Test for Kekimurus (Flower has 1800 mana stored and is floating) +test.eq("manaFlower", peripheral.getType("back"), "Peripheral should be manaFlower") +kekimurus = peripheral.wrap("back") +test.assert(kekimurus, "Peripheral not found") + +test.eq(1800, kekimurus.getMana(), "Kekimurus should have 1800 mana") +test.eq(9001, kekimurus.getMaxMana(), "Kekimurus should have a max mana of 9001") +test.assert(not kekimurus.isOnEnchantedSoil(), "Kekimurus should not be on enchanted soil") +test.assert(kekimurus.isFloating(), "Kekimurus should be floating") +-- test.assert(not kekimurus.isFull(), "Kekimurus should not be full") TODO: uncomment for 1.20.1 AP versions +-- test.assert(not kekimurus.isEmpty(), "Kekimurus should not be empty") TODO: uncomment for 1.20.1 AP versions diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua new file mode 100644 index 000000000..a7487ac3a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua @@ -0,0 +1,40 @@ +--- +--- Advanced Peripherals tests for the Botania integration on Mana Pools +--- Covers `getMana`, `getMaxMana`, `getManaNeeded`, +--- `isEmpty`, `isFull` +--- + +-- TODO Add tests for canChargeItem, hasItems and getItems in 1.20.1 AP versions + +-- Test Fabulous Mana Pool (should be empty) +test.eq("manaPool", peripheral.getType("left"), "Peripheral should be manaPool") +fabulous = peripheral.wrap("left") +test.assert(fabulous, "Peripheral not found") + +test.eq(0, fabulous.getMana(), "Mana should be 0") +test.eq(1000000, fabulous.getMaxMana(), "Max mana should be 1000000") +test.eq(1000000, fabulous.getManaNeeded(), "Mana needed should be 1000000") +-- test.assert(fabulous.isEmpty(), "Mana pool should be empty") TODO method currently not implemented +test.assert(not fabulous.isFull(), "Mana pool should not be full") + +-- Test Mana Pool (should have 36000 mana) +test.eq("manaPool", peripheral.getType("right"), "Peripheral should be manaPool") +manaPool = peripheral.wrap("right") +test.assert(manaPool, "Peripheral not found") + +test.eq(36000, manaPool.getMana(), "Mana should be 36000") +test.eq(1000000, manaPool.getMaxMana(), "Max mana should be 1000000") +test.eq(964000, manaPool.getManaNeeded(), "Mana needed should be 964000") +-- test.assert(not manaPool.isEmpty(), "Mana pool should not be empty") TODO method currently not implemented +test.assert(not manaPool.isFull(), "Mana pool should not be full") + +-- Test Creative Mana Pool (should have 1000000 mana) +test.eq("manaPool", peripheral.getType("back"), "Peripheral should be manaPool") +creative = peripheral.wrap("back") +test.assert(creative, "Peripheral not found") + +test.eq(1000000, creative.getMana(), "Mana should be 1000000") +test.eq(1000000, creative.getMaxMana(), "Max mana should be 1000000") +test.eq(0, creative.getManaNeeded(), "Mana needed should be 0") +-- test.assert(not creative.isEmpty(), "Mana pool should not be empty") TODO method currently not implemented +test.assert(creative.isFull(), "Mana pool should be full") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua new file mode 100644 index 000000000..e72424f24 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua @@ -0,0 +1,66 @@ +--- +--- Advanced Peripherals tests for the Botania integration on Mana Spreaders +--- Covers `getMana`, `getMaxMana`, `getVariant`, +--- `isEmpty`, `isFull`, `getBounding` +--- + +-- TODO Add tests for hasLens and getLens in 1.20.1 AP versions + +-- Test basic Mana Spreader that is empty and directed towards a Mana Pool +test.eq("manaSpreader", peripheral.getType("left"), "Peripheral should be manaSpreader") +spreader = peripheral.wrap("left") +test.assert(spreader, "Peripheral not found") + +test.eq(0, spreader.getMana(), "Mana should be 0") +test.eq(1000, spreader.getMaxMana(), "Max mana should be 1000") +test.eq("MANA", spreader.getVariant(), "Variant should be MANA") +-- test.assert(spreader.isEmpty(), "Mana Spreader should be empty") TODO: method returns the wrong value currently +test.assert(not spreader.isFull(), "Mana Spreader should not be full") + +bounding = spreader.getBounding() +computerPos = test.getComputerPosition() +test.assert(bounding, "Spreader binding should be returned") +test.assert(computerPos, "Computer position should be returned") + +test.eq(computerPos.x + 1, bounding.x, "Bounding x should be set to Mana pool (+1 relative to computer)") +test.eq(computerPos.y, bounding.y, "Bounding y should be set to Mana pool (same as computer)") +test.eq(computerPos.z - 1, bounding.z, "Bounding z should be set to Mana pool (-1 relative to computer") + +-- Test Gaia Mana Spreader that is full +test.eq("manaSpreader", peripheral.getType("right"), "Peripheral should be manaSpreader") +gaiaSpreader = peripheral.wrap("right") +test.assert(gaiaSpreader, "Peripheral not found") + +test.eq(6400, gaiaSpreader.getMana(), "Mana should be 6400") +test.eq(6400, gaiaSpreader.getMaxMana(), "Max mana should be 6400") +test.eq("GAIA", gaiaSpreader.getVariant(), "Variant should be GAIA") +-- test.assert(not gaiaSpreader.isEmpty(), "Mana Spreader should not be empty") TODO: method returns the wrong value currently +test.assert(gaiaSpreader.isFull(), "Mana Spreader should be full") + +test.assert(not gaiaSpreader.getBounding(), "Mana Spreader should not be bound to anything") + +-- Test Elven Mana Spreader that has 177 mana +test.eq("manaSpreader", peripheral.getType("back"), "Peripheral should be manaSpreader") +elvenSpreader = peripheral.wrap("back") +test.assert(elvenSpreader, "Peripheral not found") + +test.eq(177, elvenSpreader.getMana(), "Mana should be 177") +test.eq(1000, elvenSpreader.getMaxMana(), "Max mana should be 1000") +test.eq("ELVEN", elvenSpreader.getVariant(), "Variant should be ELVEN") +-- test.assert(not elvenSpreader.isEmpty(), "Mana Spreader should not be empty") TODO: method returns the wrong value currently +test.assert(not elvenSpreader.isFull(), "Mana Spreader should not be full") + +test.assert(not elvenSpreader.getBounding(), "Mana Spreader should not be bound to anything") + +-- Test Pulse Mana Spreader that is empty +test.eq("manaSpreader", peripheral.getType("top"), "Peripheral should be manaSpreader") +pulseSpreader = peripheral.wrap("top") +test.assert(pulseSpreader, "Peripheral not found") + +test.eq(0, pulseSpreader.getMana(), "Mana should be 0") +test.eq(1000, pulseSpreader.getMaxMana(), "Max mana should be 1000") +test.eq("REDSTONE", pulseSpreader.getVariant(), "Variant should be REDSTONE") +-- test.assert(pulseSpreader.isEmpty(), "Mana Spreader should be empty") TODO: method returns the wrong value currently +test.assert(not pulseSpreader.isFull(), "Mana Spreader should not be full") + +test.assert(not pulseSpreader.getBounding(), "Mana Spreader should not be bound to anything") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua new file mode 100644 index 000000000..ee97dc0a4 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftbeacon.lua @@ -0,0 +1,34 @@ +--- +--- Advanced Peripherals tests for the Minecraft integration on Beacons +--- Covers `getLevel`, `getPrimaryEffect`, `getSecondaryEffect` +--- + +-- Wait until the beacon structure is formed +sleep(4) + +-- Test left beacon, level 4, primary and secondary effect set to haste +test.eq("beacon", peripheral.getType("left"), "Peripheral should be beacon") +beacon = peripheral.wrap("left") +test.assert(beacon, "Peripheral not found") + +test.eq(4, beacon.getLevel(), "Level should be 4") +test.eq("effect.minecraft.haste", beacon.getPrimaryEffect(), "Primary effect should be haste") +test.eq("effect.minecraft.haste", beacon.getSecondaryEffect(), "Secondary effect should be haste") + +-- Test right beacon, level 4, primary effect set to speed, secondary effect not set +test.eq("beacon", peripheral.getType("right"), "Peripheral should be beacon") +beacon = peripheral.wrap("right") +test.assert(beacon, "Peripheral not found") + +test.eq(4, beacon.getLevel(), "Level should be 4") +test.eq("effect.minecraft.speed", beacon.getPrimaryEffect(), "Primary effect should be haste") +test.eq("none", beacon.getSecondaryEffect(), "Secondary effect should be none") + +-- Test top beacon, level 0, primary and secondary effect not set +test.eq("beacon", peripheral.getType("top"), "Peripheral should be beacon") +beacon = peripheral.wrap("top") +test.assert(beacon, "Peripheral not found") + +test.eq(0, beacon.getLevel(), "Level should be 0") +test.eq("none", beacon.getPrimaryEffect(), "Primary effect should be none") +test.eq("none", beacon.getSecondaryEffect(), "Secondary effect should be none") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua new file mode 100644 index 000000000..088ac2687 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua @@ -0,0 +1,24 @@ +--- +--- Advanced Peripherals tests for the Minecraft integration on Note Blocks +--- Covers `playNote`, `getNote`, `changeNoteBy`, `changeNote` +--- + +test.eq("noteBlock", peripheral.getType("left"), "Peripheral should be noteBlock") +noteBlock = peripheral.wrap("left") +test.assert(noteBlock, "Peripheral not found") + +test.eq(4, noteBlock.getNote(), "Note should be 4") +test.eq(24, noteBlock.changeNoteBy(24), "Note should be 24 after setting it to 24") +test.eq(24, noteBlock.getNote(), "Note should be 24") +test.eq(0, noteBlock.changeNote(), "Note should be 0 after cycling it") +test.eq(0, noteBlock.getNote(), "Note should be 0") +test.eq(1, noteBlock.changeNote(), "Note should be 1 after cycling it") +test.eq(1, noteBlock.getNote(), "Note should be 1") +noteBlock.playNote() + +-- this note block has a block above it, so it should not play a note +test.eq("noteBlock", peripheral.getType("right"), "Peripheral should be noteBlock") +silentNoteBlock = peripheral.wrap("right") +test.assert(silentNoteBlock, "Peripheral not found") + +silentNoteBlock.playNote() \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua new file mode 100644 index 000000000..455d37b85 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua @@ -0,0 +1,83 @@ +--- +--- Advanced Peripherals Geo Scanner tests +--- Covers `getFuelLevel`, `getMaxFuelLevel`, `cost`, +--- `scan`, `chunkAnalyze`, `getOperationCooldown` +--- + +-- TODO: replace getOperationCooldown with getScanCooldown once the function is implemented + +function testBlockAt(result, x, y, z, expectedName, expectedTag) + local blockEntry = nil + for _, entry in ipairs(result) do + if entry.x == x and entry.y == y and entry.z == z then + blockEntry = entry + break + end + end + + test.assert(blockEntry, ("Block at %d, %d, %d not found"):format(x, y, z)) + test.eq(expectedName, blockEntry["name"], ("Block at %d, %d, %d has the wrong name"):format(x, y, z)) + + local tagFound = false + for _, tag in ipairs(blockEntry["tags"]) do + if tag == expectedTag then + tagFound = true + break + end + end + test.assert(tagFound, ("Block at %d, %d, %d has the wrong tags"):format(x, y, z)) +end + +scanner = peripheral.find("geoScanner") +test.assert(scanner, "Peripheral not found") + +config = scanner.getConfiguration() +fuelEnabled = scanner.getMaxFuelLevel() > 0 + +-- Test scan costs +test.eq(0, scanner.cost(1), "Scans with a range of 1 should be free") +test.eq(0, scanner.cost(config["scanBlocks"]["maxFreeRadius"]), "Scans with the maximum free radius should be free") +test.assert(scanner.cost(config["scanBlocks"]["maxFreeRadius"] + 1) > 0, "Scans with a radius larger than the maximum free radius should cost fuel") + +test.assert(scanner.cost(config["scanBlocks"]["maxCostRadius"]) > 0, "Scans with the maximum cost radius should cost fuel") +test.assert(scanner.cost(config["scanBlocks"]["maxCostRadius"] + 1) == nil, "Scans with a radius larger than the maximum cost radius should not be possible") + +-- Test scan results +scanResult = scanner.scan(1) +test.assert(scanResult, "Scan result should not be nil") + +currentCooldown = scanner.getOperationCooldown("scanBlocks") +test.assert(currentCooldown > 0 and currentCooldown <= config["scanBlocks"]["cooldown"], "Cooldown should be active after a scan") + +testBlockAt(scanResult, 0, 0, 0, "advancedperipherals:geo_scanner", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 0, -1, 0, "computercraft:computer_advanced", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 0, 1, 0, "minecraft:iron_ore", "minecraft:block/forge:ores/iron") +testBlockAt(scanResult, 0, -1, 1, "minecraft:polished_diorite", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 0, -1, -1, "minecraft:polished_andesite", "minecraft:block/minecraft:mineable/pickaxe") +testBlockAt(scanResult, 1, -1, 0, "minecraft:polished_granite", "minecraft:block/minecraft:mineable/pickaxe") + +while scanner.getOperationCooldown("scanBlocks") > 0 do + sleep(0.25) +end + +-- Test chunk analysis with ores +chunkResult = scanner.chunkAnalyze() + +currentCooldown = scanner.getOperationCooldown("scanBlocks") +test.assert(currentCooldown > 0 and currentCooldown <= config["scanBlocks"]["cooldown"], "Cooldown should be active after a chunk analysis") + +test.assert(chunkResult, "Chunk analysis result should not be nil") +test.eq(1, chunkResult["minecraft:iron_ore"], "Iron ore count should be 1") +test.eq(2, chunkResult["minecraft:gold_ore"], "Gold ore count should be 2") +test.eq(3, chunkResult["minecraft:diamond_ore"], "Diamond ore count should be 3") + +while scanner.getOperationCooldown("scanBlocks") > 0 do + sleep(0.25) +end + +-- Test fuel consumption +if fuelEnabled then + scanResult = scanner.scan(config["scanBlocks"]["maxFreeRadius"] + 1) + test.assert(scanResult, "Scan result should not be nil") + test.eq(scanner.getMaxFuelLevel() - scanner.cost(config["scanBlocks"]["maxFreeRadius"] + 1), scanner.getFuelLevel(), "Fuel level should be reduced after a scan") +end diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua new file mode 100644 index 000000000..12017d4b1 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua @@ -0,0 +1,38 @@ +--- +--- Advanced Peripherals NBT Storage tests +--- Covers `read`, `writeJson`, `writeTable` +--- + +TEST_STRING = "Hello, World!" +TEST_NUMBER = 42 +TEST_FLOAT = 3.14 +TEST_VALUE = "AP Game Test" +TEST_JSON_VALUE = "AP Game Test JSON" + +test.eq("nbtStorage", peripheral.getType("left"), "Peripheral should be nbtStorage") +storage = peripheral.wrap("left") +test.assert(storage, "Peripheral not found") + +-- Read data from the test structure and verify it +stored = storage.read() +test.assert(stored, "Storage should not be nil") +test.eq(TEST_STRING, stored["test_string"], ("Stored string should be '%s'"):format(TEST_STRING)) +test.eq(TEST_NUMBER, stored["test_number"], ("Stored number should be %d"):format(TEST_NUMBER)) +test.eq(TEST_FLOAT, stored["test_float"], ("Stored float should be %f"):format(TEST_FLOAT)) + +-- Write a table to the storage and verify it +storage.writeTable({ + test_value = TEST_VALUE, +}) + +stored = storage.read() +test.assert(stored, "Storage should not be nil") +test.eq(TEST_VALUE, stored["test_value"], ("Stored value should be '%s'"):format(TEST_VALUE)) + +-- Write a JSON string to the storage and verify it +success = storage.writeJson(textutils.serializeJSON({test_value = TEST_JSON_VALUE})) +test.assert(success, "Storage writeJson should return true") + +stored = storage.read() +test.assert(stored, "Storage should not be nil") +test.eq(TEST_JSON_VALUE, stored["test_value"], ("Stored value should be '%s'"):format(TEST_JSON_VALUE)) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua new file mode 100644 index 000000000..36c4c0d8b --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua @@ -0,0 +1,37 @@ +--- +--- Advanced Peripherals Redstone Integrator tests +--- Covers `getInput`, `getOutput`, `getAnalogInput`, +--- `getAnalogOutput`, `setOutput`, `setAnalogOutput` +--- + +test.eq("redstoneIntegrator", peripheral.getType("left"), "Peripheral should be redstoneIntegrator") +test.eq("redstoneIntegrator", peripheral.getType("right"), "Peripheral should be redstoneIntegrator") + +first = peripheral.wrap("left") +test.assert(first, "Peripheral not found") + +second = peripheral.wrap("right") +test.assert(second, "Peripheral not found") + +-- Test input for Redstone Block (full strength) +test.eq(15, second.getAnalogInput("back"), "Analog input should be 15 for Redstone Block") +test.assert(second.getInput("back"), "Digital input should be true for Redstone Block") + +-- Test output on the right integrator +second.setOutput("front", true) +sleep(1) +test.assert(second.getOutput("front"), "Digital output should be true") + +-- Test analog input on the left integrator (wired from the right integrator) +test.eq(13, first.getAnalogInput("front"), "Analog input should be 13") + +-- Test analog output on the right integrator +second.setAnalogOutput("front", 10) +sleep(1) +test.eq(10, second.getAnalogOutput("front"), "Analog output should be 10") + +-- Test analog input on the left integrator (wired from the right integrator) +test.eq(8, first.getAnalogInput("front"), "Analog input should be 8") + +-- Reset redstone output +second.setOutput("front", false) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt new file mode 100644 index 000000000..02829a44b --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaflower.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "botania:enchanted_soil"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:grass_block{snowy:false}"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "botania:entropinnyum", nbt: {ForgeCaps: {}, id: "botania:entropinnyum", mana: 6500, ticksExisted: 52900}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniaflower", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "botania:endoflame", nbt: {ForgeCaps: {}, burnTime: 0, id: "botania:endoflame", mana: 0, ticksExisted: 9109}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "botania:floating_kekimurus{waterlogged:false}", nbt: {ForgeCaps: {}, floating: {islandType: "GRASS"}, id: "botania:kekimurus", mana: 1800, ticksExisted: 26663}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "botania:enchanted_soil", + "minecraft:grass_block{snowy:false}", + "minecraft:air", + "botania:entropinnyum", + "computercraft:computer_advanced{facing:west,state:blinking}", + "botania:endoflame", + "botania:floating_kekimurus{waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt new file mode 100644 index 000000000..0952833af --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniamanapool.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "botania:fabulous_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 0, manaCap: 1000000, outputKey: "", outputting: 0b}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniamanapool", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "botania:mana_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 36000, manaCap: 1000000, outputKey: "", outputting: 0b}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "botania:creative_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 1000000, manaCap: 1000000, outputKey: "", outputting: 1b}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "botania:fabulous_pool{color:none,waterlogged:false}", + "computercraft:computer_advanced{facing:west,state:blinking}", + "botania:mana_pool{color:none,waterlogged:false}", + "botania:creative_pool{color:none,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt new file mode 100644 index 000000000..4e42dbe4a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.botaniaspreader.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "botania:mana_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 10, forceClientBindingY: 60, forceClientBindingZ: -9, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 0, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 180.0f, rotationY: -14.036243f, uuid: [I; -1335544995, 1721978540, -1824636534, -1356366853]}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.botaniaspreader", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "botania:gaia_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 6400, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; 488019582, 1505248039, -1662086631, -1403515204]}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "botania:mana_pool{color:none,waterlogged:false}", nbt: {ForgeCaps: {}, canAccept: 1b, canSpare: 1b, id: "botania:mana_pool", inputKey: "", mana: 0, manaCap: 1000000, outputKey: "", outputting: 0b}}, + {pos: [3, 1, 2], state: "botania:elven_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 177, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; -360645062, -1521991436, -1469095441, -381296848]}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "botania:redstone_spreader{has_scaffolding:false,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], canShootBurst: 1b, forceClientBindingX: 0, forceClientBindingY: -2147483648, forceClientBindingZ: 0, id: "botania:mana_spreader", inputKey: "", lastPingbackX: 0.0d, lastPingbackY: -2.147483648E9d, lastPingbackZ: 0.0d, mana: 0, mapmakerOverrideEnabled: 0b, mmForcedColor: 2162464, mmForcedGravity: 0.0f, mmForcedManaLossPerTick: 4.0f, mmForcedManaPayload: 160, mmForcedTicksBeforeManaLoss: 60, mmForcedVelocityMultiplier: 1.0f, outputKey: "", paddingColor: -1, pingbackTicks: 0, requestUpdate: 0b, rotationX: 0.0f, rotationY: 90.0f, uuid: [I; 758151075, -302429323, -1148181277, 1481371264]}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "botania:mana_spreader{has_scaffolding:false,waterlogged:false}", + "computercraft:computer_advanced{facing:west,state:blinking}", + "botania:gaia_spreader{has_scaffolding:false,waterlogged:false}", + "botania:mana_pool{color:none,waterlogged:false}", + "botania:elven_spreader{has_scaffolding:false,waterlogged:false}", + "botania:redstone_spreader{has_scaffolding:false,waterlogged:false}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt new file mode 100644 index 000000000..64f2fd44a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftbeacon.snbt @@ -0,0 +1,707 @@ +{ + DataVersion: 3120, + size: [11, 7, 9], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [5, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [6, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [7, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [8, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [9, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 5], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 6], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 7], state: "minecraft:polished_andesite"}, + {pos: [10, 0, 8], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:iron_block"}, + {pos: [0, 1, 1], state: "minecraft:iron_block"}, + {pos: [0, 1, 2], state: "minecraft:iron_block"}, + {pos: [0, 1, 3], state: "minecraft:iron_block"}, + {pos: [0, 1, 4], state: "minecraft:iron_block"}, + {pos: [0, 1, 5], state: "minecraft:iron_block"}, + {pos: [0, 1, 6], state: "minecraft:iron_block"}, + {pos: [0, 1, 7], state: "minecraft:iron_block"}, + {pos: [0, 1, 8], state: "minecraft:iron_block"}, + {pos: [1, 1, 0], state: "minecraft:iron_block"}, + {pos: [1, 1, 1], state: "minecraft:iron_block"}, + {pos: [1, 1, 2], state: "minecraft:iron_block"}, + {pos: [1, 1, 3], state: "minecraft:iron_block"}, + {pos: [1, 1, 4], state: "minecraft:iron_block"}, + {pos: [1, 1, 5], state: "minecraft:iron_block"}, + {pos: [1, 1, 6], state: "minecraft:iron_block"}, + {pos: [1, 1, 7], state: "minecraft:iron_block"}, + {pos: [1, 1, 8], state: "minecraft:iron_block"}, + {pos: [2, 1, 0], state: "minecraft:iron_block"}, + {pos: [2, 1, 1], state: "minecraft:iron_block"}, + {pos: [2, 1, 2], state: "minecraft:iron_block"}, + {pos: [2, 1, 3], state: "minecraft:iron_block"}, + {pos: [2, 1, 4], state: "minecraft:iron_block"}, + {pos: [2, 1, 5], state: "minecraft:iron_block"}, + {pos: [2, 1, 6], state: "minecraft:iron_block"}, + {pos: [2, 1, 7], state: "minecraft:iron_block"}, + {pos: [2, 1, 8], state: "minecraft:iron_block"}, + {pos: [3, 1, 0], state: "minecraft:iron_block"}, + {pos: [3, 1, 1], state: "minecraft:iron_block"}, + {pos: [3, 1, 2], state: "minecraft:iron_block"}, + {pos: [3, 1, 3], state: "minecraft:iron_block"}, + {pos: [3, 1, 4], state: "minecraft:iron_block"}, + {pos: [3, 1, 5], state: "minecraft:iron_block"}, + {pos: [3, 1, 6], state: "minecraft:iron_block"}, + {pos: [3, 1, 7], state: "minecraft:iron_block"}, + {pos: [3, 1, 8], state: "minecraft:iron_block"}, + {pos: [4, 1, 0], state: "minecraft:iron_block"}, + {pos: [4, 1, 1], state: "minecraft:iron_block"}, + {pos: [4, 1, 2], state: "minecraft:iron_block"}, + {pos: [4, 1, 3], state: "minecraft:iron_block"}, + {pos: [4, 1, 4], state: "minecraft:iron_block"}, + {pos: [4, 1, 5], state: "minecraft:iron_block"}, + {pos: [4, 1, 6], state: "minecraft:iron_block"}, + {pos: [4, 1, 7], state: "minecraft:iron_block"}, + {pos: [4, 1, 8], state: "minecraft:iron_block"}, + {pos: [5, 1, 0], state: "minecraft:iron_block"}, + {pos: [5, 1, 1], state: "minecraft:iron_block"}, + {pos: [5, 1, 2], state: "minecraft:iron_block"}, + {pos: [5, 1, 3], state: "minecraft:iron_block"}, + {pos: [5, 1, 4], state: "minecraft:iron_block"}, + {pos: [5, 1, 5], state: "minecraft:iron_block"}, + {pos: [5, 1, 6], state: "minecraft:iron_block"}, + {pos: [5, 1, 7], state: "minecraft:iron_block"}, + {pos: [5, 1, 8], state: "minecraft:iron_block"}, + {pos: [6, 1, 0], state: "minecraft:iron_block"}, + {pos: [6, 1, 1], state: "minecraft:iron_block"}, + {pos: [6, 1, 2], state: "minecraft:iron_block"}, + {pos: [6, 1, 3], state: "minecraft:iron_block"}, + {pos: [6, 1, 4], state: "minecraft:iron_block"}, + {pos: [6, 1, 5], state: "minecraft:iron_block"}, + {pos: [6, 1, 6], state: "minecraft:iron_block"}, + {pos: [6, 1, 7], state: "minecraft:iron_block"}, + {pos: [6, 1, 8], state: "minecraft:iron_block"}, + {pos: [7, 1, 0], state: "minecraft:iron_block"}, + {pos: [7, 1, 1], state: "minecraft:iron_block"}, + {pos: [7, 1, 2], state: "minecraft:iron_block"}, + {pos: [7, 1, 3], state: "minecraft:iron_block"}, + {pos: [7, 1, 4], state: "minecraft:iron_block"}, + {pos: [7, 1, 5], state: "minecraft:iron_block"}, + {pos: [7, 1, 6], state: "minecraft:iron_block"}, + {pos: [7, 1, 7], state: "minecraft:iron_block"}, + {pos: [7, 1, 8], state: "minecraft:iron_block"}, + {pos: [8, 1, 0], state: "minecraft:iron_block"}, + {pos: [8, 1, 1], state: "minecraft:iron_block"}, + {pos: [8, 1, 2], state: "minecraft:iron_block"}, + {pos: [8, 1, 3], state: "minecraft:iron_block"}, + {pos: [8, 1, 4], state: "minecraft:iron_block"}, + {pos: [8, 1, 5], state: "minecraft:iron_block"}, + {pos: [8, 1, 6], state: "minecraft:iron_block"}, + {pos: [8, 1, 7], state: "minecraft:iron_block"}, + {pos: [8, 1, 8], state: "minecraft:iron_block"}, + {pos: [9, 1, 0], state: "minecraft:iron_block"}, + {pos: [9, 1, 1], state: "minecraft:iron_block"}, + {pos: [9, 1, 2], state: "minecraft:iron_block"}, + {pos: [9, 1, 3], state: "minecraft:iron_block"}, + {pos: [9, 1, 4], state: "minecraft:iron_block"}, + {pos: [9, 1, 5], state: "minecraft:iron_block"}, + {pos: [9, 1, 6], state: "minecraft:iron_block"}, + {pos: [9, 1, 7], state: "minecraft:iron_block"}, + {pos: [9, 1, 8], state: "minecraft:iron_block"}, + {pos: [10, 1, 0], state: "minecraft:iron_block"}, + {pos: [10, 1, 1], state: "minecraft:iron_block"}, + {pos: [10, 1, 2], state: "minecraft:iron_block"}, + {pos: [10, 1, 3], state: "minecraft:iron_block"}, + {pos: [10, 1, 4], state: "minecraft:iron_block"}, + {pos: [10, 1, 5], state: "minecraft:iron_block"}, + {pos: [10, 1, 6], state: "minecraft:iron_block"}, + {pos: [10, 1, 7], state: "minecraft:iron_block"}, + {pos: [10, 1, 8], state: "minecraft:iron_block"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [0, 2, 5], state: "minecraft:air"}, + {pos: [0, 2, 6], state: "minecraft:air"}, + {pos: [0, 2, 7], state: "minecraft:air"}, + {pos: [0, 2, 8], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:iron_block"}, + {pos: [1, 2, 2], state: "minecraft:iron_block"}, + {pos: [1, 2, 3], state: "minecraft:iron_block"}, + {pos: [1, 2, 4], state: "minecraft:iron_block"}, + {pos: [1, 2, 5], state: "minecraft:iron_block"}, + {pos: [1, 2, 6], state: "minecraft:iron_block"}, + {pos: [1, 2, 7], state: "minecraft:iron_block"}, + {pos: [1, 2, 8], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:iron_block"}, + {pos: [2, 2, 2], state: "minecraft:iron_block"}, + {pos: [2, 2, 3], state: "minecraft:iron_block"}, + {pos: [2, 2, 4], state: "minecraft:iron_block"}, + {pos: [2, 2, 5], state: "minecraft:iron_block"}, + {pos: [2, 2, 6], state: "minecraft:iron_block"}, + {pos: [2, 2, 7], state: "minecraft:iron_block"}, + {pos: [2, 2, 8], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:iron_block"}, + {pos: [3, 2, 2], state: "minecraft:iron_block"}, + {pos: [3, 2, 3], state: "minecraft:iron_block"}, + {pos: [3, 2, 4], state: "minecraft:iron_block"}, + {pos: [3, 2, 5], state: "minecraft:iron_block"}, + {pos: [3, 2, 6], state: "minecraft:iron_block"}, + {pos: [3, 2, 7], state: "minecraft:iron_block"}, + {pos: [3, 2, 8], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:iron_block"}, + {pos: [4, 2, 2], state: "minecraft:iron_block"}, + {pos: [4, 2, 3], state: "minecraft:iron_block"}, + {pos: [4, 2, 4], state: "minecraft:iron_block"}, + {pos: [4, 2, 5], state: "minecraft:iron_block"}, + {pos: [4, 2, 6], state: "minecraft:iron_block"}, + {pos: [4, 2, 7], state: "minecraft:iron_block"}, + {pos: [4, 2, 8], state: "minecraft:air"}, + {pos: [5, 2, 0], state: "minecraft:air"}, + {pos: [5, 2, 1], state: "minecraft:iron_block"}, + {pos: [5, 2, 2], state: "minecraft:iron_block"}, + {pos: [5, 2, 3], state: "minecraft:iron_block"}, + {pos: [5, 2, 4], state: "minecraft:iron_block"}, + {pos: [5, 2, 5], state: "minecraft:iron_block"}, + {pos: [5, 2, 6], state: "minecraft:iron_block"}, + {pos: [5, 2, 7], state: "minecraft:iron_block"}, + {pos: [5, 2, 8], state: "minecraft:air"}, + {pos: [6, 2, 0], state: "minecraft:air"}, + {pos: [6, 2, 1], state: "minecraft:iron_block"}, + {pos: [6, 2, 2], state: "minecraft:iron_block"}, + {pos: [6, 2, 3], state: "minecraft:iron_block"}, + {pos: [6, 2, 4], state: "minecraft:iron_block"}, + {pos: [6, 2, 5], state: "minecraft:iron_block"}, + {pos: [6, 2, 6], state: "minecraft:iron_block"}, + {pos: [6, 2, 7], state: "minecraft:iron_block"}, + {pos: [6, 2, 8], state: "minecraft:air"}, + {pos: [7, 2, 0], state: "minecraft:air"}, + {pos: [7, 2, 1], state: "minecraft:iron_block"}, + {pos: [7, 2, 2], state: "minecraft:iron_block"}, + {pos: [7, 2, 3], state: "minecraft:iron_block"}, + {pos: [7, 2, 4], state: "minecraft:iron_block"}, + {pos: [7, 2, 5], state: "minecraft:iron_block"}, + {pos: [7, 2, 6], state: "minecraft:iron_block"}, + {pos: [7, 2, 7], state: "minecraft:iron_block"}, + {pos: [7, 2, 8], state: "minecraft:air"}, + {pos: [8, 2, 0], state: "minecraft:air"}, + {pos: [8, 2, 1], state: "minecraft:iron_block"}, + {pos: [8, 2, 2], state: "minecraft:iron_block"}, + {pos: [8, 2, 3], state: "minecraft:iron_block"}, + {pos: [8, 2, 4], state: "minecraft:iron_block"}, + {pos: [8, 2, 5], state: "minecraft:iron_block"}, + {pos: [8, 2, 6], state: "minecraft:iron_block"}, + {pos: [8, 2, 7], state: "minecraft:iron_block"}, + {pos: [8, 2, 8], state: "minecraft:air"}, + {pos: [9, 2, 0], state: "minecraft:air"}, + {pos: [9, 2, 1], state: "minecraft:iron_block"}, + {pos: [9, 2, 2], state: "minecraft:iron_block"}, + {pos: [9, 2, 3], state: "minecraft:iron_block"}, + {pos: [9, 2, 4], state: "minecraft:iron_block"}, + {pos: [9, 2, 5], state: "minecraft:iron_block"}, + {pos: [9, 2, 6], state: "minecraft:iron_block"}, + {pos: [9, 2, 7], state: "minecraft:iron_block"}, + {pos: [9, 2, 8], state: "minecraft:air"}, + {pos: [10, 2, 0], state: "minecraft:air"}, + {pos: [10, 2, 1], state: "minecraft:air"}, + {pos: [10, 2, 2], state: "minecraft:air"}, + {pos: [10, 2, 3], state: "minecraft:air"}, + {pos: [10, 2, 4], state: "minecraft:air"}, + {pos: [10, 2, 5], state: "minecraft:air"}, + {pos: [10, 2, 6], state: "minecraft:air"}, + {pos: [10, 2, 7], state: "minecraft:air"}, + {pos: [10, 2, 8], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [0, 3, 5], state: "minecraft:air"}, + {pos: [0, 3, 6], state: "minecraft:air"}, + {pos: [0, 3, 7], state: "minecraft:air"}, + {pos: [0, 3, 8], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 5], state: "minecraft:air"}, + {pos: [1, 3, 6], state: "minecraft:air"}, + {pos: [1, 3, 7], state: "minecraft:air"}, + {pos: [1, 3, 8], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:iron_block"}, + {pos: [2, 3, 3], state: "minecraft:iron_block"}, + {pos: [2, 3, 4], state: "minecraft:iron_block"}, + {pos: [2, 3, 5], state: "minecraft:iron_block"}, + {pos: [2, 3, 6], state: "minecraft:iron_block"}, + {pos: [2, 3, 7], state: "minecraft:air"}, + {pos: [2, 3, 8], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:iron_block"}, + {pos: [3, 3, 3], state: "minecraft:iron_block"}, + {pos: [3, 3, 4], state: "minecraft:iron_block"}, + {pos: [3, 3, 5], state: "minecraft:iron_block"}, + {pos: [3, 3, 6], state: "minecraft:iron_block"}, + {pos: [3, 3, 7], state: "minecraft:air"}, + {pos: [3, 3, 8], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:iron_block"}, + {pos: [4, 3, 3], state: "minecraft:iron_block"}, + {pos: [4, 3, 4], state: "minecraft:iron_block"}, + {pos: [4, 3, 5], state: "minecraft:iron_block"}, + {pos: [4, 3, 6], state: "minecraft:iron_block"}, + {pos: [4, 3, 7], state: "minecraft:air"}, + {pos: [4, 3, 8], state: "minecraft:air"}, + {pos: [5, 3, 0], state: "minecraft:air"}, + {pos: [5, 3, 1], state: "minecraft:air"}, + {pos: [5, 3, 2], state: "minecraft:iron_block"}, + {pos: [5, 3, 3], state: "minecraft:iron_block"}, + {pos: [5, 3, 4], state: "minecraft:iron_block"}, + {pos: [5, 3, 5], state: "minecraft:iron_block"}, + {pos: [5, 3, 6], state: "minecraft:iron_block"}, + {pos: [5, 3, 7], state: "minecraft:air"}, + {pos: [5, 3, 8], state: "minecraft:air"}, + {pos: [6, 3, 0], state: "minecraft:air"}, + {pos: [6, 3, 1], state: "minecraft:air"}, + {pos: [6, 3, 2], state: "minecraft:iron_block"}, + {pos: [6, 3, 3], state: "minecraft:iron_block"}, + {pos: [6, 3, 4], state: "minecraft:iron_block"}, + {pos: [6, 3, 5], state: "minecraft:iron_block"}, + {pos: [6, 3, 6], state: "minecraft:iron_block"}, + {pos: [6, 3, 7], state: "minecraft:air"}, + {pos: [6, 3, 8], state: "minecraft:air"}, + {pos: [7, 3, 0], state: "minecraft:air"}, + {pos: [7, 3, 1], state: "minecraft:air"}, + {pos: [7, 3, 2], state: "minecraft:iron_block"}, + {pos: [7, 3, 3], state: "minecraft:iron_block"}, + {pos: [7, 3, 4], state: "minecraft:iron_block"}, + {pos: [7, 3, 5], state: "minecraft:iron_block"}, + {pos: [7, 3, 6], state: "minecraft:iron_block"}, + {pos: [7, 3, 7], state: "minecraft:air"}, + {pos: [7, 3, 8], state: "minecraft:air"}, + {pos: [8, 3, 0], state: "minecraft:air"}, + {pos: [8, 3, 1], state: "minecraft:air"}, + {pos: [8, 3, 2], state: "minecraft:iron_block"}, + {pos: [8, 3, 3], state: "minecraft:iron_block"}, + {pos: [8, 3, 4], state: "minecraft:iron_block"}, + {pos: [8, 3, 5], state: "minecraft:iron_block"}, + {pos: [8, 3, 6], state: "minecraft:iron_block"}, + {pos: [8, 3, 7], state: "minecraft:air"}, + {pos: [8, 3, 8], state: "minecraft:air"}, + {pos: [9, 3, 0], state: "minecraft:air"}, + {pos: [9, 3, 1], state: "minecraft:air"}, + {pos: [9, 3, 2], state: "minecraft:air"}, + {pos: [9, 3, 3], state: "minecraft:air"}, + {pos: [9, 3, 4], state: "minecraft:air"}, + {pos: [9, 3, 5], state: "minecraft:air"}, + {pos: [9, 3, 6], state: "minecraft:air"}, + {pos: [9, 3, 7], state: "minecraft:air"}, + {pos: [9, 3, 8], state: "minecraft:air"}, + {pos: [10, 3, 0], state: "minecraft:air"}, + {pos: [10, 3, 1], state: "minecraft:air"}, + {pos: [10, 3, 2], state: "minecraft:air"}, + {pos: [10, 3, 3], state: "minecraft:air"}, + {pos: [10, 3, 4], state: "minecraft:air"}, + {pos: [10, 3, 5], state: "minecraft:air"}, + {pos: [10, 3, 6], state: "minecraft:air"}, + {pos: [10, 3, 7], state: "minecraft:air"}, + {pos: [10, 3, 8], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [0, 4, 5], state: "minecraft:air"}, + {pos: [0, 4, 6], state: "minecraft:air"}, + {pos: [0, 4, 7], state: "minecraft:air"}, + {pos: [0, 4, 8], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 5], state: "minecraft:air"}, + {pos: [1, 4, 6], state: "minecraft:air"}, + {pos: [1, 4, 7], state: "minecraft:air"}, + {pos: [1, 4, 8], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 5], state: "minecraft:air"}, + {pos: [2, 4, 6], state: "minecraft:air"}, + {pos: [2, 4, 7], state: "minecraft:air"}, + {pos: [2, 4, 8], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:iron_block"}, + {pos: [3, 4, 4], state: "minecraft:iron_block"}, + {pos: [3, 4, 5], state: "minecraft:iron_block"}, + {pos: [3, 4, 6], state: "minecraft:air"}, + {pos: [3, 4, 7], state: "minecraft:air"}, + {pos: [3, 4, 8], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:iron_block"}, + {pos: [4, 4, 4], state: "minecraft:iron_block"}, + {pos: [4, 4, 5], state: "minecraft:iron_block"}, + {pos: [4, 4, 6], state: "minecraft:air"}, + {pos: [4, 4, 7], state: "minecraft:air"}, + {pos: [4, 4, 8], state: "minecraft:air"}, + {pos: [5, 4, 0], state: "minecraft:air"}, + {pos: [5, 4, 1], state: "minecraft:air"}, + {pos: [5, 4, 2], state: "minecraft:air"}, + {pos: [5, 4, 3], state: "minecraft:iron_block"}, + {pos: [5, 4, 4], state: "minecraft:iron_block"}, + {pos: [5, 4, 5], state: "minecraft:iron_block"}, + {pos: [5, 4, 6], state: "minecraft:air"}, + {pos: [5, 4, 7], state: "minecraft:air"}, + {pos: [5, 4, 8], state: "minecraft:air"}, + {pos: [6, 4, 0], state: "minecraft:air"}, + {pos: [6, 4, 1], state: "minecraft:air"}, + {pos: [6, 4, 2], state: "minecraft:air"}, + {pos: [6, 4, 3], state: "minecraft:iron_block"}, + {pos: [6, 4, 4], state: "minecraft:iron_block"}, + {pos: [6, 4, 5], state: "minecraft:iron_block"}, + {pos: [6, 4, 6], state: "minecraft:air"}, + {pos: [6, 4, 7], state: "minecraft:air"}, + {pos: [6, 4, 8], state: "minecraft:air"}, + {pos: [7, 4, 0], state: "minecraft:air"}, + {pos: [7, 4, 1], state: "minecraft:air"}, + {pos: [7, 4, 2], state: "minecraft:air"}, + {pos: [7, 4, 3], state: "minecraft:iron_block"}, + {pos: [7, 4, 4], state: "minecraft:iron_block"}, + {pos: [7, 4, 5], state: "minecraft:iron_block"}, + {pos: [7, 4, 6], state: "minecraft:air"}, + {pos: [7, 4, 7], state: "minecraft:air"}, + {pos: [7, 4, 8], state: "minecraft:air"}, + {pos: [8, 4, 0], state: "minecraft:air"}, + {pos: [8, 4, 1], state: "minecraft:air"}, + {pos: [8, 4, 2], state: "minecraft:air"}, + {pos: [8, 4, 3], state: "minecraft:air"}, + {pos: [8, 4, 4], state: "minecraft:air"}, + {pos: [8, 4, 5], state: "minecraft:air"}, + {pos: [8, 4, 6], state: "minecraft:air"}, + {pos: [8, 4, 7], state: "minecraft:air"}, + {pos: [8, 4, 8], state: "minecraft:air"}, + {pos: [9, 4, 0], state: "minecraft:air"}, + {pos: [9, 4, 1], state: "minecraft:air"}, + {pos: [9, 4, 2], state: "minecraft:air"}, + {pos: [9, 4, 3], state: "minecraft:air"}, + {pos: [9, 4, 4], state: "minecraft:air"}, + {pos: [9, 4, 5], state: "minecraft:air"}, + {pos: [9, 4, 6], state: "minecraft:air"}, + {pos: [9, 4, 7], state: "minecraft:air"}, + {pos: [9, 4, 8], state: "minecraft:air"}, + {pos: [10, 4, 0], state: "minecraft:air"}, + {pos: [10, 4, 1], state: "minecraft:air"}, + {pos: [10, 4, 2], state: "minecraft:air"}, + {pos: [10, 4, 3], state: "minecraft:air"}, + {pos: [10, 4, 4], state: "minecraft:air"}, + {pos: [10, 4, 5], state: "minecraft:air"}, + {pos: [10, 4, 6], state: "minecraft:air"}, + {pos: [10, 4, 7], state: "minecraft:air"}, + {pos: [10, 4, 8], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [0, 5, 5], state: "minecraft:air"}, + {pos: [0, 5, 6], state: "minecraft:air"}, + {pos: [0, 5, 7], state: "minecraft:air"}, + {pos: [0, 5, 8], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "minecraft:air"}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 5], state: "minecraft:air"}, + {pos: [1, 5, 6], state: "minecraft:air"}, + {pos: [1, 5, 7], state: "minecraft:air"}, + {pos: [1, 5, 8], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "minecraft:air"}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 5], state: "minecraft:air"}, + {pos: [2, 5, 6], state: "minecraft:air"}, + {pos: [2, 5, 7], state: "minecraft:air"}, + {pos: [2, 5, 8], state: "minecraft:air"}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "minecraft:air"}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [3, 5, 5], state: "minecraft:air"}, + {pos: [3, 5, 6], state: "minecraft:air"}, + {pos: [3, 5, 7], state: "minecraft:air"}, + {pos: [3, 5, 8], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 4, Primary: 1, Secondary: -1, id: "minecraft:beacon"}}, + {pos: [4, 5, 5], state: "minecraft:air"}, + {pos: [4, 5, 6], state: "minecraft:air"}, + {pos: [4, 5, 7], state: "minecraft:air"}, + {pos: [4, 5, 8], state: "minecraft:air"}, + {pos: [5, 5, 0], state: "minecraft:air"}, + {pos: [5, 5, 1], state: "minecraft:air"}, + {pos: [5, 5, 2], state: "minecraft:air"}, + {pos: [5, 5, 3], state: "minecraft:air"}, + {pos: [5, 5, 4], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.minecraftbeacon", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [5, 5, 5], state: "minecraft:air"}, + {pos: [5, 5, 6], state: "minecraft:air"}, + {pos: [5, 5, 7], state: "minecraft:air"}, + {pos: [5, 5, 8], state: "minecraft:air"}, + {pos: [6, 5, 0], state: "minecraft:air"}, + {pos: [6, 5, 1], state: "minecraft:air"}, + {pos: [6, 5, 2], state: "minecraft:air"}, + {pos: [6, 5, 3], state: "minecraft:air"}, + {pos: [6, 5, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 4, Primary: 3, Secondary: 3, id: "minecraft:beacon"}}, + {pos: [6, 5, 5], state: "minecraft:air"}, + {pos: [6, 5, 6], state: "minecraft:air"}, + {pos: [6, 5, 7], state: "minecraft:air"}, + {pos: [6, 5, 8], state: "minecraft:air"}, + {pos: [7, 5, 0], state: "minecraft:air"}, + {pos: [7, 5, 1], state: "minecraft:air"}, + {pos: [7, 5, 2], state: "minecraft:air"}, + {pos: [7, 5, 3], state: "minecraft:air"}, + {pos: [7, 5, 4], state: "minecraft:air"}, + {pos: [7, 5, 5], state: "minecraft:air"}, + {pos: [7, 5, 6], state: "minecraft:air"}, + {pos: [7, 5, 7], state: "minecraft:air"}, + {pos: [7, 5, 8], state: "minecraft:air"}, + {pos: [8, 5, 0], state: "minecraft:air"}, + {pos: [8, 5, 1], state: "minecraft:air"}, + {pos: [8, 5, 2], state: "minecraft:air"}, + {pos: [8, 5, 3], state: "minecraft:air"}, + {pos: [8, 5, 4], state: "minecraft:air"}, + {pos: [8, 5, 5], state: "minecraft:air"}, + {pos: [8, 5, 6], state: "minecraft:air"}, + {pos: [8, 5, 7], state: "minecraft:air"}, + {pos: [8, 5, 8], state: "minecraft:air"}, + {pos: [9, 5, 0], state: "minecraft:air"}, + {pos: [9, 5, 1], state: "minecraft:air"}, + {pos: [9, 5, 2], state: "minecraft:air"}, + {pos: [9, 5, 3], state: "minecraft:air"}, + {pos: [9, 5, 4], state: "minecraft:air"}, + {pos: [9, 5, 5], state: "minecraft:air"}, + {pos: [9, 5, 6], state: "minecraft:air"}, + {pos: [9, 5, 7], state: "minecraft:air"}, + {pos: [9, 5, 8], state: "minecraft:air"}, + {pos: [10, 5, 0], state: "minecraft:air"}, + {pos: [10, 5, 1], state: "minecraft:air"}, + {pos: [10, 5, 2], state: "minecraft:air"}, + {pos: [10, 5, 3], state: "minecraft:air"}, + {pos: [10, 5, 4], state: "minecraft:air"}, + {pos: [10, 5, 5], state: "minecraft:air"}, + {pos: [10, 5, 6], state: "minecraft:air"}, + {pos: [10, 5, 7], state: "minecraft:air"}, + {pos: [10, 5, 8], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [0, 6, 5], state: "minecraft:air"}, + {pos: [0, 6, 6], state: "minecraft:air"}, + {pos: [0, 6, 7], state: "minecraft:air"}, + {pos: [0, 6, 8], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 5], state: "minecraft:air"}, + {pos: [1, 6, 6], state: "minecraft:air"}, + {pos: [1, 6, 7], state: "minecraft:air"}, + {pos: [1, 6, 8], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "minecraft:air"}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 5], state: "minecraft:air"}, + {pos: [2, 6, 6], state: "minecraft:air"}, + {pos: [2, 6, 7], state: "minecraft:air"}, + {pos: [2, 6, 8], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 5], state: "minecraft:air"}, + {pos: [3, 6, 6], state: "minecraft:air"}, + {pos: [3, 6, 7], state: "minecraft:air"}, + {pos: [3, 6, 8], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 5], state: "minecraft:air"}, + {pos: [4, 6, 6], state: "minecraft:air"}, + {pos: [4, 6, 7], state: "minecraft:air"}, + {pos: [4, 6, 8], state: "minecraft:air"}, + {pos: [5, 6, 0], state: "minecraft:air"}, + {pos: [5, 6, 1], state: "minecraft:air"}, + {pos: [5, 6, 2], state: "minecraft:air"}, + {pos: [5, 6, 3], state: "minecraft:air"}, + {pos: [5, 6, 4], state: "minecraft:beacon", nbt: {ForgeCaps: {}, Levels: 0, Primary: -1, Secondary: -1, id: "minecraft:beacon"}}, + {pos: [5, 6, 5], state: "minecraft:air"}, + {pos: [5, 6, 6], state: "minecraft:air"}, + {pos: [5, 6, 7], state: "minecraft:air"}, + {pos: [5, 6, 8], state: "minecraft:air"}, + {pos: [6, 6, 0], state: "minecraft:air"}, + {pos: [6, 6, 1], state: "minecraft:air"}, + {pos: [6, 6, 2], state: "minecraft:air"}, + {pos: [6, 6, 3], state: "minecraft:air"}, + {pos: [6, 6, 4], state: "minecraft:air"}, + {pos: [6, 6, 5], state: "minecraft:air"}, + {pos: [6, 6, 6], state: "minecraft:air"}, + {pos: [6, 6, 7], state: "minecraft:air"}, + {pos: [6, 6, 8], state: "minecraft:air"}, + {pos: [7, 6, 0], state: "minecraft:air"}, + {pos: [7, 6, 1], state: "minecraft:air"}, + {pos: [7, 6, 2], state: "minecraft:air"}, + {pos: [7, 6, 3], state: "minecraft:air"}, + {pos: [7, 6, 4], state: "minecraft:air"}, + {pos: [7, 6, 5], state: "minecraft:air"}, + {pos: [7, 6, 6], state: "minecraft:air"}, + {pos: [7, 6, 7], state: "minecraft:air"}, + {pos: [7, 6, 8], state: "minecraft:air"}, + {pos: [8, 6, 0], state: "minecraft:air"}, + {pos: [8, 6, 1], state: "minecraft:air"}, + {pos: [8, 6, 2], state: "minecraft:air"}, + {pos: [8, 6, 3], state: "minecraft:air"}, + {pos: [8, 6, 4], state: "minecraft:air"}, + {pos: [8, 6, 5], state: "minecraft:air"}, + {pos: [8, 6, 6], state: "minecraft:air"}, + {pos: [8, 6, 7], state: "minecraft:air"}, + {pos: [8, 6, 8], state: "minecraft:air"}, + {pos: [9, 6, 0], state: "minecraft:air"}, + {pos: [9, 6, 1], state: "minecraft:air"}, + {pos: [9, 6, 2], state: "minecraft:air"}, + {pos: [9, 6, 3], state: "minecraft:air"}, + {pos: [9, 6, 4], state: "minecraft:air"}, + {pos: [9, 6, 5], state: "minecraft:air"}, + {pos: [9, 6, 6], state: "minecraft:air"}, + {pos: [9, 6, 7], state: "minecraft:air"}, + {pos: [9, 6, 8], state: "minecraft:air"}, + {pos: [10, 6, 0], state: "minecraft:air"}, + {pos: [10, 6, 1], state: "minecraft:air"}, + {pos: [10, 6, 2], state: "minecraft:air"}, + {pos: [10, 6, 3], state: "minecraft:air"}, + {pos: [10, 6, 4], state: "minecraft:air"}, + {pos: [10, 6, 5], state: "minecraft:air"}, + {pos: [10, 6, 6], state: "minecraft:air"}, + {pos: [10, 6, 7], state: "minecraft:air"}, + {pos: [10, 6, 8], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:iron_block", + "minecraft:air", + "minecraft:beacon", + "computercraft:computer_advanced{facing:north,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt new file mode 100644 index 000000000..e32bcfbcf --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:note_block{instrument:basedrum,note:4,powered:false}"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "modintegrtest.minecraftnoteblock", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:note_block{instrument:basedrum,note:0,powered:false}"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:note_block{instrument:basedrum,note:4,powered:false}", + "minecraft:note_block{instrument:basedrum,note:0,powered:false}", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt new file mode 100644 index 000000000..5344fa82e --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.minecraftnoteblock_triggering_allay.snbt @@ -0,0 +1,140 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:glass"}, + {pos: [0, 1, 1], state: "minecraft:glass"}, + {pos: [0, 1, 2], state: "minecraft:glass"}, + {pos: [0, 1, 3], state: "minecraft:glass"}, + {pos: [0, 1, 4], state: "minecraft:glass"}, + {pos: [1, 1, 0], state: "minecraft:glass"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:glass"}, + {pos: [2, 1, 0], state: "minecraft:glass"}, + {pos: [2, 1, 1], state: "minecraft:note_block{instrument:basedrum,note:4,powered:false}"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 1, ForgeCaps: {}, Label: "modintegrtest.minecraftnoteblock_triggering_allay", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:glass"}, + {pos: [3, 1, 0], state: "minecraft:glass"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:glass"}, + {pos: [4, 1, 0], state: "minecraft:glass"}, + {pos: [4, 1, 1], state: "minecraft:glass"}, + {pos: [4, 1, 2], state: "minecraft:glass"}, + {pos: [4, 1, 3], state: "minecraft:glass"}, + {pos: [4, 1, 4], state: "minecraft:glass"}, + {pos: [0, 2, 0], state: "minecraft:glass"}, + {pos: [0, 2, 1], state: "minecraft:glass"}, + {pos: [0, 2, 2], state: "minecraft:glass"}, + {pos: [0, 2, 3], state: "minecraft:glass"}, + {pos: [0, 2, 4], state: "minecraft:glass"}, + {pos: [1, 2, 0], state: "minecraft:glass"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:glass"}, + {pos: [2, 2, 0], state: "minecraft:glass"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:glass"}, + {pos: [3, 2, 0], state: "minecraft:glass"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:glass"}, + {pos: [4, 2, 0], state: "minecraft:glass"}, + {pos: [4, 2, 1], state: "minecraft:glass"}, + {pos: [4, 2, 2], state: "minecraft:glass"}, + {pos: [4, 2, 3], state: "minecraft:glass"}, + {pos: [4, 2, 4], state: "minecraft:glass"}, + {pos: [0, 3, 0], state: "minecraft:glass"}, + {pos: [0, 3, 1], state: "minecraft:glass"}, + {pos: [0, 3, 2], state: "minecraft:glass"}, + {pos: [0, 3, 3], state: "minecraft:glass"}, + {pos: [0, 3, 4], state: "minecraft:glass"}, + {pos: [1, 3, 0], state: "minecraft:glass"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:glass"}, + {pos: [2, 3, 0], state: "minecraft:glass"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:glass"}, + {pos: [3, 3, 0], state: "minecraft:glass"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:glass"}, + {pos: [4, 3, 0], state: "minecraft:glass"}, + {pos: [4, 3, 1], state: "minecraft:glass"}, + {pos: [4, 3, 2], state: "minecraft:glass"}, + {pos: [4, 3, 3], state: "minecraft:glass"}, + {pos: [4, 3, 4], state: "minecraft:glass"}, + {pos: [0, 4, 0], state: "minecraft:glass"}, + {pos: [0, 4, 1], state: "minecraft:glass"}, + {pos: [0, 4, 2], state: "minecraft:glass"}, + {pos: [0, 4, 3], state: "minecraft:glass"}, + {pos: [0, 4, 4], state: "minecraft:glass"}, + {pos: [1, 4, 0], state: "minecraft:glass"}, + {pos: [1, 4, 1], state: "minecraft:glass"}, + {pos: [1, 4, 2], state: "minecraft:glass"}, + {pos: [1, 4, 3], state: "minecraft:glass"}, + {pos: [1, 4, 4], state: "minecraft:glass"}, + {pos: [2, 4, 0], state: "minecraft:glass"}, + {pos: [2, 4, 1], state: "minecraft:glass"}, + {pos: [2, 4, 2], state: "minecraft:glass"}, + {pos: [2, 4, 3], state: "minecraft:glass"}, + {pos: [2, 4, 4], state: "minecraft:glass"}, + {pos: [3, 4, 0], state: "minecraft:glass"}, + {pos: [3, 4, 1], state: "minecraft:glass"}, + {pos: [3, 4, 2], state: "minecraft:glass"}, + {pos: [3, 4, 3], state: "minecraft:glass"}, + {pos: [3, 4, 4], state: "minecraft:glass"}, + {pos: [4, 4, 0], state: "minecraft:glass"}, + {pos: [4, 4, 1], state: "minecraft:glass"}, + {pos: [4, 4, 2], state: "minecraft:glass"}, + {pos: [4, 4, 3], state: "minecraft:glass"}, + {pos: [4, 4, 4], state: "minecraft:glass"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:glass", + "minecraft:note_block{instrument:basedrum,note:4,powered:false}", + "minecraft:note_block{instrument:basedrum,note:0,powered:false}", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt new file mode 100644 index 000000000..fd6a9bf08 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.geoscanner.snbt @@ -0,0 +1,243 @@ +{ + DataVersion: 3120, + size: [5, 9, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.geoscanner", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:polished_diorite"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:polished_granite"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "advancedperipherals:geo_scanner{orientation:west_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Geo Scanner]"}, Items: [], energy: 100000000, id: "advancedperipherals:geo_scanner", peripheralSettings: {FUEL_CONSUMING_RATE: 1, cooldowns: {scanBlocks: 1715469234280L}}}}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:iron_ore"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:gold_ore"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"}, + {pos: [0, 5, 0], state: "minecraft:air"}, + {pos: [0, 5, 1], state: "minecraft:air"}, + {pos: [0, 5, 2], state: "minecraft:air"}, + {pos: [0, 5, 3], state: "minecraft:air"}, + {pos: [0, 5, 4], state: "minecraft:air"}, + {pos: [1, 5, 0], state: "minecraft:air"}, + {pos: [1, 5, 1], state: "minecraft:air"}, + {pos: [1, 5, 2], state: "minecraft:air"}, + {pos: [1, 5, 3], state: "minecraft:air"}, + {pos: [1, 5, 4], state: "minecraft:air"}, + {pos: [2, 5, 0], state: "minecraft:air"}, + {pos: [2, 5, 1], state: "minecraft:air"}, + {pos: [2, 5, 2], state: "minecraft:gold_ore"}, + {pos: [2, 5, 3], state: "minecraft:air"}, + {pos: [2, 5, 4], state: "minecraft:air"}, + {pos: [3, 5, 0], state: "minecraft:air"}, + {pos: [3, 5, 1], state: "minecraft:air"}, + {pos: [3, 5, 2], state: "minecraft:air"}, + {pos: [3, 5, 3], state: "minecraft:air"}, + {pos: [3, 5, 4], state: "minecraft:air"}, + {pos: [4, 5, 0], state: "minecraft:air"}, + {pos: [4, 5, 1], state: "minecraft:air"}, + {pos: [4, 5, 2], state: "minecraft:air"}, + {pos: [4, 5, 3], state: "minecraft:air"}, + {pos: [4, 5, 4], state: "minecraft:air"}, + {pos: [0, 6, 0], state: "minecraft:air"}, + {pos: [0, 6, 1], state: "minecraft:air"}, + {pos: [0, 6, 2], state: "minecraft:air"}, + {pos: [0, 6, 3], state: "minecraft:air"}, + {pos: [0, 6, 4], state: "minecraft:air"}, + {pos: [1, 6, 0], state: "minecraft:air"}, + {pos: [1, 6, 1], state: "minecraft:air"}, + {pos: [1, 6, 2], state: "minecraft:air"}, + {pos: [1, 6, 3], state: "minecraft:air"}, + {pos: [1, 6, 4], state: "minecraft:air"}, + {pos: [2, 6, 0], state: "minecraft:air"}, + {pos: [2, 6, 1], state: "minecraft:air"}, + {pos: [2, 6, 2], state: "minecraft:diamond_ore"}, + {pos: [2, 6, 3], state: "minecraft:air"}, + {pos: [2, 6, 4], state: "minecraft:air"}, + {pos: [3, 6, 0], state: "minecraft:air"}, + {pos: [3, 6, 1], state: "minecraft:air"}, + {pos: [3, 6, 2], state: "minecraft:air"}, + {pos: [3, 6, 3], state: "minecraft:air"}, + {pos: [3, 6, 4], state: "minecraft:air"}, + {pos: [4, 6, 0], state: "minecraft:air"}, + {pos: [4, 6, 1], state: "minecraft:air"}, + {pos: [4, 6, 2], state: "minecraft:air"}, + {pos: [4, 6, 3], state: "minecraft:air"}, + {pos: [4, 6, 4], state: "minecraft:air"}, + {pos: [0, 7, 0], state: "minecraft:air"}, + {pos: [0, 7, 1], state: "minecraft:air"}, + {pos: [0, 7, 2], state: "minecraft:air"}, + {pos: [0, 7, 3], state: "minecraft:air"}, + {pos: [0, 7, 4], state: "minecraft:air"}, + {pos: [1, 7, 0], state: "minecraft:air"}, + {pos: [1, 7, 1], state: "minecraft:air"}, + {pos: [1, 7, 2], state: "minecraft:air"}, + {pos: [1, 7, 3], state: "minecraft:air"}, + {pos: [1, 7, 4], state: "minecraft:air"}, + {pos: [2, 7, 0], state: "minecraft:air"}, + {pos: [2, 7, 1], state: "minecraft:air"}, + {pos: [2, 7, 2], state: "minecraft:diamond_ore"}, + {pos: [2, 7, 3], state: "minecraft:air"}, + {pos: [2, 7, 4], state: "minecraft:air"}, + {pos: [3, 7, 0], state: "minecraft:air"}, + {pos: [3, 7, 1], state: "minecraft:air"}, + {pos: [3, 7, 2], state: "minecraft:air"}, + {pos: [3, 7, 3], state: "minecraft:air"}, + {pos: [3, 7, 4], state: "minecraft:air"}, + {pos: [4, 7, 0], state: "minecraft:air"}, + {pos: [4, 7, 1], state: "minecraft:air"}, + {pos: [4, 7, 2], state: "minecraft:air"}, + {pos: [4, 7, 3], state: "minecraft:air"}, + {pos: [4, 7, 4], state: "minecraft:air"}, + {pos: [0, 8, 0], state: "minecraft:air"}, + {pos: [0, 8, 1], state: "minecraft:air"}, + {pos: [0, 8, 2], state: "minecraft:air"}, + {pos: [0, 8, 3], state: "minecraft:air"}, + {pos: [0, 8, 4], state: "minecraft:air"}, + {pos: [1, 8, 0], state: "minecraft:air"}, + {pos: [1, 8, 1], state: "minecraft:air"}, + {pos: [1, 8, 2], state: "minecraft:air"}, + {pos: [1, 8, 3], state: "minecraft:air"}, + {pos: [1, 8, 4], state: "minecraft:air"}, + {pos: [2, 8, 0], state: "minecraft:air"}, + {pos: [2, 8, 1], state: "minecraft:air"}, + {pos: [2, 8, 2], state: "minecraft:diamond_ore"}, + {pos: [2, 8, 3], state: "minecraft:air"}, + {pos: [2, 8, 4], state: "minecraft:air"}, + {pos: [3, 8, 0], state: "minecraft:air"}, + {pos: [3, 8, 1], state: "minecraft:air"}, + {pos: [3, 8, 2], state: "minecraft:air"}, + {pos: [3, 8, 3], state: "minecraft:air"}, + {pos: [3, 8, 4], state: "minecraft:air"}, + {pos: [4, 8, 0], state: "minecraft:air"}, + {pos: [4, 8, 1], state: "minecraft:air"}, + {pos: [4, 8, 2], state: "minecraft:air"}, + {pos: [4, 8, 3], state: "minecraft:air"}, + {pos: [4, 8, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:polished_diorite", + "minecraft:polished_granite", + "minecraft:iron_ore", + "minecraft:gold_ore", + "minecraft:diamond_ore", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:blinking}", + "advancedperipherals:geo_scanner{orientation:west_up}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt new file mode 100644 index 000000000..0f0515b89 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.nbtstorage.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "advancedperipherals:nbt_storage{orientation:up_east}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[NBT Storage]"}, Items: [], id: "advancedperipherals:nbt_storage", storedData: {test_float: 3.14d, test_number: 42.0d, test_string: "Hello, World!"}}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.nbtstorage", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "advancedperipherals:nbt_storage{orientation:up_east}", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt new file mode 100644 index 000000000..0c084d522 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.rsintegrator.snbt @@ -0,0 +1,142 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:redstone_wire{east:side,north:none,power:0,south:side,west:none}"}, + {pos: [1, 1, 2], state: "minecraft:redstone_wire{east:side,north:side,power:0,south:side,west:none}"}, + {pos: [1, 1, 3], state: "minecraft:redstone_wire{east:side,north:side,power:0,south:none,west:none}"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "advancedperipherals:redstone_integrator{orientation:west_up}", nbt: {DOWNPower: 0, EASTPower: 0, ForgeCaps: {}, ForgeData: {CustomName: "[Redstone Integrator]"}, Items: [], NORTHPower: 0, SOUTHPower: 0, UPPower: 0, WESTPower: 0, id: "advancedperipherals:redstone_integrator"}}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:west,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.rsintegrator", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "advancedperipherals:redstone_integrator{orientation:west_up}", nbt: {DOWNPower: 0, EASTPower: 0, ForgeCaps: {}, ForgeData: {CustomName: "[Redstone Integrator]"}, Items: [], NORTHPower: 0, SOUTHPower: 0, UPPower: 0, WESTPower: 0, id: "advancedperipherals:redstone_integrator"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:redstone_block"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:redstone_block", + "minecraft:air", + "minecraft:redstone_wire{east:side,north:none,power:0,south:side,west:none}", + "minecraft:redstone_wire{east:side,north:side,power:0,south:side,west:none}", + "minecraft:redstone_wire{east:side,north:side,power:0,south:none,west:none}", + "advancedperipherals:redstone_integrator{orientation:west_up}", + "computercraft:computer_advanced{facing:west,state:blinking}" + ] +} From 9cf6e2aa17fa9e7de2d7a3244f9e8763a042ec32 Mon Sep 17 00:00:00 2001 From: Srendi Date: Tue, 21 May 2024 18:30:18 +0200 Subject: [PATCH 44/61] Some documentation additions --- docs/CREATING_TESTS.MD | 55 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/docs/CREATING_TESTS.MD b/docs/CREATING_TESTS.MD index 87c9f29bc..5d771e476 100644 --- a/docs/CREATING_TESTS.MD +++ b/docs/CREATING_TESTS.MD @@ -24,7 +24,10 @@ Now you need to set a label to the computer, so it can run the lua test script. For example, peripheraltest as the test type. The test type is the name of the `@GameTestHolder` class. PeripheralTest.kt for this type. `environment` would be our test name. So the label would be `peripheraltest.environment`. -The computer needs the id 0 so it can load the default startup.lua and the tests scripts from the resources folder. +The computer can either have the id 0 or 1. It depends what you want to do later. +It is possible to either run a test script on the computer which is explained in "Writing the test" and you can run +code on the computer using the kotlin game tests. +Use id 0 if you want to run a lua script on the computer and id 1 if you only want to run code using kotlin game tests. Now to save your test, get a structure block, place it in the lower right corner of the test structure and set the mode to save. Use the command `/give @p minecraft:structure_block` to get a structure block. @@ -44,6 +47,10 @@ The class should be annotated with `@GameTestHolder`. The class should have a function annotated with `@GameTest` that will be executed by the game test server later. The function needs to have the parameter `GameTestContext` that will be used to interact with the game world. +There are two ways to test things on a computer. You can either run a lua script or run code on the computer using kotlin. + +#### Lua Tests + A simple game test would look like this. You can see that the context can be used to interact with the world. You can then use one of the helper functions to interact with the computer. For example, `thenComputerOk()` to check if the script on the computer was executed without any fails. ```kt @@ -69,4 +76,48 @@ test.eq(false, isRaining, "It should not rain") Last but not least, import the script to the computer. You need to do that when you're currently in the test world, and you want to write the script in your IDE. Luckily, the test framework provides a command for that. `/cctest import` imports the scripts from the resources folder to the world folder. -You can then find the script in the computer's folder using `ls tests/`. \ No newline at end of file +You can then find the script in the computer's folder using `ls tests/`. + + +#### Kotlin Tests + +To run tests on a computer, the computer needs to have the id 1 + +```kt +thenOnComputer { callPeripheral("left", "playNote") } +``` + +This would run `callPeripheral("left", "playNote")` on the computer which just calls a function on the peripheral on the left + +Here is an example with our note block test + +```kt + @GameTest(timeoutTicks = 300) + fun minecraftNoteBlock_Triggering_Allay(context: GameTestHelper) = context.sequence { + // test if playNote triggers an allay + // related issue: https://github.com/IntelligenceModding/AdvancedPeripherals/issues/603 + + val item = Items.DIAMOND + var allay: Allay? = null + thenExecute { + allay = context.spawn(EntityType.ALLAY, 2, 3, 2) + allay?.setItemInHand(InteractionHand.MAIN_HAND, ItemStack(item)) + + context.spawnItem(item, 2f, 3f, 2f) + } + + thenWaitUntil { context.assertEntityNotPresent(EntityType.ITEM) } + thenWaitUntil { + if (allay?.inventory?.getItem(0)?.count != 1) + context.fail("Expected Allay to pick up item") + } + thenOnComputer { callPeripheral("left", "playNote") } + thenWaitUntil { context.assertEntityPresent(EntityType.ITEM) } + thenWaitUntil { + if (allay?.inventory?.getItem(0)?.count != 0) + context.fail("Expected Allay to drop item") + } + } +``` + +For more examples, you can also check how the tests from CC work [here](https://github.com/cc-tweaked/CC-Tweaked/tree/mc-1.19.2/src/testMod/kotlin/dan200/computercraft/gametest). \ No newline at end of file From 20bc455e6ccbbe2909a4d746b9708009c860664a Mon Sep 17 00:00:00 2001 From: Srendi Date: Sat, 1 Jun 2024 14:47:08 +0200 Subject: [PATCH 45/61] Fixed the orientation of RS Blocks when they are loaded from a structure block. #BlameRS --- build.gradle | 2 + mixin.patch | 106 ++++++++++++++++++ .../test/mixin/RsBaseBlockMixin.java | 38 +++++++ .../advancedperipheralstest.mixins.json | 8 +- src/testMod/resources/ccgametest.mixins.json | 16 +++ 5 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 mixin.patch create mode 100644 src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java create mode 100644 src/testMod/resources/ccgametest.mixins.json diff --git a/build.gradle b/build.gradle index c66075c79..d2d3e930d 100644 --- a/build.gradle +++ b/build.gradle @@ -171,6 +171,7 @@ minecraft { property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + args "--mixin.config=ccgametest.mixins.json" args "--mixin.config=advancedperipheralstest.mixins.json" mods { @@ -202,6 +203,7 @@ minecraft { property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + args "--mixin.config=ccgametest.mixins.json" args "--mixin.config=advancedperipheralstest.mixins.json" parent runs.server diff --git a/mixin.patch b/mixin.patch new file mode 100644 index 000000000..ea08be1b3 --- /dev/null +++ b/mixin.patch @@ -0,0 +1,106 @@ +diff --git a/build.gradle b/build.gradle +index c66075c7..d2d3e930 100644 +--- a/build.gradle ++++ b/build.gradle +@@ -171,6 +171,7 @@ minecraft { + property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' + property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + ++ args "--mixin.config=ccgametest.mixins.json" + args "--mixin.config=advancedperipheralstest.mixins.json" + + mods { +@@ -202,6 +203,7 @@ minecraft { + property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' + property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + ++ args "--mixin.config=ccgametest.mixins.json" + args "--mixin.config=advancedperipheralstest.mixins.json" + parent runs.server + +diff --git a/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java b/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java +new file mode 100644 +index 00000000..eaef15c4 +--- /dev/null ++++ b/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java +@@ -0,0 +1,35 @@ ++package de.srendi.advancedperipherals.test.mixin; ++ ++import com.refinedmods.refinedstorage.block.BaseBlock; ++import com.refinedmods.refinedstorage.block.BlockDirection; ++import net.minecraft.core.Direction; ++import net.minecraft.world.level.block.Rotation; ++import net.minecraft.world.level.block.state.BlockState; ++import org.spongepowered.asm.mixin.Mixin; ++import org.spongepowered.asm.mixin.Overwrite; ++import org.spongepowered.asm.mixin.Shadow; ++ ++@Mixin(BaseBlock.class) ++public class RsBaseBlockMixin { ++ ++ @Shadow ++ public BlockDirection getDirection() { ++ return null; ++ } ++ ++ @Overwrite ++ public BlockState rotate(BlockState state, Rotation rot) { ++ BlockDirection dir = this.getDirection(); ++ if (dir == BlockDirection.NONE) return state; ++ ++ Direction newDirection = switch (rot) { ++ case NONE -> state.getValue(dir.getProperty()); ++ case CLOCKWISE_90 -> dir.cycle(state.getValue(dir.getProperty()).getClockWise().getClockWise()); ++ case CLOCKWISE_180 -> dir.cycle(state.getValue(dir.getProperty()).getClockWise().getClockWise().getClockWise()); ++ case COUNTERCLOCKWISE_90 -> dir.cycle(state.getValue(dir.getProperty())); ++ }; ++ ++ return state.setValue(dir.getProperty(), newDirection); ++ } ++ ++} +diff --git a/src/testMod/resources/advancedperipheralstest.mixins.json b/src/testMod/resources/advancedperipheralstest.mixins.json +index 76ac7799..782eaa71 100644 +--- a/src/testMod/resources/advancedperipheralstest.mixins.json ++++ b/src/testMod/resources/advancedperipheralstest.mixins.json +@@ -1,16 +1,12 @@ + { + "required": true, +- "package": "dan200.computercraft.mixin.gametest", ++ "package": "de.srendi.advancedperipherals.test.mixin", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ +- "GameTestHelperAccessor", +- "GameTestInfoAccessor", +- "GameTestSequenceAccessor", +- "GameTestSequenceMixin", +- "TestCommandAccessor" ++ "RsBaseBlockMixin" + ] + } +diff --git a/src/testMod/resources/ccgametest.mixins.json b/src/testMod/resources/ccgametest.mixins.json +new file mode 100644 +index 00000000..76ac7799 +--- /dev/null ++++ b/src/testMod/resources/ccgametest.mixins.json +@@ -0,0 +1,16 @@ ++{ ++ "required": true, ++ "package": "dan200.computercraft.mixin.gametest", ++ "minVersion": "0.8", ++ "compatibilityLevel": "JAVA_17", ++ "injectors": { ++ "defaultRequire": 1 ++ }, ++ "mixins": [ ++ "GameTestHelperAccessor", ++ "GameTestInfoAccessor", ++ "GameTestSequenceAccessor", ++ "GameTestSequenceMixin", ++ "TestCommandAccessor" ++ ] ++} diff --git a/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java b/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java new file mode 100644 index 000000000..a17bb2d51 --- /dev/null +++ b/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java @@ -0,0 +1,38 @@ +package de.srendi.advancedperipherals.test.mixin; + +import com.refinedmods.refinedstorage.block.BaseBlock; +import com.refinedmods.refinedstorage.block.BlockDirection; +import net.minecraft.core.Direction; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +/** + * Used to fix the orientation of RS Blocks when they are loaded from a structure block. + */ +@Mixin(BaseBlock.class) +public class RsBaseBlockMixin { + + @Shadow + public BlockDirection getDirection() { + return null; + } + + @Overwrite + public BlockState rotate(BlockState state, Rotation rot) { + BlockDirection dir = this.getDirection(); + if (dir == BlockDirection.NONE) return state; + + Direction newDirection = switch (rot) { + case NONE -> state.getValue(dir.getProperty()); + case CLOCKWISE_90 -> dir.cycle(state.getValue(dir.getProperty()).getClockWise().getClockWise()); + case CLOCKWISE_180 -> dir.cycle(state.getValue(dir.getProperty()).getClockWise().getClockWise().getClockWise()); + case COUNTERCLOCKWISE_90 -> dir.cycle(state.getValue(dir.getProperty())); + }; + + return state.setValue(dir.getProperty(), newDirection); + } + +} diff --git a/src/testMod/resources/advancedperipheralstest.mixins.json b/src/testMod/resources/advancedperipheralstest.mixins.json index 76ac77997..782eaa715 100644 --- a/src/testMod/resources/advancedperipheralstest.mixins.json +++ b/src/testMod/resources/advancedperipheralstest.mixins.json @@ -1,16 +1,12 @@ { "required": true, - "package": "dan200.computercraft.mixin.gametest", + "package": "de.srendi.advancedperipherals.test.mixin", "minVersion": "0.8", "compatibilityLevel": "JAVA_17", "injectors": { "defaultRequire": 1 }, "mixins": [ - "GameTestHelperAccessor", - "GameTestInfoAccessor", - "GameTestSequenceAccessor", - "GameTestSequenceMixin", - "TestCommandAccessor" + "RsBaseBlockMixin" ] } diff --git a/src/testMod/resources/ccgametest.mixins.json b/src/testMod/resources/ccgametest.mixins.json new file mode 100644 index 000000000..76ac77997 --- /dev/null +++ b/src/testMod/resources/ccgametest.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "package": "dan200.computercraft.mixin.gametest", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ + "GameTestHelperAccessor", + "GameTestInfoAccessor", + "GameTestSequenceAccessor", + "GameTestSequenceMixin", + "TestCommandAccessor" + ] +} From 4b49523a7cd64ed957e438c7637925965dd22766 Mon Sep 17 00:00:00 2001 From: Srendi Date: Sat, 1 Jun 2024 14:55:45 +0200 Subject: [PATCH 46/61] Begone --- mixin.patch | 106 ---------------------------------------------------- 1 file changed, 106 deletions(-) delete mode 100644 mixin.patch diff --git a/mixin.patch b/mixin.patch deleted file mode 100644 index ea08be1b3..000000000 --- a/mixin.patch +++ /dev/null @@ -1,106 +0,0 @@ -diff --git a/build.gradle b/build.gradle -index c66075c7..d2d3e930 100644 ---- a/build.gradle -+++ b/build.gradle -@@ -171,6 +171,7 @@ minecraft { - property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' - property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath - -+ args "--mixin.config=ccgametest.mixins.json" - args "--mixin.config=advancedperipheralstest.mixins.json" - - mods { -@@ -202,6 +203,7 @@ minecraft { - property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' - property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath - -+ args "--mixin.config=ccgametest.mixins.json" - args "--mixin.config=advancedperipheralstest.mixins.json" - parent runs.server - -diff --git a/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java b/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java -new file mode 100644 -index 00000000..eaef15c4 ---- /dev/null -+++ b/src/testMod/java/de/srendi/advancedperipherals/test/mixin/RsBaseBlockMixin.java -@@ -0,0 +1,35 @@ -+package de.srendi.advancedperipherals.test.mixin; -+ -+import com.refinedmods.refinedstorage.block.BaseBlock; -+import com.refinedmods.refinedstorage.block.BlockDirection; -+import net.minecraft.core.Direction; -+import net.minecraft.world.level.block.Rotation; -+import net.minecraft.world.level.block.state.BlockState; -+import org.spongepowered.asm.mixin.Mixin; -+import org.spongepowered.asm.mixin.Overwrite; -+import org.spongepowered.asm.mixin.Shadow; -+ -+@Mixin(BaseBlock.class) -+public class RsBaseBlockMixin { -+ -+ @Shadow -+ public BlockDirection getDirection() { -+ return null; -+ } -+ -+ @Overwrite -+ public BlockState rotate(BlockState state, Rotation rot) { -+ BlockDirection dir = this.getDirection(); -+ if (dir == BlockDirection.NONE) return state; -+ -+ Direction newDirection = switch (rot) { -+ case NONE -> state.getValue(dir.getProperty()); -+ case CLOCKWISE_90 -> dir.cycle(state.getValue(dir.getProperty()).getClockWise().getClockWise()); -+ case CLOCKWISE_180 -> dir.cycle(state.getValue(dir.getProperty()).getClockWise().getClockWise().getClockWise()); -+ case COUNTERCLOCKWISE_90 -> dir.cycle(state.getValue(dir.getProperty())); -+ }; -+ -+ return state.setValue(dir.getProperty(), newDirection); -+ } -+ -+} -diff --git a/src/testMod/resources/advancedperipheralstest.mixins.json b/src/testMod/resources/advancedperipheralstest.mixins.json -index 76ac7799..782eaa71 100644 ---- a/src/testMod/resources/advancedperipheralstest.mixins.json -+++ b/src/testMod/resources/advancedperipheralstest.mixins.json -@@ -1,16 +1,12 @@ - { - "required": true, -- "package": "dan200.computercraft.mixin.gametest", -+ "package": "de.srendi.advancedperipherals.test.mixin", - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "injectors": { - "defaultRequire": 1 - }, - "mixins": [ -- "GameTestHelperAccessor", -- "GameTestInfoAccessor", -- "GameTestSequenceAccessor", -- "GameTestSequenceMixin", -- "TestCommandAccessor" -+ "RsBaseBlockMixin" - ] - } -diff --git a/src/testMod/resources/ccgametest.mixins.json b/src/testMod/resources/ccgametest.mixins.json -new file mode 100644 -index 00000000..76ac7799 ---- /dev/null -+++ b/src/testMod/resources/ccgametest.mixins.json -@@ -0,0 +1,16 @@ -+{ -+ "required": true, -+ "package": "dan200.computercraft.mixin.gametest", -+ "minVersion": "0.8", -+ "compatibilityLevel": "JAVA_17", -+ "injectors": { -+ "defaultRequire": 1 -+ }, -+ "mixins": [ -+ "GameTestHelperAccessor", -+ "GameTestInfoAccessor", -+ "GameTestSequenceAccessor", -+ "GameTestSequenceMixin", -+ "TestCommandAccessor" -+ ] -+} From 8272ba2230a71c26bafdc38f6fbc0dd5fc6c1508 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 2 Jun 2024 00:23:20 +0200 Subject: [PATCH 47/61] Backported changes from the CC: Tweaked Gametest framework present in the 1.20.x branch This was mainly done to allow the execution of client tests --- .../gametest/core/CCTestCommand.java | 2 +- .../gametest/core/ClientHooks.java | 49 ----- .../gametest/core/MinecraftExtensions.java | 15 ++ .../computercraft/gametest/core/TestAPI.java | 24 ++- .../gametest/core/TestHooks.java | 57 ------ .../computercraft/gametest/core/TestMod.java | 77 ++----- .../mixin/gametest/GameTestSequenceMixin.java | 2 +- .../gametest/client/LevelSummaryMixin.java | 19 ++ .../mixin/gametest/client/MinecraftMixin.java | 55 +++++ .../gametest/client/WorldOpenFlowsMixin.java | 30 +++ .../gametest/api/ClientGameTest.kt | 33 +++ .../gametest/api/ClientTestExtensions.kt | 136 +++++++++++++ .../gametest/api/TestExtensions.kt | 4 +- .../computercraft/gametest/api/TestTags.kt | 20 ++ .../gametest/core/ClientTestHooks.kt | 189 ++++++++++++++++++ .../computercraft/gametest/core/TestHooks.kt | 143 +++++++++++++ .../gametest/core/TestReporters.kt | 48 +++++ src/testMod/resources/ccgametest.mixins.json | 5 + 18 files changed, 729 insertions(+), 179 deletions(-) delete mode 100644 src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java create mode 100644 src/testMod/java/dan200/computercraft/gametest/core/MinecraftExtensions.java delete mode 100644 src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java create mode 100644 src/testMod/java/dan200/computercraft/mixin/gametest/client/LevelSummaryMixin.java create mode 100644 src/testMod/java/dan200/computercraft/mixin/gametest/client/MinecraftMixin.java create mode 100644 src/testMod/java/dan200/computercraft/mixin/gametest/client/WorldOpenFlowsMixin.java create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/api/ClientGameTest.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/api/ClientTestExtensions.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/api/TestTags.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt create mode 100644 src/testMod/kotlin/dan200/computercraft/gametest/core/TestReporters.kt diff --git a/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java b/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java index 8c613eb13..b8d961bf3 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/CCTestCommand.java @@ -107,7 +107,7 @@ private static Path getWorldComputerPath(MinecraftServer server) { } private static Path getSourceComputerPath() { - return TestHooks.sourceDir.resolve("computer"); + return TestHooks.getSourceDir().resolve("computer"); } private static int error(CommandSourceStack source, String message) { diff --git a/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java b/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java deleted file mode 100644 index 14170d26a..000000000 --- a/src/testMod/java/dan200/computercraft/gametest/core/ClientHooks.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest.core; - -import net.minecraft.client.CloudStatus; -import net.minecraft.client.Minecraft; -import net.minecraft.client.ParticleStatus; -import net.minecraft.client.gui.screens.TitleScreen; -import net.minecraft.client.tutorial.TutorialSteps; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ScreenEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -@Mod.EventBusSubscriber(modid = "cctest", value = Dist.CLIENT) -public final class ClientHooks { - private static final Logger LOG = LogManager.getLogger(TestHooks.class); - - private static boolean triggered = false; - - private ClientHooks() { - } - - @SubscribeEvent - public static void onGuiInit(ScreenEvent.Init event) { - if (triggered || !(event.getScreen() instanceof TitleScreen)) - return; - triggered = true; - - ClientHooks.openWorld(); - } - - private static void openWorld() { - Minecraft minecraft = Minecraft.getInstance(); - - // Clear some options before we get any further. - minecraft.options.autoJump().set(false); - minecraft.options.cloudStatus().set(CloudStatus.OFF); - minecraft.options.particles().set(ParticleStatus.MINIMAL); - minecraft.options.tutorialStep = TutorialSteps.NONE; - minecraft.options.renderDistance().set(6); - minecraft.options.gamma().set(1.0); - } -} diff --git a/src/testMod/java/dan200/computercraft/gametest/core/MinecraftExtensions.java b/src/testMod/java/dan200/computercraft/gametest/core/MinecraftExtensions.java new file mode 100644 index 000000000..1a21f8d9a --- /dev/null +++ b/src/testMod/java/dan200/computercraft/gametest/core/MinecraftExtensions.java @@ -0,0 +1,15 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.core; + +import net.minecraft.client.Minecraft; + +/** + * Extensions to {@link Minecraft}, injected via mixin. + */ +public interface MinecraftExtensions { + boolean computercraft$isRenderingStable(); +} diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java index 5ea5e8cfc..7c5d12362 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestAPI.java @@ -16,7 +16,10 @@ import de.srendi.advancedperipherals.common.util.LuaConverter; import net.minecraft.gametest.framework.GameTestSequence; import net.minecraftforge.server.ServerLifecycleHooks; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import java.util.Optional; /** @@ -27,8 +30,10 @@ * @see TestExtensionsKt#thenComputerOk(GameTestSequence, String, String) To check tests on the computer have passed. */ public class TestAPI extends ComputerState implements ILuaAPI { + private static final Logger LOG = LoggerFactory.getLogger(TestAPI.class); + private final IComputerSystem system; - private String label; + private @Nullable String label; TestAPI(IComputerSystem system) { this.system = system; @@ -39,10 +44,10 @@ public void startup() { if (label == null) label = system.getLabel(); if (label == null) { label = "#" + system.getID(); - ComputerCraft.log.warn("Computer {} has no label", label); + LOG.warn("Computer {} has no label", label); } - ComputerCraft.log.info("Computer '{}' has turned on.", label); + LOG.info("Computer '{}' has turned on.", label); markers.clear(); error = null; lookup.put(label, this); @@ -50,19 +55,18 @@ public void startup() { @Override public void shutdown() { - ComputerCraft.log.info("Computer '{}' has shut down.", label); - if (lookup.get(label) == this) - lookup.remove(label); + LOG.info("Computer '{}' has shut down.", label); + if (lookup.get(label) == this) lookup.remove(label); } @Override public String[] getNames() { - return new String[]{"test"}; + return new String[]{ "test" }; } @LuaFunction public final void fail(String message) throws LuaException { - ComputerCraft.log.error("Computer '{}' failed with {}", label, message); + LOG.error("Computer '{}' failed with {}", label, message); if (markers.contains(ComputerState.DONE)) throw new LuaException("Cannot call fail/ok multiple times."); markers.add(ComputerState.DONE); error = message; @@ -71,7 +75,7 @@ public final void fail(String message) throws LuaException { @LuaFunction public final void ok(Optional marker) throws LuaException { - String actualMarker = marker.orElse(ComputerState.DONE); + var actualMarker = marker.orElse(ComputerState.DONE); if (markers.contains(ComputerState.DONE) || markers.contains(actualMarker)) { throw new LuaException("Cannot call fail/ok multiple times."); } @@ -81,7 +85,7 @@ public final void ok(Optional marker) throws LuaException { @LuaFunction public final void log(String message) { - ComputerCraft.log.info("[Computer '{}'] {}", label, message); + LOG.info("[Computer '{}'] {}", label, message); } @LuaFunction diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java b/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java deleted file mode 100644 index cf1164c52..000000000 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestHooks.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.gametest.core; - -import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.gametest.api.Times; -import dan200.computercraft.shared.computer.core.ServerContext; -import net.minecraft.core.BlockPos; -import net.minecraft.gametest.framework.GameTestRunner; -import net.minecraft.gametest.framework.GameTestTicker; -import net.minecraft.gametest.framework.StructureUtils; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.Level; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.file.Path; -import java.nio.file.Paths; - -public class TestHooks { - public static final Logger LOGGER = LoggerFactory.getLogger(TestHooks.class); - - public static final Path sourceDir = Paths.get(System.getProperty("advancedperipheralstest.sources")).normalize().toAbsolutePath(); - - public static void init() { - ServerContext.luaMachine = ManagedComputers.INSTANCE; - ComputerCraftAPI.registerAPIFactory(TestAPI::new); - StructureUtils.testStructuresDir = sourceDir.resolve("structures").toString(); - } - - public static void onServerStarted(MinecraftServer server) { - GameRules rules = server.getGameRules(); - rules.getRule(GameRules.RULE_DAYLIGHT).set(false, server); - - ServerLevel world = server.getLevel(Level.OVERWORLD); - if (world != null) - world.setDayTime(Times.NOON); - - LOGGER.info("Cleaning up after last run"); - GameTestRunner.clearAllTests(server.overworld(), new BlockPos(0, -60, 0), GameTestTicker.SINGLETON, 200); - - // Delete server context and add one with a mutable machine factory. This allows us to set the factory for - // specific test batches without having to reset all computers. - for (var computer : ServerContext.get(server).registry().getComputers()) { - var label = computer.getLabel() == null ? "#" + computer.getID() : computer.getLabel(); - LOGGER.warn("Unexpected computer {}", label); - } - - LOGGER.info("Importing files"); - CCTestCommand.importFiles(server); - } -} diff --git a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java index 116ecd458..187f446a0 100644 --- a/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java +++ b/src/testMod/java/dan200/computercraft/gametest/core/TestMod.java @@ -7,17 +7,16 @@ import dan200.computercraft.export.Exporter; import dan200.computercraft.gametest.api.GameTestHolder; -import net.minecraft.gametest.framework.GameTest; -import net.minecraft.gametest.framework.GameTestRegistry; -import net.minecraft.gametest.framework.StructureUtils; -import net.minecraft.gametest.framework.TestFunction; -import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.RegisterClientCommandsEvent; +import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.RegisterGameTestsEvent; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.server.ServerStartedEvent; import net.minecraftforge.eventbus.api.EventPriority; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -43,7 +42,7 @@ public TestMod() { var bus = MinecraftForge.EVENT_BUS; bus.addListener(EventPriority.LOW, (ServerStartedEvent e) -> TestHooks.onServerStarted(e.getServer())); bus.addListener((RegisterCommandsEvent e) -> CCTestCommand.register(e.getDispatcher())); - bus.addListener((RegisterClientCommandsEvent e) -> Exporter.register(e.getDispatcher())); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> TestMod::onInitializeClient); var modBus = FMLJavaModLoadingContext.get().getModEventBus(); modBus.addListener((RegisterGameTestsEvent event) -> { @@ -56,6 +55,17 @@ public TestMod() { }); } + private static void onInitializeClient() { + var bus = MinecraftForge.EVENT_BUS; + + bus.addListener((TickEvent.ServerTickEvent e) -> { + if (e.phase == TickEvent.Phase.START) ClientTestHooks.onServerTick(e.getServer()); + }); + bus.addListener((ScreenEvent.Opening e) -> { + if (ClientTestHooks.onOpenScreen(e.getScreen())) e.setCanceled(true); + }); + bus.addListener((RegisterClientCommandsEvent e) -> Exporter.register(e.getDispatcher())); + } private static Class loadClass(String name) { try { @@ -68,60 +78,7 @@ private static Class loadClass(String name) { private static void registerClass(String className, Consumer fallback) { var klass = loadClass(className); for (var method : klass.getDeclaredMethods()) { - var testInfo = method.getAnnotation(GameTest.class); - if (testInfo == null) { - fallback.accept(method); - continue; - } - - GameTestRegistry.getAllTestFunctions().add(turnMethodIntoTestFunction(method, testInfo)); - GameTestRegistry.getAllTestClassNames().add(className); + TestHooks.registerTest(klass, method, fallback); } } - - /** - * Custom implementation of {@link GameTestRegistry#turnMethodIntoTestFunction(Method)} which makes - * {@link GameTest#template()} behave the same as Fabric, namely in that it points to a {@link ResourceLocation}, - * rather than a test-class-specific structure. - *

- * This effectively acts as a global version of {@link PrefixGameTestTemplate}, just one which doesn't require Forge - * to be present. - * - * @param method The method to register. - * @param testInfo The test info. - * @return The constructed test function. - */ - private static TestFunction turnMethodIntoTestFunction(Method method, GameTest testInfo) { - var className = method.getDeclaringClass().getSimpleName().toLowerCase(Locale.ROOT); - var testName = className + "." + method.getName().toLowerCase(Locale.ROOT); - return new TestFunction( - testInfo.batch(), - testName, - testInfo.template().isEmpty() ? testName : testInfo.template(), - StructureUtils.getRotationForRotationSteps(testInfo.rotationSteps()), testInfo.timeoutTicks(), testInfo.setupTicks(), - testInfo.required(), testInfo.requiredSuccesses(), testInfo.attempts(), - turnMethodIntoConsumer(method) - ); - } - - private static Consumer turnMethodIntoConsumer(Method method) { - return value -> { - try { - Object instance = null; - if (!Modifier.isStatic(method.getModifiers())) { - instance = method.getDeclaringClass().getConstructor().newInstance(); - } - - method.invoke(instance, value); - } catch (InvocationTargetException e) { - if (e.getCause() instanceof RuntimeException) { - throw (RuntimeException) e.getCause(); - } else { - throw new RuntimeException(e.getCause()); - } - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - }; - } } diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java index bbc65b042..86f3e5d16 100644 --- a/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/GameTestSequenceMixin.java @@ -37,7 +37,7 @@ public void tickAndContinue(long ticks) { parent.fail(e); } catch (Exception e) { // Fail the test, rather than crashing the server. - TestHooks.LOGGER.error("{} threw unexpected exception", parent.getTestName(), e); + TestHooks.LOG.error("{} threw unexpected exception", parent.getTestName(), e); parent.fail(e); } } diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/client/LevelSummaryMixin.java b/src/testMod/java/dan200/computercraft/mixin/gametest/client/LevelSummaryMixin.java new file mode 100644 index 000000000..41b3548b8 --- /dev/null +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/client/LevelSummaryMixin.java @@ -0,0 +1,19 @@ +package dan200.computercraft.mixin.gametest.client; + +import net.minecraft.world.level.storage.LevelSummary; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +/** + * Used to suppress the "Worlds using Experimental Settings are not supported" warning + * when loading a world in GameTest. + */ +@Mixin(LevelSummary.class) +public class LevelSummaryMixin { + + @Overwrite + public boolean isExperimental() { + return false; + } + +} diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/client/MinecraftMixin.java b/src/testMod/java/dan200/computercraft/mixin/gametest/client/MinecraftMixin.java new file mode 100644 index 000000000..141bf1525 --- /dev/null +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/client/MinecraftMixin.java @@ -0,0 +1,55 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.mixin.gametest.client; + +import dan200.computercraft.gametest.core.MinecraftExtensions; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.renderer.LevelRenderer; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import javax.annotation.Nullable; +import java.util.concurrent.atomic.AtomicBoolean; + +@Mixin(Minecraft.class) +class MinecraftMixin implements MinecraftExtensions { + @Final + @Shadow + public LevelRenderer levelRenderer; + + @Shadow + @Nullable + public ClientLevel level; + + @Shadow + @Nullable + public LocalPlayer player; + + @Unique + private final AtomicBoolean isStable = new AtomicBoolean(false); + + @Inject(method = "runTick", at = @At("TAIL")) + @SuppressWarnings("unused") + private void updateStable(boolean render, CallbackInfo ci) { + isStable.set( + level != null && player != null && + levelRenderer.isChunkCompiled(player.blockPosition()) && levelRenderer.countRenderedChunks() > 10 && + levelRenderer.hasRenderedAllChunks() + ); + } + + @Override + public boolean computercraft$isRenderingStable() { + return isStable.get(); + } +} diff --git a/src/testMod/java/dan200/computercraft/mixin/gametest/client/WorldOpenFlowsMixin.java b/src/testMod/java/dan200/computercraft/mixin/gametest/client/WorldOpenFlowsMixin.java new file mode 100644 index 000000000..c55a72e1c --- /dev/null +++ b/src/testMod/java/dan200/computercraft/mixin/gametest/client/WorldOpenFlowsMixin.java @@ -0,0 +1,30 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.mixin.gametest.client; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.worldselection.WorldOpenFlows; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; + +@Mixin(WorldOpenFlows.class) +public class WorldOpenFlowsMixin { + /** + * Never prompt for backup/experimental options when running tests. + * + * @param screen The current menu. + * @param level The level to load. + * @param customised Whether this rule uses legacy customised worldgen options. + * @param action The action run to load the world. + * @author SquidDev + * @reason Makes it easier to run tests. We can switch to an @Inject if this becomes a problem. + */ + @Overwrite + @SuppressWarnings("unused") + private void askForBackup(Screen screen, String level, boolean customised, Runnable action) { + action.run(); + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientGameTest.kt b/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientGameTest.kt new file mode 100644 index 000000000..2527d3159 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientGameTest.kt @@ -0,0 +1,33 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.api + +import net.minecraft.gametest.framework.GameTest + +/** + * Similar to [GameTest], this annotation defines a method which runs under Minecraft's gametest sequence. + * + * Unlike standard game tests, client game tests are only registered when running under the Minecraft client, and run + * sequentially rather than in parallel. + */ +@Target(AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +annotation class ClientGameTest( + /** + * The template to use for this test, identical to [GameTest.template] + */ + val template: String = "", + + /** + * The timeout for this test, identical to [GameTest.timeoutTicks]. + */ + val timeoutTicks: Int = Timeouts.DEFAULT, + + /** + * The tag associated with this test, denoting when it should run. + */ + val tag: String = TestTags.CLIENT, +) diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientTestExtensions.kt b/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientTestExtensions.kt new file mode 100644 index 000000000..7c8147ab7 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/api/ClientTestExtensions.kt @@ -0,0 +1,136 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.api + +import dan200.computercraft.gametest.core.MinecraftExtensions +import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor +import net.minecraft.client.Minecraft +import net.minecraft.client.Screenshot +import net.minecraft.client.gui.screens.inventory.MenuAccess +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTestAssertException +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.gametest.framework.GameTestSequence +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.EntityType +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.inventory.MenuType +import net.minecraftforge.registries.ForgeRegistries +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ExecutionException +import java.util.concurrent.atomic.AtomicBoolean + +/** + * Attempt to guess whether all chunks have been rendered. + */ +fun Minecraft.isRenderingStable(): Boolean = (this as MinecraftExtensions).`computercraft$isRenderingStable`() + +/** + * Run a task on the client. + */ +fun GameTestSequence.thenOnClient(task: ClientTestHelper.() -> Unit): GameTestSequence { + var future: CompletableFuture? = null + thenExecute { future = Minecraft.getInstance().submit { task(ClientTestHelper()) } } + thenWaitUntil { if (!future!!.isDone) throw GameTestAssertException("Not done task yet") } + thenExecute { + try { + future!!.get() + } catch (e: ExecutionException) { + throw e.cause ?: e + } + } + return this +} + +/** + * Take a screenshot of the current game state. + */ +fun GameTestSequence.thenScreenshot(name: String? = null, showGui: Boolean = false): GameTestSequence { + val suffix = if (name == null) "" else "-$name" + val test = (this as GameTestSequenceAccessor).parent + val fullName = "${test.testName}$suffix" + + // Wait until all chunks have been rendered and we're idle for an extended period. + var counter = 0 + thenWaitUntil { + if (Minecraft.getInstance().isRenderingStable()) { + val idleFor = ++counter + if (idleFor <= 20) throw GameTestAssertException("Only idle for $idleFor ticks") + } else { + counter = 0 + throw GameTestAssertException("Waiting for client to finish rendering") + } + } + + // Now disable the GUI, take a screenshot and reenable it. Sleep a little afterwards to ensure the render thread + // has caught up. + thenOnClient { minecraft.options.hideGui = !showGui } + thenIdle(2) + + // Take a screenshot and wait for it to have finished. + val hasScreenshot = AtomicBoolean() + thenOnClient { screenshot("$fullName.png") { hasScreenshot.set(true) } } + thenWaitUntil { if (!hasScreenshot.get()) throw GameTestAssertException("Screenshot does not exist") } + thenOnClient { minecraft.options.hideGui = false } + + return this +} + +/** + * "Reset" the current player, ensuring. + */ +fun ServerPlayer.setupForTest() { + if (containerMenu != inventoryMenu) closeContainer() +} + +/** + * Position the player at an armor stand. + */ +fun GameTestHelper.positionAtArmorStand() { + val stand = getEntity(EntityType.ARMOR_STAND) + val player = level.randomPlayer ?: throw GameTestAssertException("Player does not exist") + + player.setupForTest() + player.connection.teleport(stand.x, stand.y, stand.z, stand.yRot, stand.xRot) +} + +/** + * Position the player at a given coordinate. + */ +fun GameTestHelper.positionAt(pos: BlockPos, yRot: Float = 0.0f, xRot: Float = 0.0f) { + val absolutePos = absolutePos(pos) + val player = level.randomPlayer ?: throw GameTestAssertException("Player does not exist") + + player.setupForTest() + player.connection.teleport(absolutePos.x + 0.5, absolutePos.y + 0.5, absolutePos.z + 0.5, yRot, xRot) +} + +/** + * The equivalent of a [GameTestHelper] on the client. + */ +class ClientTestHelper { + val minecraft: Minecraft = Minecraft.getInstance() + + fun screenshot(name: String, callback: () -> Unit = {}) { + Screenshot.grab(minecraft.gameDirectory, name, minecraft.mainRenderTarget) { callback() } + } + + /** + * Get the currently open [AbstractContainerMenu], ensuring it is of a specific type. + */ + fun getOpenMenu(type: MenuType): T { + fun getName(type: MenuType<*>) = ForgeRegistries.MENU_TYPES.getKey(type) + + val screen = minecraft.screen + @Suppress("UNCHECKED_CAST") + when { + screen == null -> throw GameTestAssertException("Expected a ${getName(type)} menu, but no screen is open") + screen !is MenuAccess<*> -> throw GameTestAssertException("Expected a ${getName(type)} menu, but a $screen is open") + screen.menu.type != type -> throw GameTestAssertException("Expected a ${getName(type)} menu, but a ${getName(screen.menu.type)} is open") + else -> return screen.menu as T + } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt index 6f776aee7..16874ee2f 100644 --- a/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt +++ b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestExtensions.kt @@ -46,7 +46,9 @@ object Times { * @see GameTest.timeoutTicks */ object Timeouts { - private const val SECOND: Int = 20 + const val SECOND: Int = 20 + + const val DEFAULT: Int = SECOND * 5 const val COMPUTER_TIMEOUT: Int = SECOND * 15 } diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/api/TestTags.kt b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestTags.kt new file mode 100644 index 000000000..a0b999d1c --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/api/TestTags.kt @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.gametest.api + +/** + * "Tags" associated with each test, denoting whether a specific test should be registered for the current Minecraft + * session. + * + * This is used to only run some tests on the client, or when a specific mod is loaded. + */ +object TestTags { + const val COMMON = "common" + const val CLIENT = "client" + + private val tags: Set = System.getProperty("advancedperipheralstest.tags", COMMON).split(',').toSet() + + fun isEnabled(tag: String) = tags.contains(tag) +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt new file mode 100644 index 000000000..e986197ee --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt @@ -0,0 +1,189 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.core + +import dan200.computercraft.gametest.api.Timeouts +import dan200.computercraft.gametest.api.isRenderingStable +import dan200.computercraft.gametest.api.setupForTest +import net.minecraft.client.CloudStatus +import net.minecraft.client.Minecraft +import net.minecraft.client.ParticleStatus +import net.minecraft.client.gui.screens.AccessibilityOptionsScreen +import net.minecraft.client.gui.screens.Screen +import net.minecraft.client.gui.screens.TitleScreen +import net.minecraft.client.tutorial.TutorialSteps +import net.minecraft.core.BlockPos +import net.minecraft.core.Registry +import net.minecraft.core.RegistryAccess +import net.minecraft.gametest.framework.* +import net.minecraft.server.MinecraftServer +import net.minecraft.sounds.SoundSource +import net.minecraft.util.RandomSource +import net.minecraft.world.Difficulty +import net.minecraft.world.level.* +import net.minecraft.world.level.block.Rotation +import net.minecraft.world.level.levelgen.presets.WorldPresets +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import kotlin.system.exitProcess + +/** + * Client-side hooks for game tests. + * + * This mirrors Minecraft's + */ +object ClientTestHooks { + private val LOG: Logger = LoggerFactory.getLogger(ClientTestHooks::class.java) + + private const val LEVEL_NAME = "test" + + /** + * Time (in ticks) that we wait after the client joins the world + */ + private const val STARTUP_DELAY = 5 * Timeouts.SECOND + + /** + * Whether our client-side game test driver is enabled. + */ + private val enabled: Boolean = System.getProperty("advancedperipheralstest.client") != null + + private var loadedWorld: Boolean = false + + @JvmStatic + fun onOpenScreen(screen: Screen): Boolean = when { + enabled && !loadedWorld && (screen is TitleScreen || screen is AccessibilityOptionsScreen) -> { + loadedWorld = true + openWorld() + true + } + + else -> false + } + + /** + * Open or create our test world immediately on game launch. + */ + private fun openWorld() { + val minecraft = Minecraft.getInstance() + + // Clear some options before we get any further. + minecraft.options.autoJump().set(false) + minecraft.options.cloudStatus().set(CloudStatus.OFF) + minecraft.options.particles().set(ParticleStatus.MINIMAL) + minecraft.options.tutorialStep = TutorialSteps.NONE + minecraft.options.renderDistance().set(6) + minecraft.options.gamma().set(1.0) + minecraft.options.setSoundCategoryVolume(SoundSource.MUSIC, 0f) + minecraft.options.setSoundCategoryVolume(SoundSource.AMBIENT, 0f) + + if (minecraft.levelSource.levelExists(LEVEL_NAME)) { + LOG.info("World already exists, opening.") + minecraft.createWorldOpenFlows().loadLevel(minecraft.screen, LEVEL_NAME) + } else { + LOG.info("World does not exist, creating it.") + val rules = GameRules() + rules.getRule(GameRules.RULE_DOMOBSPAWNING).set(false, null) + rules.getRule(GameRules.RULE_DAYLIGHT).set(false, null) + rules.getRule(GameRules.RULE_WEATHER_CYCLE).set(false, null) + + val registryAccess = RegistryAccess.builtinCopy().freeze() + minecraft.createWorldOpenFlows().createFreshLevel( + LEVEL_NAME, + LevelSettings("Test Level", GameType.CREATIVE, false, Difficulty.EASY, true, rules, DataPackConfig.DEFAULT), + registryAccess, + registryAccess.registryOrThrow(Registry.WORLD_PRESET_REGISTRY).getHolderOrThrow(WorldPresets.FLAT).value().createWorldGenSettings(RandomSource.create().nextLong(), false, false) + ) + } + } + + private var testTracker: MultipleTestTracker? = null + private var hasFinished: Boolean = false + private var startupDelay: Int = STARTUP_DELAY + + @JvmStatic + fun onServerTick(server: MinecraftServer) { + if (!enabled || hasFinished) return + + val testTracker = when (val tracker = this.testTracker) { + null -> { + if (server.overworld().players().isEmpty()) return + if (!Minecraft.getInstance().isRenderingStable()) return + if (startupDelay >= 0) { + // TODO: Is there a better way? Maybe set a flag when the client starts rendering? + startupDelay-- + return + } + + LOG.info("Server ready, starting.") + + val tests = GameTestRunner.runTestBatches( + GameTestRunner.groupTestsIntoBatches(GameTestRegistry.getAllTestFunctions()), + BlockPos(0, -60, 0), + Rotation.NONE, + server.overworld(), + GameTestTicker.SINGLETON, + 8, + ) + val testTracker = MultipleTestTracker(tests) + testTracker.addListener( + object : GameTestListener { + fun testFinished() { + for (it in server.playerList.players) it.setupForTest() + } + + override fun testPassed(test: GameTestInfo) = testFinished() + override fun testFailed(test: GameTestInfo) = testFinished() + override fun testStructureLoaded(test: GameTestInfo) = Unit + }, + ) + + LOG.info("{} tests are now running!", testTracker.totalCount) + this.testTracker = testTracker + testTracker + } + + else -> tracker + } + + if (server.overworld().gameTime % 20L == 0L) LOG.info(testTracker.progressBar) + + if (testTracker.isDone) { + hasFinished = true + LOG.info(testTracker.progressBar) + + GlobalTestReporter.finish() + LOG.info("========= {} GAME TESTS COMPLETE ======================", testTracker.totalCount) + if (testTracker.hasFailedRequired()) { + LOG.info("{} required tests failed :(", testTracker.failedRequiredCount) + for (test in testTracker.failedRequired) LOG.info(" - {}", test.testName) + } else { + LOG.info("All {} required tests passed :)", testTracker.totalCount) + } + if (testTracker.hasFailedOptional()) { + LOG.info("{} optional tests failed", testTracker.failedOptionalCount) + for (test in testTracker.failedOptional) LOG.info(" - {}", test.testName) + } + LOG.info("====================================================") + + // Stop Minecraft *from the client thread*. We need to do this to avoid deadlocks in stopping the server. + val minecraft = Minecraft.getInstance() + minecraft.execute { + LOG.info("Stopping client.") + minecraft.level!!.disconnect() + minecraft.clearLevel() + minecraft.stop() + + exitProcess( + when { + testTracker.totalCount == 0 -> 1 + testTracker.hasFailedRequired() -> 2 + else -> 0 + }, + ) + } + } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt new file mode 100644 index 000000000..ab1c77de6 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt @@ -0,0 +1,143 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.core + +import dan200.computercraft.api.ComputerCraftAPI +import dan200.computercraft.gametest.* +import dan200.computercraft.gametest.api.ClientGameTest +import dan200.computercraft.gametest.api.TestTags +import dan200.computercraft.gametest.api.Times +import dan200.computercraft.shared.computer.core.ServerContext +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.* +import net.minecraft.server.MinecraftServer +import net.minecraft.world.level.GameRules +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.io.File +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method +import java.lang.reflect.Modifier +import java.nio.file.Path +import java.nio.file.Paths +import java.util.function.Consumer +import javax.xml.parsers.ParserConfigurationException + +object TestHooks { + @JvmField + val LOG: Logger = LoggerFactory.getLogger(TestHooks::class.java) + + @JvmStatic + val sourceDir: Path = Paths.get(System.getProperty("advancedperipheralstest.sources")).normalize().toAbsolutePath() + + @JvmStatic + fun init() { + ServerContext.luaMachine = ManagedComputers + ComputerCraftAPI.registerAPIFactory(::TestAPI) + StructureUtils.testStructuresDir = sourceDir.resolve("structures").toString() + + // Set up our test reporter if configured. + val outputPath = System.getProperty("advancedperipheralstest.gametest-report") + if (outputPath != null) { + try { + GlobalTestReporter.replaceWith( + MultiTestReporter( + JunitTestReporter(File(outputPath)), + LogTestReporter(), + ), + ) + } catch (e: ParserConfigurationException) { + throw RuntimeException(e) + } + } + } + + @JvmStatic + fun onServerStarted(server: MinecraftServer) { + val rules = server.gameRules + rules.getRule(GameRules.RULE_DAYLIGHT).set(false, server) + server.overworld().dayTime = Times.NOON + + LOG.info("Cleaning up after last run") + GameTestRunner.clearAllTests(server.overworld(), BlockPos(0, -60, 0), GameTestTicker.SINGLETON, 200) + + // Delete server context and add one with a mutable machine factory. This allows us to set the factory for + // specific test batches without having to reset all computers. + for (computer in ServerContext.get(server).registry().computers) { + val label = if (computer.label == null) "#" + computer.id else computer.label!! + LOG.warn("Unexpected computer {}", label) + } + + LOG.info("Importing files") + CCTestCommand.importFiles(server) + } + + private val isCi = System.getenv("CI") != null + + /** + * Adjust the timeout of a test. This makes it 1.5 times longer when run under CI, as CI servers are less powerful + * than our own. + */ + private fun adjustTimeout(timeout: Int): Int = if (isCi) timeout + (timeout / 2) else timeout + + @JvmStatic + fun registerTest(testClass: Class<*>, method: Method, fallbackRegister: Consumer) { + val className = testClass.simpleName.lowercase() + val testName = className + "." + method.name.lowercase() + + method.getAnnotation(GameTest::class.java)?.let { testInfo -> + if (!TestTags.isEnabled(TestTags.COMMON)) return + + GameTestRegistry.getAllTestFunctions().add( + TestFunction( + testInfo.batch, testName, testInfo.template.ifEmpty { testName }, + StructureUtils.getRotationForRotationSteps(testInfo.rotationSteps), + adjustTimeout(testInfo.timeoutTicks), + testInfo.setupTicks, + testInfo.required, testInfo.requiredSuccesses, testInfo.attempts, + ) { value -> safeInvoke(method, value) }, + ) + GameTestRegistry.getAllTestClassNames().add(testClass.simpleName) + return + } + + method.getAnnotation(ClientGameTest::class.java)?.let { testInfo -> + if (!TestTags.isEnabled(testInfo.tag)) return + + GameTestRegistry.getAllTestFunctions().add( + TestFunction( + testName, + testName, + testInfo.template.ifEmpty { testName }, + adjustTimeout(testInfo.timeoutTicks), + 0, + true, + ) { value -> safeInvoke(method, value) }, + ) + GameTestRegistry.getAllTestClassNames().add(testClass.simpleName) + return + } + + fallbackRegister.accept(method) + } + + private fun safeInvoke(method: Method, value: Any) { + try { + var instance: Any? = null + if (!Modifier.isStatic(method.modifiers)) { + instance = method.declaringClass.getConstructor().newInstance() + } + method.invoke(instance, value) + } catch (e: InvocationTargetException) { + when (val cause = e.cause) { + is RuntimeException -> throw cause + else -> throw RuntimeException(cause) + } + } catch (e: ReflectiveOperationException) { + throw RuntimeException(e) + } + } +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/TestReporters.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/TestReporters.kt new file mode 100644 index 000000000..4d9d4bf89 --- /dev/null +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/TestReporters.kt @@ -0,0 +1,48 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.gametest.core + +import net.minecraft.gametest.framework.GameTestInfo +import net.minecraft.gametest.framework.JUnitLikeTestReporter +import net.minecraft.gametest.framework.TestReporter +import java.io.File +import java.io.IOException +import java.nio.file.Files +import javax.xml.transform.TransformerException + +/** + * A test reporter which delegates to a list of other reporters. + */ +class MultiTestReporter(private val reporters: List) : TestReporter { + constructor(vararg reporters: TestReporter) : this(listOf(*reporters)) + + override fun onTestFailed(test: GameTestInfo) { + for (reporter in reporters) reporter.onTestFailed(test) + } + + override fun onTestSuccess(test: GameTestInfo) { + for (reporter in reporters) reporter.onTestSuccess(test) + } + + override fun finish() { + for (reporter in reporters) reporter.finish() + } +} + +/** + * Reports tests to a JUnit XML file. This is equivalent to [JUnitLikeTestReporter], except it ensures the destination + * directory exists. + */ +class JunitTestReporter constructor(destination: File) : JUnitLikeTestReporter(destination) { + override fun save(file: File) { + try { + Files.createDirectories(file.toPath().parent) + } catch (e: IOException) { + throw TransformerException("Failed to create parent directory", e) + } + super.save(file) + } +} diff --git a/src/testMod/resources/ccgametest.mixins.json b/src/testMod/resources/ccgametest.mixins.json index 76ac77997..299086dc9 100644 --- a/src/testMod/resources/ccgametest.mixins.json +++ b/src/testMod/resources/ccgametest.mixins.json @@ -12,5 +12,10 @@ "GameTestSequenceAccessor", "GameTestSequenceMixin", "TestCommandAccessor" + ], + "client": [ + "client.MinecraftMixin", + "client.WorldOpenFlowsMixin", + "client.LevelSummaryMixin" ] } From bc4d3e470cdd78835403df9730e912eff1269c8a Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 2 Jun 2024 01:31:48 +0200 Subject: [PATCH 48/61] Add gradle task to start automated client tests --- build.gradle | 11 +- buildSrc/build.gradle.kts | 21 ++ .../kotlin/cc/tweaked/gradle/Extensions.kt | 157 +++++++++++++ .../cc/tweaked/gradle/ForgeExtensions.kt | 26 +++ .../kotlin/cc/tweaked/gradle/MinecraftExec.kt | 215 ++++++++++++++++++ .../cc/tweaked/gradle/ProcessHelpers.kt | 77 +++++++ .../gradle/common/util/runs/RunConfigSetup.kt | 48 ++++ .../gametest/core/ClientTestHooks.kt | 2 +- 8 files changed, 554 insertions(+), 3 deletions(-) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/cc/tweaked/gradle/Extensions.kt create mode 100644 buildSrc/src/main/kotlin/cc/tweaked/gradle/ForgeExtensions.kt create mode 100644 buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt create mode 100644 buildSrc/src/main/kotlin/cc/tweaked/gradle/ProcessHelpers.kt create mode 100644 buildSrc/src/main/kotlin/net/minecraftforge/gradle/common/util/runs/RunConfigSetup.kt diff --git a/build.gradle b/build.gradle index d2d3e930d..a24ec0d47 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,4 @@ +import cc.tweaked.gradle.ClientJavaExec import net.darkhax.curseforgegradle.TaskPublishCurseForge import java.text.SimpleDateFormat @@ -8,7 +9,7 @@ plugins { id 'org.jetbrains.changelog' version '1.2.1' id "com.modrinth.minotaur" version "2.+" id "org.jetbrains.kotlin.jvm" version "${kotlin_version}" - id 'net.minecraftforge.gradle' version '[6.0.18,6.2)' + id 'net.minecraftforge.gradle' id 'org.parchmentmc.librarian.forgegradle' version '1.+' id 'org.spongepowered.mixin' version '0.7.+' id "com.github.breadmoirai.github-release" version "2.5.2" @@ -148,7 +149,7 @@ minecraft { } } - gameTestClient { + testClient { workingDirectory project.file('test-files/client') parent runs.client @@ -664,3 +665,9 @@ publishing { } } } + +tasks.register('runGameTestClient', ClientJavaExec, { task -> + description "Runs client-side gametests with no mods" + setRunConfig(minecraft.runs["testClient"]) + tags("client") +}) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 000000000..d2d420771 --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,21 @@ +plugins { + `java-gradle-plugin` + `kotlin-dsl` + kotlin("jvm") version "1.9.23" +} + +repositories { + mavenCentral() + + maven("https://maven.minecraftforge.net") { + name = "Forge" + content { + includeGroup("net.minecraftforge") + includeGroup("net.minecraftforge.gradle") + } + } +} + +dependencies { + implementation("net.minecraftforge.gradle:ForgeGradle:[6.0.18,6.2)") +} diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/Extensions.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/Extensions.kt new file mode 100644 index 000000000..8afc4f0f3 --- /dev/null +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/Extensions.kt @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package cc.tweaked.gradle + +import org.gradle.api.artifacts.dsl.DependencyHandler +import org.gradle.api.file.FileSystemLocation +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.JavaExec +import org.gradle.process.BaseExecSpec +import org.gradle.process.JavaExecSpec +import org.gradle.process.ProcessForkOptions + +/** + * Add an annotation processor to all source sets. + */ +fun DependencyHandler.annotationProcessorEverywhere(dep: Any) { + add("compileOnly", dep) + add("annotationProcessor", dep) + + add("clientCompileOnly", dep) + add("clientAnnotationProcessor", dep) + + add("testCompileOnly", dep) + add("testAnnotationProcessor", dep) +} + +/** + * A version of [JavaExecSpec.copyTo] which copies *all* properties. + */ +fun JavaExec.copyToFull(spec: JavaExec) { + copyTo(spec) + + // Additional Java options + spec.jvmArgs = jvmArgs // Fabric overrides getJvmArgs so copyTo doesn't do the right thing. + spec.args = args + spec.argumentProviders.addAll(argumentProviders) + spec.mainClass.set(mainClass) + spec.classpath = classpath + spec.javaLauncher.set(javaLauncher) + if (executable != null) spec.setExecutable(executable!!) + + // Additional ExecSpec options + copyToExec(spec) +} + +/** + * Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo]. + */ +fun BaseExecSpec.copyToExec(spec: BaseExecSpec) { + spec.isIgnoreExitValue = isIgnoreExitValue + if (standardInput != null) spec.standardInput = standardInput + if (standardOutput != null) spec.standardOutput = standardOutput + if (errorOutput != null) spec.errorOutput = errorOutput +} + +/** + * An alternative to [Nothing] with a more descriptive name. Use to enforce calling a function with named arguments: + * + * ```kotlin + * fun f(vararg unused: UseNamedArgs, arg1: Int, arg2: Int) { + * // ... + * } + * ``` + */ +class UseNamedArgs private constructor() + +/** + * An [AutoCloseable] implementation which can be used to combine other [AutoCloseable] instances. + * + * Values which implement [AutoCloseable] can be dynamically registered with [CloseScope.add]. When the scope is closed, + * each value is closed in the opposite order. + * + * This is largely intended for cases where it's not appropriate to nest [AutoCloseable.use], for instance when nested + * would be too deep. + */ +class CloseScope : AutoCloseable { + private val toClose = ArrayDeque() + + /** + * Add a value to be closed when this scope is closed. + */ + public fun add(value: AutoCloseable) { + toClose.addLast(value) + } + + override fun close() { + close(null) + } + + @PublishedApi + internal fun close(baseException: Throwable?) { + var exception = baseException + + while (true) { + var toClose = toClose.removeLastOrNull() ?: break + try { + toClose.close() + } catch (e: Throwable) { + if (exception == null) { + exception = e + } else { + exception.addSuppressed(e) + } + } + } + + if (exception != null) throw exception + } + + inline fun use(block: (CloseScope) -> R): R { + var exception: Throwable? = null + try { + return block(this) + } catch (e: Throwable) { + exception = e + throw e + } finally { + close(exception) + } + } +} + +/** Proxy method to avoid overload ambiguity. */ +fun Property.setProvider(provider: Provider) = set(provider) + +/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */ +fun Provider.getAbsolutePath(): String = get().asFile.absolutePath + +/** + * Get the version immediately after the provided version. + * + * For example, given "1.2.3", this will return "1.2.4". + */ +fun getNextVersion(version: String): String { + // Split a version like x.y.z-SNAPSHOT into x.y.z and -SNAPSHOT + val dashIndex = version.indexOf('-') + val mainVersion = if (dashIndex < 0) version else version.substring(0, dashIndex) + + // Find the last component in x.y.z and increment it. + val lastIndex = mainVersion.lastIndexOf('.') + if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"") + val lastVersion = try { + version.substring(lastIndex + 1).toInt() + } catch (e: NumberFormatException) { + throw IllegalArgumentException("Cannot parse version format \"$version\"", e) + } + + // Then append all components together. + val out = StringBuilder() + out.append(version, 0, lastIndex + 1) + out.append(lastVersion + 1) + if (dashIndex >= 0) out.append(version, dashIndex, version.length) + return out.toString() +} diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/ForgeExtensions.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/ForgeExtensions.kt new file mode 100644 index 000000000..bbf6e86c5 --- /dev/null +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/ForgeExtensions.kt @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package cc.tweaked.gradle + +import net.minecraftforge.gradle.common.util.RunConfig +import net.minecraftforge.gradle.common.util.runs.setRunConfigInternal +import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.tasks.JavaExec +import org.gradle.jvm.toolchain.JavaToolchainService +import java.nio.file.Files + +/** + * Set [JavaExec] task to run a given [RunConfig]. + */ +fun JavaExec.setRunConfig(config: RunConfig) { + dependsOn("prepareRuns") + setRunConfigInternal(project, this, config) + doFirst("Create working directory") { Files.createDirectories(workingDir.toPath()) } + + javaLauncher.set( + project.extensions.getByType(JavaToolchainService::class.java) + .launcherFor(project.extensions.getByType(JavaPluginExtension::class.java).toolchain), + ) +} diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt new file mode 100644 index 000000000..daf382ab0 --- /dev/null +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt @@ -0,0 +1,215 @@ +// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package cc.tweaked.gradle + +import net.minecraftforge.gradle.common.util.RunConfig +import org.gradle.api.GradleException +import org.gradle.api.file.FileSystemOperations +import org.gradle.api.invocation.Gradle +import org.gradle.api.provider.Provider +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.api.tasks.* +import org.gradle.kotlin.dsl.getByName +import org.gradle.language.base.plugins.LifecycleBasePlugin +import java.io.File +import java.nio.file.Files +import java.util.concurrent.TimeUnit +import java.util.function.Supplier +import javax.inject.Inject +import kotlin.random.Random + +/** + * A [JavaExec] task for client-tests. This sets some common setup, and uses [MinecraftRunnerService] to ensure only one + * test runs at once. + */ +abstract class ClientJavaExec : JavaExec() { + private val clientRunner: Provider = MinecraftRunnerService.get(project.gradle) + + init { + group = LifecycleBasePlugin.VERIFICATION_GROUP + usesService(clientRunner) + } + + @get:Input + val renderdoc get() = project.hasProperty("renderdoc") + + /** + * When [false], tests will not be run automatically, allowing the user to debug rendering. + */ + @get:Input + val clientDebug get() = renderdoc || project.hasProperty("clientDebug") + + /** + * When [false], tests will not run under a framebuffer. + */ + @get:Input + val useFramebuffer get() = !clientDebug && !project.hasProperty("clientNoFramebuffer") + + /** + * The path test results are written to. + */ + @get:OutputFile + val testResults = project.layout.buildDirectory.file("test-results/$name.xml") + + private fun setTestProperties() { + if (!clientDebug) systemProperty("advancedperipheralstest.client", "") + if (renderdoc) environment("LD_PRELOAD", "/usr/lib/librenderdoc.so") + systemProperty("advancedperipheralstest.gametest-report", testResults.get().asFile.absoluteFile) + workingDir(project.layout.buildDirectory.dir("gametest/$name")) + } + + init { + setTestProperties() + } + + /** + * Set this task to run a given [RunConfig]. + */ + fun setRunConfig(config: RunConfig) { + (this as JavaExec).setRunConfig(config) + setTestProperties() // setRunConfig may clobber some properties, ensure everything is set. + } + + /** + * Copy configuration from a task with the given name. + */ + fun copyFrom(path: String) = copyFrom(project.tasks.getByName(path, JavaExec::class)) + + /** + * Copy configuration from an existing [JavaExec] task. + */ + fun copyFrom(task: JavaExec) { + for (dep in task.dependsOn) dependsOn(dep) + task.copyToFull(this) + setTestProperties() // copyToFull may clobber some properties, ensure everything is set. + } + + /** + * Only run tests with the given tags. + */ + fun tags(vararg tags: String) { + systemProperty("advancedperipheralstest.tags", tags.joinToString(",")) + } + + /** + * Write a file with the given contents before starting Minecraft. This may be useful for writing config files. + */ + fun withFileContents(path: Any, contents: Supplier) { + val file = project.file(path).toPath() + doFirst { + Files.createDirectories(file.parent) + Files.writeString(file, contents.get()) + } + } + + /** + * Copy a file to the provided path before starting Minecraft. This copy only occurs if the file does not already + * exist. + */ + fun withFileFrom(path: Any, source: Supplier) { + val file = project.file(path).toPath() + doFirst { + Files.createDirectories(file.parent) + if (!Files.exists(file)) Files.copy(source.get().toPath(), file) + } + } + + @TaskAction + override fun exec() { + Files.createDirectories(workingDir.toPath()) + fsOperations.delete { delete(workingDir.resolve("screenshots")) } + + if (useFramebuffer) { + clientRunner.get().wrapClient(this) { super.exec() } + } else { + super.exec() + } + } + + @get:Inject + protected abstract val fsOperations: FileSystemOperations +} + +/** + * A service for [JavaExec] tasks which start Minecraft. + * + * Tasks may run `usesService(MinecraftRunnerService.get(gradle))` to ensure that only one Minecraft-related task runs + * at once. + */ +abstract class MinecraftRunnerService : BuildService { + private val hasXvfb = lazy { + System.getProperty("os.name", "").equals("linux", ignoreCase = true) && ProcessHelpers.onPath("xvfb-run") + } + + internal fun wrapClient(exec: JavaExec, run: () -> Unit) = when { + hasXvfb.value -> runXvfb(exec, run) + else -> run() + } + + /** + * Run a program under Xvfb, preventing it spawning a window. + */ + private fun runXvfb(exec: JavaExec, run: () -> Unit) { + fun ProcessBuilder.startVerbose(): Process { + exec.logger.info("Running ${this.command()}") + return start() + } + + CloseScope().use { scope -> + val dir = Files.createTempDirectory("cctweaked").toAbsolutePath() + scope.add { fsOperations.delete { delete(dir) } } + + val authFile = Files.createTempFile(dir, "Xauthority", "").toAbsolutePath() + + val cookie = StringBuilder().also { + for (i in 0..31) it.append("0123456789abcdef"[Random.nextInt(16)]) + }.toString() + + val xvfb = + ProcessBuilder("Xvfb", "-displayfd", "1", "-screen", "0", "640x480x24", "-nolisten", "tcp").also { + it.inheritIO() + it.environment()["XAUTHORITY"] = authFile.toString() + it.redirectOutput(ProcessBuilder.Redirect.PIPE) + }.startVerbose() + scope.add { xvfb.destroyForcibly().waitFor() } + + val server = xvfb.inputReader().use { it.readLine().trim() } + exec.logger.info("Running at :$server (XAUTHORITY=$authFile.toA") + + ProcessBuilder("xauth", "add", ":$server", ".", cookie).also { + it.inheritIO() + it.environment()["XAUTHORITY"] = authFile.toString() + }.startVerbose().waitForOrThrow("Failed to setup XAuthority file") + + scope.add { + ProcessBuilder("xauth", "remove", ":$server").also { + it.inheritIO() + it.environment()["XAUTHORITY"] = authFile.toString() + }.startVerbose().waitFor() + } + + // Wait a few seconds for Xvfb to start. Ugly, but identical to xvfb-run. + if (xvfb.waitFor(3, TimeUnit.SECONDS)) { + throw GradleException("Xvfb unexpectedly exited (with status code ${xvfb.exitValue()})") + } + + exec.environment("XAUTHORITY", authFile.toString()) + exec.environment("DISPLAY", ":$server") + + run() + } + } + + @get:Inject + protected abstract val fsOperations: FileSystemOperations + + companion object { + fun get(gradle: Gradle): Provider = + gradle.sharedServices.registerIfAbsent("cc.tweaked.gradle.ClientJavaExec", MinecraftRunnerService::class.java) { + maxParallelUsages.set(1) + } + } +} diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/ProcessHelpers.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/ProcessHelpers.kt new file mode 100644 index 000000000..2fdb2a650 --- /dev/null +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/ProcessHelpers.kt @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package cc.tweaked.gradle + +import org.codehaus.groovy.runtime.ProcessGroovyMethods +import org.gradle.api.GradleException +import java.io.BufferedReader +import java.io.File +import java.io.InputStreamReader +import java.nio.charset.StandardCharsets + +internal object ProcessHelpers { + fun startProcess(vararg command: String): Process { + // Something randomly passes in "GIT_DIR=" as an environment variable which clobbers everything else. Don't + // inherit the environment array! + return ProcessBuilder() + .command(*command) + .redirectError(ProcessBuilder.Redirect.INHERIT) + .also { it.environment().clear() } + .start() + } + + fun captureOut(vararg command: String): String { + val process = startProcess(*command) + process.outputStream.close() + + val result = ProcessGroovyMethods.getText(process) + process.waitForOrThrow("Failed to run command") + return result + } + + fun captureLines(vararg command: String): List { + val process = startProcess(*command) + process.outputStream.close() + + val out = BufferedReader(InputStreamReader(process.inputStream, StandardCharsets.UTF_8)).use { reader -> + reader.lines().filter { it.isNotEmpty() }.toList() + } + ProcessGroovyMethods.closeStreams(process) + process.waitForOrThrow("Failed to run command") + return out + } + + fun onPath(name: String): Boolean { + val path = System.getenv("PATH") ?: return false + return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() } + } + + /** + * Search for an executable on the `PATH` if required. + * + * [Process]/[ProcessBuilder] does not handle all executable file extensions on Windows (such as `.com). When on + * Windows, this function searches `PATH` and `PATHEXT` for an executable matching [name]. + */ + fun getExecutable(name: String): String { + if (!System.getProperty("os.name").lowercase().contains("windows")) return name + + val path = (System.getenv("PATH") ?: return name).split(File.pathSeparator) + val pathExt = (System.getenv("PATHEXT") ?: return name).split(File.pathSeparator) + + for (pathEntry in path) { + for (ext in pathExt) { + val resolved = File(pathEntry, name + ext) + if (resolved.exists()) return resolved.getAbsolutePath() + } + } + + return name + } +} + +internal fun Process.waitForOrThrow(message: String) { + val ret = waitFor() + if (ret != 0) throw GradleException("$message (exited with $ret)") +} diff --git a/buildSrc/src/main/kotlin/net/minecraftforge/gradle/common/util/runs/RunConfigSetup.kt b/buildSrc/src/main/kotlin/net/minecraftforge/gradle/common/util/runs/RunConfigSetup.kt new file mode 100644 index 000000000..3494c5358 --- /dev/null +++ b/buildSrc/src/main/kotlin/net/minecraftforge/gradle/common/util/runs/RunConfigSetup.kt @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package net.minecraftforge.gradle.common.util.runs + +import net.minecraftforge.gradle.common.util.RunConfig +import org.gradle.api.Project +import org.gradle.process.CommandLineArgumentProvider +import org.gradle.process.JavaExecSpec +import java.io.File + +/** + * Set up a [JavaExecSpec] to execute a [RunConfig]. + * + * [MinecraftRunTask] sets up all its properties when the task is executed, rather than when configured. As such, it's + * not possible to use [cc.tweaked.gradle.copyToFull] like we do for Fabric. Instead, we set up the task manually. + * + * Unfortunately most of the functionality we need is package-private, and so we have to put our code into the package. + */ +internal fun setRunConfigInternal(project: Project, spec: JavaExecSpec, config: RunConfig) { + spec.workingDir = File(config.workingDirectory) + + spec.mainClass.set(config.main) + for (source in config.allSources) spec.classpath(source.runtimeClasspath) + + val originalTask = project.tasks.named(config.taskName, MinecraftRunTask::class.java) + + // Add argument and JVM argument via providers, to be as lazy as possible with fetching artifacts. + val lazyTokens = RunConfigGenerator.configureTokensLazy( + project, config, RunConfigGenerator.mapModClassesToGradle(project, config), + originalTask.get().minecraftArtifacts, + originalTask.get().runtimeClasspathArtifacts, + ) + spec.argumentProviders.add( + CommandLineArgumentProvider { + RunConfigGenerator.getArgsStream(config, lazyTokens, false).toList() + }, + ) + spec.jvmArgumentProviders.add( + CommandLineArgumentProvider { + (if (config.isClient) config.jvmArgs + originalTask.get().additionalClientArgs.get() else config.jvmArgs).map { config.replace(lazyTokens, it) } + + config.properties.map { (k, v) -> "-D${k}=${config.replace(lazyTokens, v)}" } + }, + ) + + for ((key, value) in config.environment) spec.environment(key, config.replace(lazyTokens, value)) +} diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt index e986197ee..5a2384351 100644 --- a/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt @@ -81,7 +81,7 @@ object ClientTestHooks { if (minecraft.levelSource.levelExists(LEVEL_NAME)) { LOG.info("World already exists, opening.") - minecraft.createWorldOpenFlows().loadLevel(minecraft.screen, LEVEL_NAME) + minecraft.createWorldOpenFlows().loadLevel(minecraft.screen!!, LEVEL_NAME) } else { LOG.info("World does not exist, creating it.") val rules = GameRules() From 6227fd68b4c44e83a6b9632220205e60fece16b4 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sun, 2 Jun 2024 01:41:44 +0200 Subject: [PATCH 49/61] Add docs on client tests --- docs/CREATING_TESTS.MD | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/CREATING_TESTS.MD b/docs/CREATING_TESTS.MD index 5d771e476..15a348581 100644 --- a/docs/CREATING_TESTS.MD +++ b/docs/CREATING_TESTS.MD @@ -9,7 +9,7 @@ To write a test, you need to have a test world. But this needs to be done in the To run the testing environment, run the gradle task `runTestClient`. This will start a new instance of Minecraft with the testing environment. That includes the ability to run tests, import and export tests using the `/cctest` and the `/test` command. -After the tests are created, you can use the gradle task `runTestServer` to start the game test server which then runs all the test. +After the tests are created, you can use the gradle task `runGameTestServer` to start the game test server which then runs all the test. To test a single test, you can also use `/test run ` in the testing environment. ### Building your test structure @@ -120,4 +120,14 @@ Here is an example with our note block test } ``` +### Client Tests + +Similar to the common game tests described above, you can also write tests that will be executed on the client. +To define a client test, use the annotation `@ClientGameTest` instead of `@GameTest`. The rest of the process is the same. +In the test function, you can then use `thenOnClient { ... }` to run code on the client. + +To run the client tests automatically, use the gradle task `runGameTestClient`. + +--- + For more examples, you can also check how the tests from CC work [here](https://github.com/cc-tweaked/CC-Tweaked/tree/mc-1.19.2/src/testMod/kotlin/dan200/computercraft/gametest). \ No newline at end of file From 2a805bd5847082be34d61e34f620a1d4084a0ca4 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Mon, 3 Jun 2024 12:19:34 +0200 Subject: [PATCH 50/61] Added client test for the Chat Box peripheral --- build.gradle | 1 + .../gametest/core/ClientTestEvents.java | 21 +++ .../test/APClientTestExtensions.kt | 33 ++++ .../advancedperipherals/test/ChatBoxTest.kt | 161 ++++++++++++++++++ .../test/ComponentFormattedCharSink.kt | 44 +++++ .../resources/META-INF/accesstransformer.cfg | 6 +- .../computer/tests/chatboxtest.chatbox.lua | 97 +++++++++++ .../structures/chatboxtest.chatbox.snbt | 138 +++++++++++++++ 8 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 src/testMod/java/dan200/computercraft/gametest/core/ClientTestEvents.java create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/APClientTestExtensions.kt create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/ComponentFormattedCharSink.kt create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt diff --git a/build.gradle b/build.gradle index a24ec0d47..49a464dab 100644 --- a/build.gradle +++ b/build.gradle @@ -171,6 +171,7 @@ minecraft { property 'forge.logging.console.level', 'debug' property 'forge.enabledGameTestNamespaces', 'advancedperipherals,advancedperipheralstest' property 'advancedperipheralstest.sources', file("src/testMod/resources/data/advancedperipheralstest").absolutePath + property 'advancedperipheralstest.tags', 'common,client' args "--mixin.config=ccgametest.mixins.json" args "--mixin.config=advancedperipheralstest.mixins.json" diff --git a/src/testMod/java/dan200/computercraft/gametest/core/ClientTestEvents.java b/src/testMod/java/dan200/computercraft/gametest/core/ClientTestEvents.java new file mode 100644 index 000000000..9956894b9 --- /dev/null +++ b/src/testMod/java/dan200/computercraft/gametest/core/ClientTestEvents.java @@ -0,0 +1,21 @@ +package dan200.computercraft.gametest.core; + +import com.google.common.collect.Lists; +import net.minecraft.client.gui.components.toasts.Toast; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ToastAddEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.List; + +@Mod.EventBusSubscriber(modid = TestMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) +public class ClientTestEvents { + public static final List toasts = Lists.newArrayList(); + + @SubscribeEvent + public static void onToast(ToastAddEvent event) { + toasts.add(event.getToast()); + } + +} diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/APClientTestExtensions.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/APClientTestExtensions.kt new file mode 100644 index 000000000..985c59db5 --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/APClientTestExtensions.kt @@ -0,0 +1,33 @@ +package de.srendi.advancedperipherals.test + +import net.minecraft.client.Minecraft +import net.minecraft.gametest.framework.GameTestAssertException +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.network.chat.Component +import java.util.function.Predicate + +fun GameTestHelper.chatContains(filter: Predicate) = Minecraft.getInstance().gui.chat.allMessages.any { filter.test(it.content) } + +fun GameTestHelper.assertChatContains(component: Component) { + if (!chatContains { it == component }) { + throw GameTestAssertException("Expected chat to contain $component") + } +} + +fun GameTestHelper.assertChatContains(filter: Predicate) { + if (!chatContains(filter)) { + throw GameTestAssertException("Expected chat to contain message matching filter") + } +} + +fun GameTestHelper.assertChatNotContains(component: Component) { + if (chatContains { it == component }) { + throw GameTestAssertException("Expected chat to not contain $component") + } +} + +fun GameTestHelper.assertChatNotContains(filter: Predicate) { + if (chatContains(filter)) { + throw GameTestAssertException("Expected chat to not contain message matching filter") + } +} \ No newline at end of file diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt new file mode 100644 index 000000000..b112647f1 --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt @@ -0,0 +1,161 @@ +package de.srendi.advancedperipherals.test + +import dan200.computercraft.gametest.api.* +import dan200.computercraft.gametest.api.Timeouts.SECOND +import dan200.computercraft.gametest.core.ClientTestEvents +import net.minecraft.ChatFormatting +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.components.toasts.SystemToast +import net.minecraft.core.BlockPos +import net.minecraft.gametest.framework.GameTestHelper +import net.minecraft.network.chat.ClickEvent +import net.minecraft.network.chat.Component +import java.util.function.BiPredicate + +@GameTestHolder +class ChatBoxTest { + + private fun getFormattedMessage(bracketColor: String, openBracket: Char, closeBracket: Char, prefix: String, message: String): Component { + return Component.literal("$bracketColor$openBracket§r") + .append(prefix) + .append("$bracketColor$closeBracket§r ") + .append( + Component.literal("Red ").withStyle(ChatFormatting.RED) + .append(Component.literal("Bold ").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.WHITE)) + .append(Component.literal("Click ").withStyle(ChatFormatting.UNDERLINE).withStyle(ChatFormatting.WHITE) + .withStyle { it.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, "https://advancedperipherals.madefor.cc/")) }) + .append(Component.literal(message).withStyle(ChatFormatting.ITALIC).withStyle(ChatFormatting.AQUA)) + ) + } + + private fun getFormattedToast(bracketColor: ChatFormatting?, openBracket: Char, closeBracket: Char, prefix: String, message: String): List { + val prefixComponents = if (bracketColor != null) { + listOf( + Component.literal("$openBracket").withStyle(bracketColor), + Component.literal(prefix), + Component.literal("$closeBracket").withStyle(bracketColor), + Component.literal(" ") + ) + } else { + listOf( + Component.literal("$openBracket$prefix$closeBracket ") + ) + } + + return prefixComponents + listOf( + Component.literal("Red ").withStyle(ChatFormatting.RED), + Component.literal("Bold ").withStyle(ChatFormatting.WHITE).withStyle(ChatFormatting.BOLD), + Component.literal("Click ").withStyle(ChatFormatting.WHITE).withStyle(ChatFormatting.UNDERLINE) + .withStyle { it.withClickEvent(ClickEvent(ClickEvent.Action.OPEN_URL, "https://advancedperipherals.madefor.cc/")) }, + Component.literal(message).withStyle(ChatFormatting.AQUA).withStyle(ChatFormatting.ITALIC) + ) + } + + private fun containsToast(filter: BiPredicate>): Boolean { + return ClientTestEvents.toasts.filterIsInstance().any { + val sink = ComponentFormattedCharSink() + it.messageLines.forEachIndexed { index, line -> + line.accept(sink) + if (index < it.messageLines.size - 1) { + sink.accept(0, sink.currentStyle!!, ' '.code) + } + } + + filter.test(it.title, sink.getComponents()) + } + } + + private fun assertContainsToast(title: Component, components: List) { + if (!containsToast { toastTitle, toastComponents -> toastTitle == title && toastComponents == components }) { + throw AssertionError("Toast with title $title and components $components not found") + } + } + + private fun assertNotContainsToast(title: Component, components: List) { + if (containsToast { toastTitle, toastComponents -> toastTitle == title && toastComponents == components }) { + throw AssertionError("Toast with title $title and components $components found") + } + } + + private fun assertNotContainsToast(filter: BiPredicate>) { + if (containsToast(filter)) { + throw AssertionError("Toast matching filter found") + } + } + + @ClientGameTest(timeoutTicks = 60 * SECOND) + fun chatBox(context: GameTestHelper) = context.sequence { + thenExecute { context.positionAt(BlockPos(2, 6, 2), 90f) } + thenOnClient { + Minecraft.getInstance().gui.chat.clearMessages(false) + ClientTestEvents.toasts.clear() + } + thenComputerOk() + thenOnClient { + // sendMessage + context.assertChatContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message")) + context.assertChatContains(Component.literal("[§r").append("GameTest").append("]§r ").append("Message with prefix")) + context.assertChatContains(Component.literal("<§r").append("GameTest").append(">§r ").append("Message with brackets")) + context.assertChatContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with bracket color")) + context.assertChatNotContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with short range")) + context.assertChatNotContains { it.toString().contains("Message with invalid brackets") } + + // sendMessageToPlayer + context.assertChatContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message to player")) + context.assertChatContains(Component.literal("[§r").append("GameTest").append("]§r ").append("Message with prefix to player")) + context.assertChatContains(Component.literal("<§r").append("GameTest").append(">§r ").append("Message with brackets to player")) + context.assertChatContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with bracket color to player")) + context.assertChatNotContains(Component.literal("§a<§r").append("GameTest").append("§a>§r ").append("Message with short range to player")) + context.assertChatNotContains { it.toString().contains("Message with invalid brackets to player") } + context.assertChatNotContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message to invalid player")) + + // sendFormattedMessage + context.assertChatContains(getFormattedMessage("", '[', ']', "AP", "Default formatted message")) + context.assertChatContains(getFormattedMessage("", '[', ']', "GameTest", "Formatted message with prefix")) + context.assertChatContains(getFormattedMessage("", '<', '>', "GameTest", "Formatted message with brackets")) + context.assertChatContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with bracket color")) + context.assertChatNotContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with short range")) + context.assertChatNotContains { it.toString().contains("Formatted message with invalid brackets") } + + // sendFormattedMessageToPlayer + context.assertChatContains(getFormattedMessage("", '[', ']', "AP", "Default formatted message to player")) + context.assertChatContains(getFormattedMessage("", '[', ']', "GameTest", "Formatted message with prefix to player")) + context.assertChatContains(getFormattedMessage("", '<', '>', "GameTest", "Formatted message with brackets to player")) + context.assertChatContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with bracket color to player")) + context.assertChatNotContains(getFormattedMessage("§a", '<', '>', "GameTest", "Formatted message with short range to player")) + context.assertChatNotContains { it.toString().contains("Formatted message with invalid brackets to player") } + context.assertChatNotContains(getFormattedMessage("", '[', ']', "AP", "Default formatted message to invalid player")) + + // sendToastToPlayer + val defaultToastTitle = Component.literal("Toast Title") + assertContainsToast(defaultToastTitle, listOf(Component.literal("[AP] Default toast to player"))) + assertContainsToast(defaultToastTitle, listOf(Component.literal("[GameTest] Toast with prefix to player"))) + assertContainsToast(defaultToastTitle, listOf(Component.literal(" Toast with brackets to player"))) + assertContainsToast(defaultToastTitle, listOf( + Component.literal("<").withStyle(ChatFormatting.GREEN), + Component.literal("GameTest"), + Component.literal(">").withStyle(ChatFormatting.GREEN), + Component.literal(" Toast with bracket color to player") + )) + assertNotContainsToast(defaultToastTitle, listOf( + Component.literal("<").withStyle(ChatFormatting.GREEN), + Component.literal("GameTest"), + Component.literal(">").withStyle(ChatFormatting.GREEN), + Component.literal(" Toast with short range to player") + )) + assertNotContainsToast { title, components -> title == defaultToastTitle && components.any { it.toString().contains("Toast with invalid brackets to player") } } + assertNotContainsToast(defaultToastTitle, listOf(Component.literal("[AP] Default toast to invalid player"))) + + // sendFormattedToastToPlayer + val formattedToastTitle = Component.literal("Formatted Toast Title").withStyle(ChatFormatting.DARK_PURPLE) + assertContainsToast(formattedToastTitle, getFormattedToast(null, '[', ']', "AP", "Default formatted toast to player")) + assertContainsToast(formattedToastTitle, getFormattedToast(null, '[', ']', "GameTest", "Formatted toast with prefix to player")) + assertContainsToast(formattedToastTitle, getFormattedToast(null, '<', '>', "GameTest", "Formatted toast with brackets to player")) + assertContainsToast(formattedToastTitle, getFormattedToast(ChatFormatting.GREEN, '<', '>', "GameTest", "Formatted toast with bracket color to player")) + assertNotContainsToast(formattedToastTitle, getFormattedToast(ChatFormatting.GREEN, '<', '>', "GameTest", "Formatted toast with short range to player")) + assertNotContainsToast { title, components -> title == formattedToastTitle && components.any { it.toString().contains("Formatted toast with invalid brackets to player") } } + assertNotContainsToast(formattedToastTitle, getFormattedToast(null, '[', ']', "AP", "Default formatted toast to invalid player")) + } + } + +} \ No newline at end of file diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ComponentFormattedCharSink.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ComponentFormattedCharSink.kt new file mode 100644 index 000000000..bc62f38b9 --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ComponentFormattedCharSink.kt @@ -0,0 +1,44 @@ +package de.srendi.advancedperipherals.test + +import net.minecraft.network.chat.Component +import net.minecraft.network.chat.Style +import net.minecraft.util.FormattedCharSink + +class ComponentFormattedCharSink : FormattedCharSink { + var currentStyle: Style? = null; + private var currentText: String = ""; + private val components = mutableListOf(); + + override fun accept(pPositionInCurrentSequence: Int, pStyle: Style, pCodePoint: Int): Boolean { + if (currentStyle?.equals(pStyle) == false) { + if (currentText.isNotEmpty()) { + components.add(Component.literal(currentText).withStyle(simplifyStyle(currentStyle!!))) + currentText = "" + } + } + + currentStyle = pStyle + currentText += String(Character.toChars(pCodePoint)) + + return true + } + + fun getComponents(): List{ + if (currentText.isNotEmpty()) { + components.add(Component.literal(currentText).withStyle(simplifyStyle(currentStyle!!))) + currentText = "" + } + + return components + } + + private fun simplifyStyle(style: Style): Style { + return style + .withBold(if (style.isBold) true else null) + .withItalic(if (style.isItalic) true else null) + .withUnderlined(if (style.isUnderlined) true else null) + .withStrikethrough(if (style.isStrikethrough) true else null) + .withObfuscated(if (style.isObfuscated) true else null) + } + +} \ No newline at end of file diff --git a/src/testMod/resources/META-INF/accesstransformer.cfg b/src/testMod/resources/META-INF/accesstransformer.cfg index 8fcc2e072..a8570dd52 100644 --- a/src/testMod/resources/META-INF/accesstransformer.cfg +++ b/src/testMod/resources/META-INF/accesstransformer.cfg @@ -4,4 +4,8 @@ public net.minecraft.gametest.framework.GameTestHelper m_177448_()Lnet/minecraft public net.minecraft.gametest.framework.GameTestHelper f_127595_ # testInfo public net.minecraft.gametest.framework.GameTestSequence f_127774_ # parent -public net.minecraft.gametest.framework.MultipleTestTracker f_127798_ # tests \ No newline at end of file +public net.minecraft.gametest.framework.MultipleTestTracker f_127798_ # tests + +public net.minecraft.client.gui.components.ChatComponent f_93760_ # allMessages +public net.minecraft.client.gui.components.toasts.SystemToast f_94821_ # title +public net.minecraft.client.gui.components.toasts.SystemToast f_94822_ # messageLines \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua new file mode 100644 index 000000000..6ed39caf7 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua @@ -0,0 +1,97 @@ +--- +--- Advanced Peripherals Chat Box tests +--- Covers `sendMessage`, `sendMessageToPlayer`, `sendToastToPlayer`, `sendFormattedToastToPlayer`, +--- `sendFormattedMessage`, `sendFormattedMessageToPlayer` +--- + +sleep(3) + +chatBox = peripheral.find("chatBox") +test.assert(chatBox, "Peripheral not found") +config = chatBox.getConfiguration() + +function assertCooldown() + local currentCooldown = chatBox.getOperationCooldown("chatMessage") + test.assert(currentCooldown > 0 and currentCooldown <= config["chatMessage"]["cooldown"], "Cooldown should be active after a message was sent") + + while chatBox.getOperationCooldown("chatMessage") > 0 do + sleep(0.1) + end +end + +function assertSendMessage(fn, ...) + local message = arg[1] + test.assert(fn(unpack(arg)), message .. " should be sent") + assertCooldown() +end + +function assertFailedSendMessage(fn, ...) + local message = arg[1] + test.assert(not fn(unpack(arg)), message .. " should not be sent") + -- test.eq(0, chatBox.getOperationCooldown("chatMessage"), "Cooldown should not be active after a failed message") failed messages still trigger cooldown, maybe a bug? + assertCooldown() -- TODO Remove when fixed +end + +function getFormattedMessage(message) + local message = { + { text = "Red ", color = "red" }, + { text = "Bold ", color = "white", bold = true }, + { text = "Click ", underlined = true, color = "white", clickEvent = { action = "open_url", value = "https://advancedperipherals.madefor.cc/" } }, + { text = message, color = "aqua", italic = true } + } + local json = textutils.serialiseJSON(message) + return json +end + +-- Test sendMessage in different formats +assertSendMessage(chatBox.sendMessage, "Default message") +assertSendMessage(chatBox.sendMessage, "Message with prefix", "GameTest") +assertSendMessage(chatBox.sendMessage, "Message with brackets", "GameTest", "<>") +assertSendMessage(chatBox.sendMessage, "Message with bracket color", "GameTest", "<>", "&a") +assertSendMessage(chatBox.sendMessage, "Message with short range", "GameTest", "<>", "&a", 3) +assertFailedSendMessage(chatBox.sendMessage, "Message with invalid brackets", "GameTest", "<") + +-- Test sendMessageToPlayer in different formats +assertSendMessage(chatBox.sendMessageToPlayer, "Default message to player", "Dev") +assertSendMessage(chatBox.sendMessageToPlayer, "Message with prefix to player", "Dev", "GameTest") +assertSendMessage(chatBox.sendMessageToPlayer, "Message with brackets to player", "Dev", "GameTest", "<>") +assertSendMessage(chatBox.sendMessageToPlayer, "Message with bracket color to player", "Dev", "GameTest", "<>", "&a") +assertSendMessage(chatBox.sendMessageToPlayer, "Message with short range to player", "Dev", "GameTest", "<>", "&a", 3) +assertFailedSendMessage(chatBox.sendMessageToPlayer, "Message with invalid brackets to player", "Dev", "GameTest", "<") +assertFailedSendMessage(chatBox.sendMessageToPlayer, "Default message to invalid player", "InvalidPlayer") + +-- Test sendFormattedMessage in different formats +assertSendMessage(chatBox.sendFormattedMessage, getFormattedMessage("Default formatted message")) +assertSendMessage(chatBox.sendFormattedMessage, getFormattedMessage("Formatted message with prefix"), "GameTest") +assertSendMessage(chatBox.sendFormattedMessage, getFormattedMessage("Formatted message with brackets"), "GameTest", "<>") +assertSendMessage(chatBox.sendFormattedMessage, getFormattedMessage("Formatted message with bracket color"), "GameTest", "<>", "&a") +assertSendMessage(chatBox.sendFormattedMessage, getFormattedMessage("Formatted message with short range"), "GameTest", "<>", "&a", 3) +assertFailedSendMessage(chatBox.sendFormattedMessage, getFormattedMessage("Formatted message with invalid brackets"), "GameTest", "<") + +-- Test sendFormattedMessageToPlayer in different formats +assertSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Default formatted message to player"), "Dev") +assertSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Formatted message with prefix to player"), "Dev", "GameTest") +assertSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Formatted message with brackets to player"), "Dev", "GameTest", "<>") +assertSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Formatted message with bracket color to player"), "Dev", "GameTest", "<>", "&a") +assertSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Formatted message with short range to player"), "Dev", "GameTest", "<>", "&a", 3) +assertFailedSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Formatted message with invalid brackets to player"), "Dev", "GameTest", "<") +assertFailedSendMessage(chatBox.sendFormattedMessageToPlayer, getFormattedMessage("Default formatted message to invalid player"), "InvalidPlayer") + +-- Test sendToastToPlayer in different formats +assertSendMessage(chatBox.sendToastToPlayer, "Default toast to player", "Toast Title", "Dev") +assertSendMessage(chatBox.sendToastToPlayer, "Toast with prefix to player", "Toast Title", "Dev", "GameTest") +assertSendMessage(chatBox.sendToastToPlayer, "Toast with brackets to player", "Toast Title", "Dev", "GameTest", "<>") +assertSendMessage(chatBox.sendToastToPlayer, "Toast with bracket color to player", "Toast Title", "Dev", "GameTest", "<>", "&a") +assertSendMessage(chatBox.sendToastToPlayer, "Toast with short range to player", "Toast Title", "Dev", "GameTest", "<>", "&a", 3) +assertFailedSendMessage(chatBox.sendToastToPlayer, "Toast with invalid brackets to player", "Toast Title", "Dev", "GameTest", "<") +assertFailedSendMessage(chatBox.sendToastToPlayer, "Default toast to invalid player", "Toast Title", "InvalidPlayer") + +-- Test sendFormattedToastToPlayer in different formats +formattedToastTitle = textutils.serialiseJSON({ { text = "Formatted Toast Title", color = "dark_purple" } }) +assertSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Default formatted toast to player"), formattedToastTitle, "Dev") +assertSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Formatted toast with prefix to player"), formattedToastTitle, "Dev", "GameTest") +assertSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Formatted toast with brackets to player"), formattedToastTitle, "Dev", "GameTest", "<>") +assertSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Formatted toast with bracket color to player"), formattedToastTitle, "Dev", "GameTest", "<>", "&a") +assertSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Formatted toast with short range to player"),formattedToastTitle, "Dev", "GameTest", "<>", "&a", 3) +assertFailedSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Formatted toast with invalid brackets to player"), formattedToastTitle, "Dev", "GameTest", "<") +assertFailedSendMessage(chatBox.sendFormattedToastToPlayer, getFormattedMessage("Default formatted toast to invalid player"), formattedToastTitle, "InvalidPlayer") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt new file mode 100644 index 000000000..b9dde7cfa --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "computercraft:computer_advanced{facing:west,state:on}", nbt: {ComputerId: 1, ForgeCaps: {}, Label: "chatboxtest.chatbox_events", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 2], state: "advancedperipherals:chat_box{orientation:west_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Chat Box]"}, Items: [], id: "advancedperipherals:chat_box", peripheralSettings: {cooldowns: {chatMessage: 1717353228235L}}}}, + {pos: [2, 1, 3], state: "computercraft:computer_advanced{facing:west,state:on}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "chatboxtest.chatbox", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:on}", + "advancedperipherals:chat_box{orientation:west_up}" + ] +} From fe249527f8ad04585af3714658b1615c9f3184d7 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 29 Jun 2024 18:59:38 +0200 Subject: [PATCH 51/61] Fix NPE on client test start with existing world --- .../dan200/computercraft/gametest/core/ClientTestHooks.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt b/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt index 5a2384351..505407067 100644 --- a/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt +++ b/src/testMod/kotlin/dan200/computercraft/gametest/core/ClientTestHooks.kt @@ -56,7 +56,7 @@ object ClientTestHooks { fun onOpenScreen(screen: Screen): Boolean = when { enabled && !loadedWorld && (screen is TitleScreen || screen is AccessibilityOptionsScreen) -> { loadedWorld = true - openWorld() + openWorld(screen) true } @@ -66,7 +66,7 @@ object ClientTestHooks { /** * Open or create our test world immediately on game launch. */ - private fun openWorld() { + private fun openWorld(screen: Screen) { val minecraft = Minecraft.getInstance() // Clear some options before we get any further. @@ -81,7 +81,7 @@ object ClientTestHooks { if (minecraft.levelSource.levelExists(LEVEL_NAME)) { LOG.info("World already exists, opening.") - minecraft.createWorldOpenFlows().loadLevel(minecraft.screen!!, LEVEL_NAME) + minecraft.createWorldOpenFlows().loadLevel(screen, LEVEL_NAME) } else { LOG.info("World does not exist, creating it.") val rules = GameRules() From e5b46ad62dc33c96e2525489268cbc81d26444c6 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 29 Jun 2024 19:32:43 +0200 Subject: [PATCH 52/61] Add Chat Box event test --- .../advancedperipherals/test/ChatBoxTest.kt | 11 ++ .../tests/chatboxtest.chatbox_events.lua | 19 +++ .../structures/chatboxtest.chatbox.snbt | 2 +- .../chatboxtest.chatbox_events.snbt | 138 ++++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox_events.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt index b112647f1..245063187 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ChatBoxTest.kt @@ -91,6 +91,7 @@ class ChatBoxTest { ClientTestEvents.toasts.clear() } thenComputerOk() + thenOnClient { // sendMessage context.assertChatContains(Component.literal("[§r").append("AP").append("]§r ").append("Default message")) @@ -158,4 +159,14 @@ class ChatBoxTest { } } + @ClientGameTest + fun chatBox_Events(context: GameTestHelper) = context.sequence { + thenIdle(20) + thenOnClient { Minecraft.getInstance().player!!.chatSigned("This is a normal chat message", null) } + thenIdle(20) + thenOnClient { Minecraft.getInstance().player!!.chatSigned("\$This is a hidden chat message", null) } + thenIdle(20) + thenComputerOk() + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua new file mode 100644 index 000000000..526b9b54a --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua @@ -0,0 +1,19 @@ +--- +--- Advanced Peripherals Chat Box tests +--- Covers `sendMessage`, `sendMessageToPlayer`, `sendToastToPlayer`, `sendFormattedToastToPlayer`, +--- `sendFormattedMessage`, `sendFormattedMessageToPlayer` +--- + +chatBox = peripheral.find("chatBox") +test.assert(chatBox, "Peripheral not found") + +function assertMessage(msg, hidden) + local event, username, message, uuid, isHidden = os.pullEvent("chat") + test.eq("chat", event, "Event should be 'chat'") + test.eq("Dev", username, "Username of sender should be 'Dev'") + test.eq(msg, message, "Message should be '" .. msg .. "'") + test.eq(hidden, isHidden, "Message should be " .. (hidden and "hidden" or "visible")) +end + +assertMessage("This is a normal chat message", false) +assertMessage("This is a hidden chat message", true) diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt index b9dde7cfa..017725869 100644 --- a/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt +++ b/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox.snbt @@ -38,7 +38,7 @@ {pos: [1, 1, 3], state: "minecraft:air"}, {pos: [1, 1, 4], state: "minecraft:air"}, {pos: [2, 1, 0], state: "minecraft:air"}, - {pos: [2, 1, 1], state: "computercraft:computer_advanced{facing:west,state:on}", nbt: {ComputerId: 1, ForgeCaps: {}, Label: "chatboxtest.chatbox_events", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 1], state: "minecraft:air"}, {pos: [2, 1, 2], state: "advancedperipherals:chat_box{orientation:west_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Chat Box]"}, Items: [], id: "advancedperipherals:chat_box", peripheralSettings: {cooldowns: {chatMessage: 1717353228235L}}}}, {pos: [2, 1, 3], state: "computercraft:computer_advanced{facing:west,state:on}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "chatboxtest.chatbox", On: 1b, id: "computercraft:computer_advanced"}}, {pos: [2, 1, 4], state: "minecraft:air"}, diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox_events.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox_events.snbt new file mode 100644 index 000000000..c3bc156f8 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/chatboxtest.chatbox_events.snbt @@ -0,0 +1,138 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "minecraft:air"}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "advancedperipherals:chat_box{orientation:west_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Chat Box]"}, Items: [], id: "advancedperipherals:chat_box", peripheralSettings: {cooldowns: {chatMessage: 1717353228235L}}}}, + {pos: [2, 1, 3], state: "computercraft:computer_advanced{facing:west,state:on}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "chatboxtest.chatbox_events", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "computercraft:computer_advanced{facing:west,state:on}", + "advancedperipherals:chat_box{orientation:west_up}" + ] +} From 4904f853c3397c2746a3240715fceb64478f10a3 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Sat, 29 Jun 2024 20:16:48 +0200 Subject: [PATCH 53/61] Fix runGameTestClient task also running common tests --- build.gradle | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 49a464dab..bae45dc20 100644 --- a/build.gradle +++ b/build.gradle @@ -184,6 +184,15 @@ minecraft { } } + // internal run config to automatically run the client-side gametests with the runGameTestClient task + runGameTestClientInternal { + parent runs.testClient + + lazyToken("minecraft_classpath", lazyTokens["minecraft_classpath"]) + + property 'advancedperipheralstest.tags', 'client' + } + gameTestServer { def oldClasspath = lazyTokens["minecraft_classpath"] lazyToken("minecraft_classpath") { @@ -669,6 +678,5 @@ publishing { tasks.register('runGameTestClient', ClientJavaExec, { task -> description "Runs client-side gametests with no mods" - setRunConfig(minecraft.runs["testClient"]) - tags("client") + setRunConfig(minecraft.runs.runGameTestClientInternal) }) From 83c79771b826e6cb092793b7b1340fb6a78c6859 Mon Sep 17 00:00:00 2001 From: Dogboy21 Date: Thu, 4 Jul 2024 22:17:13 +0200 Subject: [PATCH 54/61] Clean and fix runGameTestClient task --- build.gradle | 14 ++++---------- .../main/kotlin/cc/tweaked/gradle/MinecraftExec.kt | 7 ++++++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index bae45dc20..e7ce82319 100644 --- a/build.gradle +++ b/build.gradle @@ -184,15 +184,6 @@ minecraft { } } - // internal run config to automatically run the client-side gametests with the runGameTestClient task - runGameTestClientInternal { - parent runs.testClient - - lazyToken("minecraft_classpath", lazyTokens["minecraft_classpath"]) - - property 'advancedperipheralstest.tags', 'client' - } - gameTestServer { def oldClasspath = lazyTokens["minecraft_classpath"] lazyToken("minecraft_classpath") { @@ -677,6 +668,9 @@ publishing { } tasks.register('runGameTestClient', ClientJavaExec, { task -> + task.outputs.upToDateWhen { false } + description "Runs client-side gametests with no mods" - setRunConfig(minecraft.runs.runGameTestClientInternal) + setRunConfig(minecraft.runs.testClient) + tags("client") }) diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt index daf382ab0..4755f0274 100644 --- a/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftExec.kt @@ -14,6 +14,7 @@ import org.gradle.api.services.BuildServiceParameters import org.gradle.api.tasks.* import org.gradle.kotlin.dsl.getByName import org.gradle.language.base.plugins.LifecycleBasePlugin +import org.gradle.process.CommandLineArgumentProvider import java.io.File import java.nio.file.Files import java.util.concurrent.TimeUnit @@ -91,7 +92,11 @@ abstract class ClientJavaExec : JavaExec() { * Only run tests with the given tags. */ fun tags(vararg tags: String) { - systemProperty("advancedperipheralstest.tags", tags.joinToString(",")) + jvmArgumentProviders.add( + CommandLineArgumentProvider { + listOf("-Dadvancedperipheralstest.tags=${tags.joinToString(",")}") + } + ) } /** From 7bf7b7940efd66904dde944ed460440c5fc127cd Mon Sep 17 00:00:00 2001 From: endi Date: Sat, 31 Aug 2024 14:10:29 +0200 Subject: [PATCH 55/61] Energy Detector tests --- .../test/PeripheralTest.kt | 5 + .../tests/peripheraltest.energydet.lua | 22 +++ .../structures/peripheraltest.energydet.snbt | 144 ++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 928892033..264be4d2a 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -52,4 +52,9 @@ class PeripheralTest { thenComputerOk(); } + @GameTest + fun energyDet(context: GameTestHelper) = context.sequence { + thenComputerOk(); + } + } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua new file mode 100644 index 000000000..5839fcb57 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua @@ -0,0 +1,22 @@ +--- +--- Advanced Peripherals Energy Detector tests +--- Covers `getTransferRate`, `setTransferRateLimit`, `getTransferRateLimit` +--- + +test.eq("energyDetector", peripheral.getType("right"), "Peripheral should be energyDetector") + +det = peripheral.wrap("right") +det.setTransferRateLimit(0) +sleep(0.5) +test.eq(0, det.getTransferRate(), "Transfer Rate should be 0") +test.eq(0, det.getTransferRateLimit(), "Transfer Rate Limit should be 0") + +det.setTransferRateLimit(100) +sleep(0.5) +test.eq(100, det.getTransferRate(), "Transfer Rate should be 100") +test.eq(100, det.getTransferRateLimit(), "Transfer Rate Limit should be 100") + +det.setTransferRateLimit(100000) +sleep(0.5) +test.eq(3200, det.getTransferRate(), "Transfer Rate should be 3200") -- Rate limit from the cables +test.eq(100000, det.getTransferRateLimit(), "Transfer Rate Limit should be 100000") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt new file mode 100644 index 000000000..a7d9cca1b --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt @@ -0,0 +1,144 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "mekanism:creative_energy_cube{facing:north,fluid_logged:empty}", nbt: {EnergyContainers: [], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 1, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 0, id: "mekanism:creative_energy_cube", redstone: 0b}}, + {pos: [1, 1, 1], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, id: "mekanism:basic_universal_cable", redstone: 0b}}, + {pos: [1, 1, 2], state: "advancedperipherals:energy_detector{orientation:south_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Energy Detector]"}, Items: [], id: "advancedperipherals:energy_detector", rateLimit: 0}}, + {pos: [1, 1, 3], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, energy: "8000", id: "mekanism:basic_universal_cable", redstone: 0b}}, + {pos: [1, 1, 4], state: "mekanism:creative_energy_cube{facing:west,fluid_logged:empty}", nbt: {EnergyContainers: [{Container: 0b, stored: "18446744073709551615.9999"}], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 4, side1: 4, side2: 4, side3: 4, side4: 4, side5: 4}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 15, id: "mekanism:creative_energy_cube", redstone: 0b}}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.energydet", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "mekanism:creative_energy_cube{facing:east,fluid_logged:empty}", nbt: {EnergyContainers: [{Container: 0b, stored: "18446744073709551615.9999"}], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 4, side1: 4, side2: 4, side3: 4, side4: 4, side5: 4}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 15, id: "mekanism:creative_energy_cube", redstone: 0b}}, + {pos: [3, 1, 1], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, energy: "8000", id: "mekanism:basic_universal_cable", redstone: 0b}}, + {pos: [3, 1, 2], state: "advancedperipherals:energy_detector{orientation:north_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Energy Detector]"}, Items: [], id: "advancedperipherals:energy_detector", rateLimit: 0}}, + {pos: [3, 1, 3], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, id: "mekanism:basic_universal_cable", redstone: 0b}}, + {pos: [3, 1, 4], state: "mekanism:basic_energy_cube{facing:west,fluid_logged:empty}", nbt: {EnergyContainers: [{Container: 0b, stored: "4000000"}], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 15, id: "mekanism:basic_energy_cube", redstone: 0b}}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "mekanism:creative_energy_cube{facing:north,fluid_logged:empty}", + "mekanism:basic_universal_cable{fluid_logged:empty}", + "advancedperipherals:energy_detector{orientation:south_up}", + "mekanism:creative_energy_cube{facing:west,fluid_logged:empty}", + "computercraft:computer_advanced{facing:north,state:blinking}", + "mekanism:creative_energy_cube{facing:east,fluid_logged:empty}", + "advancedperipherals:energy_detector{orientation:north_up}", + "mekanism:basic_energy_cube{facing:west,fluid_logged:empty}" + ] +} From 21c4f6f0a63d792d6e932a9d2fe1cea735976ec6 Mon Sep 17 00:00:00 2001 From: endi Date: Sat, 7 Sep 2024 22:33:22 +0200 Subject: [PATCH 56/61] snake case peripheral types, some ae2 test fixes --- .../integrations/NoteBlockIntegration.java | 2 +- .../peripheral/FluidDetectorPeripheral.java | 4 ++-- .../peripheral/GasDetectorPeripheral.java | 4 ++-- .../peripheral/MeBridgePeripheral.java | 2 +- .../common/util/inventory/ItemUtil.java | 4 ++++ .../gametest/TestGameTests.java | 17 ----------------- .../computer/tests/chatboxtest.chatbox.lua | 2 +- .../tests/chatboxtest.chatbox_events.lua | 2 +- .../tests/modintegrtest.botaniaflower.lua | 6 +++--- .../tests/modintegrtest.botaniamanapool.lua | 6 +++--- .../tests/modintegrtest.botaniaspreader.lua | 8 ++++---- .../tests/modintegrtest.minecraftnoteblock.lua | 2 +- .../tests/peripheraltest.blockreader.lua | 6 +++--- .../computer/tests/peripheraltest.energydet.lua | 2 +- .../tests/peripheraltest.environment.lua | 2 +- .../tests/peripheraltest.geoscanner.lua | 2 +- .../computer/tests/peripheraltest.mestorage.lua | 16 ++++++++-------- .../tests/peripheraltest.metransfer.lua | 2 +- .../tests/peripheraltest.nbtstorage.lua | 2 +- .../tests/peripheraltest.rsintegrator.lua | 4 ++-- 20 files changed, 41 insertions(+), 54 deletions(-) delete mode 100644 src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/NoteBlockIntegration.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/NoteBlockIntegration.java index ad5a653d3..c158a5672 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/NoteBlockIntegration.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/integrations/NoteBlockIntegration.java @@ -19,7 +19,7 @@ public NoteBlockIntegration(Level world, BlockPos pos) { @NotNull @Override public String getType() { - return "noteBlock"; + return "note_block"; } @LuaFunction(mainThread = true) diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/FluidDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/FluidDetectorPeripheral.java index c54dde612..8bace2906 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/FluidDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/FluidDetectorPeripheral.java @@ -9,10 +9,10 @@ public class FluidDetectorPeripheral extends BasePeripheral> { - public static final String TYPE = "fluid_detector"; + public static final String PERIPHERAL_TYPE = "fluid_detector"; public FluidDetectorPeripheral(FluidDetectorEntity tileEntity) { - super(TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); + super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); } @Override diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GasDetectorPeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GasDetectorPeripheral.java index fd94811e3..b066c72ee 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GasDetectorPeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/GasDetectorPeripheral.java @@ -8,10 +8,10 @@ public class GasDetectorPeripheral extends BasePeripheral> { - public static final String TYPE = "gas_detector"; + public static final String PERIPHERAL_TYPE = "gas_detector"; public GasDetectorPeripheral(GasDetectorEntity tileEntity) { - super(TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); + super(PERIPHERAL_TYPE, new BlockEntityPeripheralOwner<>(tileEntity)); } @Override diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java index 86776f7b0..787f1ec14 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java @@ -37,7 +37,7 @@ public class MeBridgePeripheral extends BasePeripheral> implements IStorageSystemPeripheral { - public static final String PERIPHERAL_TYPE = "meBridge"; + public static final String PERIPHERAL_TYPE = "me_bridge"; private final MeBridgeEntity tile; private IGridNode node; diff --git a/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java b/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java index 3aa3de0a1..1985ccfd0 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java +++ b/src/main/java/de/srendi/advancedperipherals/common/util/inventory/ItemUtil.java @@ -2,8 +2,12 @@ import dan200.computercraft.shared.Registry; import de.srendi.advancedperipherals.AdvancedPeripherals; +import de.srendi.advancedperipherals.client.KeyBindings; +import de.srendi.advancedperipherals.common.util.EnumColor; import de.srendi.advancedperipherals.common.util.StringUtil; import net.minecraft.ResourceLocationException; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; diff --git a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java b/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java deleted file mode 100644 index 11a9bc84e..000000000 --- a/src/testMod/java/de/srendi/advancedperipherals/gametest/TestGameTests.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.srendi.advancedperipherals.gametest; - -import net.minecraft.gametest.framework.GameTest; -import net.minecraft.gametest.framework.GameTestHelper; -import net.minecraftforge.gametest.GameTestHolder; -import net.minecraftforge.gametest.PrefixGameTestTemplate; - -@GameTestHolder("advancedperipheralstest") -public class TestGameTests { - - @PrefixGameTestTemplate(false) - @GameTest(templateNamespace = "advancedperipheralstest") - public static void envDetectorTest(GameTestHelper helper) { - helper.succeed(); - } - -} diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua index 6ed39caf7..f6e7dfafe 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox.lua @@ -6,7 +6,7 @@ sleep(3) -chatBox = peripheral.find("chatBox") +chatBox = peripheral.find("chat_box") test.assert(chatBox, "Peripheral not found") config = chatBox.getConfiguration() diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua index 526b9b54a..3332524a4 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/chatboxtest.chatbox_events.lua @@ -4,7 +4,7 @@ --- `sendFormattedMessage`, `sendFormattedMessageToPlayer` --- -chatBox = peripheral.find("chatBox") +chatBox = peripheral.find("chat_box") test.assert(chatBox, "Peripheral not found") function assertMessage(msg, hidden) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua index 911e8144a..bb2d265d6 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaflower.lua @@ -5,7 +5,7 @@ --- -- Test for Entropinnyum (Flower has full mana store and is on enchanted soil) -test.eq("manaFlower", peripheral.getType("left"), "Peripheral should be manaFlower") +test.eq("mana_flower", peripheral.getType("left"), "Peripheral should be manaFlower") entropinnyum = peripheral.wrap("left") test.assert(entropinnyum, "Peripheral not found") @@ -17,7 +17,7 @@ test.assert(not entropinnyum.isFloating(), "Entropinnyum should not be floating" -- test.assert(not entropinnyum.isEmpty(), "Entropinnyum should not be empty") TODO: uncomment for 1.20.1 AP versions -- Test for Endoflame (Flower has no mana stored and is on normal soil) -test.eq("manaFlower", peripheral.getType("right"), "Peripheral should be manaFlower") +test.eq("mana_flower", peripheral.getType("right"), "Peripheral should be manaFlower") endoflame = peripheral.wrap("right") test.assert(endoflame, "Peripheral not found") @@ -29,7 +29,7 @@ test.assert(not endoflame.isFloating(), "Endoflame should not be floating") -- test.assert(endoflame.isEmpty(), "Endoflame should be empty") TODO: uncomment for 1.20.1 AP versions -- Test for Kekimurus (Flower has 1800 mana stored and is floating) -test.eq("manaFlower", peripheral.getType("back"), "Peripheral should be manaFlower") +test.eq("mana_flower", peripheral.getType("back"), "Peripheral should be manaFlower") kekimurus = peripheral.wrap("back") test.assert(kekimurus, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua index a7487ac3a..fb53d7dc0 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniamanapool.lua @@ -7,7 +7,7 @@ -- TODO Add tests for canChargeItem, hasItems and getItems in 1.20.1 AP versions -- Test Fabulous Mana Pool (should be empty) -test.eq("manaPool", peripheral.getType("left"), "Peripheral should be manaPool") +test.eq("mana_pool", peripheral.getType("left"), "Peripheral should be manaPool") fabulous = peripheral.wrap("left") test.assert(fabulous, "Peripheral not found") @@ -18,7 +18,7 @@ test.eq(1000000, fabulous.getManaNeeded(), "Mana needed should be 1000000") test.assert(not fabulous.isFull(), "Mana pool should not be full") -- Test Mana Pool (should have 36000 mana) -test.eq("manaPool", peripheral.getType("right"), "Peripheral should be manaPool") +test.eq("mana_pool", peripheral.getType("right"), "Peripheral should be manaPool") manaPool = peripheral.wrap("right") test.assert(manaPool, "Peripheral not found") @@ -29,7 +29,7 @@ test.eq(964000, manaPool.getManaNeeded(), "Mana needed should be 964000") test.assert(not manaPool.isFull(), "Mana pool should not be full") -- Test Creative Mana Pool (should have 1000000 mana) -test.eq("manaPool", peripheral.getType("back"), "Peripheral should be manaPool") +test.eq("mana_pool", peripheral.getType("back"), "Peripheral should be manaPool") creative = peripheral.wrap("back") test.assert(creative, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua index e72424f24..269e79c88 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.botaniaspreader.lua @@ -7,7 +7,7 @@ -- TODO Add tests for hasLens and getLens in 1.20.1 AP versions -- Test basic Mana Spreader that is empty and directed towards a Mana Pool -test.eq("manaSpreader", peripheral.getType("left"), "Peripheral should be manaSpreader") +test.eq("mana_spreader", peripheral.getType("left"), "Peripheral should be manaSpreader") spreader = peripheral.wrap("left") test.assert(spreader, "Peripheral not found") @@ -27,7 +27,7 @@ test.eq(computerPos.y, bounding.y, "Bounding y should be set to Mana pool (same test.eq(computerPos.z - 1, bounding.z, "Bounding z should be set to Mana pool (-1 relative to computer") -- Test Gaia Mana Spreader that is full -test.eq("manaSpreader", peripheral.getType("right"), "Peripheral should be manaSpreader") +test.eq("mana_spreader", peripheral.getType("right"), "Peripheral should be manaSpreader") gaiaSpreader = peripheral.wrap("right") test.assert(gaiaSpreader, "Peripheral not found") @@ -40,7 +40,7 @@ test.assert(gaiaSpreader.isFull(), "Mana Spreader should be full") test.assert(not gaiaSpreader.getBounding(), "Mana Spreader should not be bound to anything") -- Test Elven Mana Spreader that has 177 mana -test.eq("manaSpreader", peripheral.getType("back"), "Peripheral should be manaSpreader") +test.eq("mana_spreader", peripheral.getType("back"), "Peripheral should be manaSpreader") elvenSpreader = peripheral.wrap("back") test.assert(elvenSpreader, "Peripheral not found") @@ -53,7 +53,7 @@ test.assert(not elvenSpreader.isFull(), "Mana Spreader should not be full") test.assert(not elvenSpreader.getBounding(), "Mana Spreader should not be bound to anything") -- Test Pulse Mana Spreader that is empty -test.eq("manaSpreader", peripheral.getType("top"), "Peripheral should be manaSpreader") +test.eq("mana_spreader", peripheral.getType("top"), "Peripheral should be manaSpreader") pulseSpreader = peripheral.wrap("top") test.assert(pulseSpreader, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua index 088ac2687..f36ef44de 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua @@ -3,7 +3,7 @@ --- Covers `playNote`, `getNote`, `changeNoteBy`, `changeNote` --- -test.eq("noteBlock", peripheral.getType("left"), "Peripheral should be noteBlock") +test.eq("note_block", peripheral.getType("left"), "Peripheral should be noteBlock") noteBlock = peripheral.wrap("left") test.assert(noteBlock, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua index 3d61e5466..c4e9edbc3 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.blockreader.lua @@ -10,7 +10,7 @@ function tableLength(T) end -- Test Block Reader functions on a simple block -test.eq("blockReader", peripheral.getType("left"), "Peripheral should be blockReader") +test.eq("block_reader", peripheral.getType("left"), "Peripheral should be blockReader") simpleReader = peripheral.wrap("left") test.assert(simpleReader, "Peripheral not found") @@ -20,7 +20,7 @@ test.assert(not simpleReader.isTileEntity(), "Block should not be a TileEntity") test.eq(0, tableLength(simpleReader.getBlockStates()), "Block State should be empty") -- Test Block Reader functions on a stair block -test.eq("blockReader", peripheral.getType("back"), "Peripheral should be blockReader") +test.eq("block_reader", peripheral.getType("back"), "Peripheral should be blockReader") stairReader = peripheral.wrap("back") test.assert(stairReader, "Peripheral not found") @@ -35,7 +35,7 @@ test.eq("straight", stairReader.getBlockStates()["shape"], "Stair Shape should b test.assert(not stairReader.getBlockStates()["waterlogged"], "Stair Waterlogged should be false") -- Test Block Reader functions on a sign block -test.eq("blockReader", peripheral.getType("right"), "Peripheral should be blockReader") +test.eq("block_reader", peripheral.getType("right"), "Peripheral should be blockReader") signReader = peripheral.wrap("right") test.assert(signReader, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua index 5839fcb57..8b294ebde 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua @@ -3,7 +3,7 @@ --- Covers `getTransferRate`, `setTransferRateLimit`, `getTransferRateLimit` --- -test.eq("energyDetector", peripheral.getType("right"), "Peripheral should be energyDetector") +test.eq("energy_detector", peripheral.getType("right"), "Peripheral should be energyDetector") det = peripheral.wrap("right") det.setTransferRateLimit(0) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua index ff0400c66..ac7cfda8f 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.environment.lua @@ -1,4 +1,4 @@ -detector = peripheral.find("environmentDetector") +detector = peripheral.find("environment_detector") test.assert(detector, true, "Peripheral not found") isRaining = detector.isRaining() diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua index 455d37b85..f1b4861e4 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.geoscanner.lua @@ -28,7 +28,7 @@ function testBlockAt(result, x, y, z, expectedName, expectedTag) test.assert(tagFound, ("Block at %d, %d, %d has the wrong tags"):format(x, y, z)) end -scanner = peripheral.find("geoScanner") +scanner = peripheral.find("geo_scanner") test.assert(scanner, "Peripheral not found") config = scanner.getConfiguration() diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua index cdac21a34..8c03825d0 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua @@ -15,29 +15,29 @@ test.assert(isOnline, "Bridge is not connected/system is not online") energyUsage = bridge.getEnergyUsage() test.assert(energyUsage > 18, tostring(energyUsage) .. " Consumption does not seem right") -maxEnergyStorage = bridge.getMaxEnergyStorage() +maxEnergyStorage = bridge.getEnergyCapacity() test.assert(maxEnergyStorage == 1608800, tostring(maxEnergyStorage) .. " Max Energy Storage does not seem right") -energyStorage = bridge.getEnergyStorage() +energyStorage = bridge.getStoredEnergy() test.assert(energyStorage > 1590000, tostring(energyStorage) .. " Energy Storage does not seem right") totalItemStorage = bridge.getTotalItemStorage() -test.assert(totalItemStorage == 67264, "Total item storage is not valid") +test.assert(totalItemStorage == 65536, "Total item storage is not valid") totalFluidStorage = bridge.getTotalFluidStorage() -test.assert(totalFluidStorage == 81536, "Total fluid storage is not valid") +test.assert(totalFluidStorage == 65536, "Total fluid storage is not valid") usedItemStorage = bridge.getUsedItemStorage() -test.assert(usedItemStorage == 1120, "Used item storage is not valid") +test.assert(usedItemStorage == 1088, "Used item storage is not valid") usedFluidStorage = bridge.getUsedFluidStorage() -test.assert(usedFluidStorage == 2025, "Used fluid storage is not valid") +test.assert(usedFluidStorage == 1025, "Used fluid storage is not valid") availableItemStorage = bridge.getAvailableItemStorage() -test.assert(availableItemStorage == 66144, "Available item storage is not valid") +test.assert(availableItemStorage == 64448, "Available item storage is not valid") availableFluidStorage = bridge.getAvailableFluidStorage() -test.assert(availableFluidStorage == 79511, "Available fluid storage is not valid") +test.assert(availableFluidStorage == 64511, "Available fluid storage is not valid") cells = bridge.listCells() test.assert(#cells == 2, "There should be 2 cells") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua index f414733f6..84a7674f5 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua @@ -5,7 +5,7 @@ --- sleep(4) -bridge = peripheral.wrap("meBridge_3") +bridge = peripheral.wrap("me_bridge_3") chest = peripheral.wrap("minecraft:chest_2") test.assert(bridge, "Peripheral not found") test.assert(chest, "Chest not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua index 12017d4b1..6fcc6a357 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.nbtstorage.lua @@ -9,7 +9,7 @@ TEST_FLOAT = 3.14 TEST_VALUE = "AP Game Test" TEST_JSON_VALUE = "AP Game Test JSON" -test.eq("nbtStorage", peripheral.getType("left"), "Peripheral should be nbtStorage") +test.eq("nbt_storage", peripheral.getType("left"), "Peripheral should be nbtStorage") storage = peripheral.wrap("left") test.assert(storage, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua index 36c4c0d8b..a983e2040 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.rsintegrator.lua @@ -4,8 +4,8 @@ --- `getAnalogOutput`, `setOutput`, `setAnalogOutput` --- -test.eq("redstoneIntegrator", peripheral.getType("left"), "Peripheral should be redstoneIntegrator") -test.eq("redstoneIntegrator", peripheral.getType("right"), "Peripheral should be redstoneIntegrator") +test.eq("redstone_integrator", peripheral.getType("left"), "Peripheral should be redstone_integrator") +test.eq("redstone_integrator", peripheral.getType("right"), "Peripheral should be redstone_integrator") first = peripheral.wrap("left") test.assert(first, "Peripheral not found") From 2b9d61209778feb9eb6e6e5be6a4c6d1222ba31c Mon Sep 17 00:00:00 2001 From: endi Date: Sat, 7 Sep 2024 22:55:09 +0200 Subject: [PATCH 57/61] Adapted some me bridge tests to the new me bridge peripheral --- .../tests/modintegrtest.minecraftnoteblock.lua | 2 +- .../computer/tests/peripheraltest.mestorage.lua | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua index f36ef44de..3bf3ceec7 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/modintegrtest.minecraftnoteblock.lua @@ -17,7 +17,7 @@ test.eq(1, noteBlock.getNote(), "Note should be 1") noteBlock.playNote() -- this note block has a block above it, so it should not play a note -test.eq("noteBlock", peripheral.getType("right"), "Peripheral should be noteBlock") +test.eq("note_block", peripheral.getType("right"), "Peripheral should be noteBlock") silentNoteBlock = peripheral.wrap("right") test.assert(silentNoteBlock, "Peripheral not found") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua index 8c03825d0..e1111ebfe 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mestorage.lua @@ -41,16 +41,16 @@ test.assert(availableFluidStorage == 64511, "Available fluid storage is not vali cells = bridge.listCells() test.assert(#cells == 2, "There should be 2 cells") - +print(textutils.serialize(cells[1])) itemCell = nil fluidCell = nil for _, cell in pairs(cells) do - if cell.cellType == "item" then + if cell.type == "ae2:i" then itemCell = cell end end for _, cell in pairs(cells) do - if cell.cellType == "fluid" then + if cell.type == "ae2:f" then fluidCell = cell end end @@ -58,16 +58,17 @@ end test.assert(itemCell, "Item cell not found") test.assert(fluidCell, "Fluid cell not found") -itemCellBytes = itemCell.totalBytes +itemCellBytes = itemCell.bytes +print(textutils.serialize(itemCell)) test.assert(itemCellBytes == 65536, "Item cell bytes is not valid") -fluidCellBytes = fluidCell.totalBytes +fluidCellBytes = fluidCell.bytes test.assert(fluidCellBytes == 65536, "Fluid cell bytes is not valid") -itemCellItem = itemCell.item +itemCellItem = itemCell.item.name test.assert(itemCellItem == "ae2:item_storage_cell_64k", "Item cell item not found") -fluidCellItem = fluidCell.item +fluidCellItem = fluidCell.item.name test.assert(fluidCellItem == "ae2:fluid_storage_cell_64k", "Fluid cell item not found") itemCellBytesPerType = itemCell.bytesPerType From 099279efecc8eaa0f0e776d4836ca3b1bfd5dc31 Mon Sep 17 00:00:00 2001 From: endi Date: Tue, 10 Sep 2024 13:10:40 +0200 Subject: [PATCH 58/61] Using powah for the energy detector test to prevent a crashing NPE with mekanism Fixed the me transfer test --- gradle.properties | 2 +- .../peripheral/MeBridgePeripheral.java | 4 +-- .../test/PeripheralTest.kt | 6 ++-- .../tests/peripheraltest.energydet.lua | 6 ++-- .../tests/peripheraltest.mecrafting.lua | 2 +- .../tests/peripheraltest.metransfer.lua | 14 ++++----- .../structures/peripheraltest.energydet.snbt | 31 +++++++++---------- .../structures/peripheraltest.metransfer.snbt | 14 ++++----- 8 files changed, 38 insertions(+), 41 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2826e90a8..d905797a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ org.gradle.logging.level=info # Minecraft related mod_id=advancedperipherals minecraft_version=1.19.2 -forge_version=43.4.0 +forge_version=43.4.2 loader_version=43 mod_version=0.8r release_type=release diff --git a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java index 787f1ec14..d577b5d66 100644 --- a/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java +++ b/src/main/java/de/srendi/advancedperipherals/common/addons/computercraft/peripheral/MeBridgePeripheral.java @@ -262,7 +262,7 @@ public final MethodResult importItem(IComputerAccess computer, IArguments argume String side = arguments.getString(1); IItemHandler inventory; - if (Direction.byName(side.toUpperCase(Locale.ROOT)) == null && ComputerSide.valueOfInsensitive(side.toUpperCase(Locale.ROOT)) == null) { + if (Direction.byName(side) != null || ComputerSide.valueOfInsensitive(side.toUpperCase(Locale.ROOT)) != null) { inventory = InventoryUtil.getHandlerFromDirection(arguments.getString(1), owner); } else { inventory = InventoryUtil.getHandlerFromName(computer, arguments.getString(1)); @@ -280,7 +280,7 @@ public final MethodResult exportItem(IComputerAccess computer, @NotNull IArgumen String side = arguments.getString(1); IItemHandler inventory; - if (Direction.byName(side.toUpperCase(Locale.ROOT)) == null && ComputerSide.valueOfInsensitive(side.toUpperCase(Locale.ROOT)) == null) { + if (Direction.byName(side) != null || ComputerSide.valueOfInsensitive(side.toUpperCase(Locale.ROOT)) != null) { inventory = InventoryUtil.getHandlerFromDirection(arguments.getString(1), owner); } else { inventory = InventoryUtil.getHandlerFromName(computer, arguments.getString(1)); diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 264be4d2a..7f0ffb13c 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -17,17 +17,17 @@ class PeripheralTest { // The ME System needs to boot up, so we use a sleep() in the specific lua script // We set the timeoutTicks to 300 so the test does not fail - @GameTest(timeoutTicks = 300) + @GameTest(timeoutTicks = 600) fun meCrafting(context: GameTestHelper) = context.sequence { thenComputerOk(); } - @GameTest(timeoutTicks = 300) + @GameTest(timeoutTicks = 600) fun meStorage(context: GameTestHelper) = context.sequence { thenComputerOk(); } - @GameTest(timeoutTicks = 300) + @GameTest(timeoutTicks = 600) fun meTransfer(context: GameTestHelper) = context.sequence { thenComputerOk(); } diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua index 8b294ebde..4c442e746 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.energydet.lua @@ -16,7 +16,7 @@ sleep(0.5) test.eq(100, det.getTransferRate(), "Transfer Rate should be 100") test.eq(100, det.getTransferRateLimit(), "Transfer Rate Limit should be 100") -det.setTransferRateLimit(100000) +det.setTransferRateLimit(4000000) sleep(0.5) -test.eq(3200, det.getTransferRate(), "Transfer Rate should be 3200") -- Rate limit from the cables -test.eq(100000, det.getTransferRateLimit(), "Transfer Rate Limit should be 100000") +test.eq(100000, det.getTransferRate(), "Transfer Rate should be 100000") -- Rate limit from the cables +test.eq(4000000, det.getTransferRateLimit(), "Transfer Rate Limit should be 4000000") diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua index ad9d15a7d..465dcc7a2 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -54,7 +54,7 @@ stickCount = bridge.getItem(stickFilter).amount test.assert(stickCount == 8, "We should have 8 sticks") -- There is no getFluid function, so we need to do it like this -waterCount = bridge.listCraftableFluid()[1].amount +waterCount = bridge.listCraftableFluids()[1].amount test.assert(waterCount == 0, "We should not have water") craftingSuccessful = bridge.craftFluid(waterFilter) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua index 84a7674f5..2b46d3308 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.metransfer.lua @@ -5,7 +5,7 @@ --- sleep(4) -bridge = peripheral.wrap("me_bridge_3") +bridge = peripheral.wrap("me_bridge_20") chest = peripheral.wrap("minecraft:chest_2") test.assert(bridge, "Peripheral not found") test.assert(chest, "Chest not found") @@ -19,8 +19,8 @@ test.assert(energyUsage > 17, tostring(energyUsage) .. " Consumption does not se planksFilter = {name="minecraft:oak_planks", count=5} logFilter = {name="minecraft:oak_log", count=8} -exported, err = bridge.exportItemToPeripheral(planksFilter, peripheral.getName(chest)) -test.assert(exported == 5, "Export failed ".. (err or "")) +exported, err = bridge.exportItem(planksFilter, peripheral.getName(chest)) +test.assert(exported == 5, "Export failed 5 planks to chest ".. (err or "")) planksItem = bridge.getItem(planksFilter) test.assert(planksItem.amount == 251, "We should have 251 planks") @@ -36,7 +36,7 @@ test.assert(chestPlanks, "Planks not found in chest") test.assert(chestPlanks.count == 5, "We should have 5 planks in the chest") exported, err = bridge.exportItem(planksFilter, "front") -test.assert(exported == 5, "Export failed ".. (err or "")) +test.assert(exported == 5, "Export failed 5 planks to front:".. (err or "")) planksItem = bridge.getItem(planksFilter) test.assert(planksItem.amount == 246, "We should have 246 planks") @@ -50,8 +50,8 @@ end test.assert(chestPlanks, "Planks not found in chest") test.assert(chestPlanks.count == 10, "We should have 5 planks in the chest") -imported, err = bridge.importItemFromPeripheral(logFilter, peripheral.getName(chest)) -test.assert(imported == 8, "import failed ".. (err or "")) +imported, err = bridge.importItem(logFilter, peripheral.getName(chest)) +test.assert(imported == 8, "import failed 8 logs to chest".. (err or "")) logsItem = bridge.getItem(logFilter) test.assert(logsItem.amount == 264, "We should have 264 logs") @@ -67,7 +67,7 @@ test.assert(chestLogs, "Logs not found in chest") test.assert(chestLogs.count == 56, "We should have 56 logs in the chest") imported, err = bridge.importItem(logFilter, "south") -test.assert(imported == 8, "import failed ".. (err or "")) +test.assert(imported == 8, "import failed 8 logs from south".. (err or "")) logsItem = bridge.getItem(logFilter) test.assert(logsItem.amount == 272, "We should have 272 logs") diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt index a7d9cca1b..fbb06aa29 100644 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.energydet.snbt @@ -32,21 +32,21 @@ {pos: [0, 1, 2], state: "minecraft:air"}, {pos: [0, 1, 3], state: "minecraft:air"}, {pos: [0, 1, 4], state: "minecraft:air"}, - {pos: [1, 1, 0], state: "mekanism:creative_energy_cube{facing:north,fluid_logged:empty}", nbt: {EnergyContainers: [], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 1, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 0, id: "mekanism:creative_energy_cube", redstone: 0b}}, - {pos: [1, 1, 1], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, id: "mekanism:basic_universal_cable", redstone: 0b}}, - {pos: [1, 1, 2], state: "advancedperipherals:energy_detector{orientation:south_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Energy Detector]"}, Items: [], id: "advancedperipherals:energy_detector", rateLimit: 0}}, - {pos: [1, 1, 3], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, energy: "8000", id: "mekanism:basic_universal_cable", redstone: 0b}}, - {pos: [1, 1, 4], state: "mekanism:creative_energy_cube{facing:west,fluid_logged:empty}", nbt: {EnergyContainers: [{Container: 0b, stored: "18446744073709551615.9999"}], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 4, side1: 4, side2: 4, side3: 4, side4: 4, side5: 4}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 15, id: "mekanism:creative_energy_cube", redstone: 0b}}, + {pos: [1, 1, 0], state: "powah:energy_cell_niotic{waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], Size: 2, energy_stored_main_energy: 16400L, id: "powah:energy_cell", redstone_mode: 0, side_transfer_type: [I; 0, 0, 0, 0, 0, 0], variant: 4}}, + {pos: [1, 1, 1], state: "powah:energy_cable_nitro{down:false,east:false,north:false,south:false,up:false,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, cs: 12b, energy_capacity_main_energy: 0L, energy_stored_main_energy: 0L, id: "powah:energy_cable", redstone_mode: 0, side_transfer_type: [I; 0, 0, 1, 2, 0, 0], variant: 6}}, + {pos: [1, 1, 2], state: "advancedperipherals:energy_detector{orientation:south_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Energy Detector]"}, Items: [], id: "advancedperipherals:energy_detector", rateLimit: 100}}, + {pos: [1, 1, 3], state: "powah:energy_cable_nitro{down:false,east:false,north:false,south:false,up:false,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, cs: 12b, energy_capacity_main_energy: 0L, energy_stored_main_energy: 0L, id: "powah:energy_cable", redstone_mode: 0, side_transfer_type: [I; 0, 0, 1, 2, 0, 0], variant: 6}}, + {pos: [1, 1, 4], state: "powah:energy_cell_creative{waterlogged:false}", nbt: {ForgeCaps: {}, Items: [], Size: 2, energy_capacity_main_energy: 9000000000000000000L, energy_stored_main_energy: 9000000000000000000L, id: "powah:energy_cell", redstone_mode: 0, side_transfer_type: [I; 1, 1, 1, 1, 1, 1], variant: 7}}, {pos: [2, 1, 0], state: "minecraft:air"}, {pos: [2, 1, 1], state: "minecraft:air"}, {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.energydet", On: 1b, id: "computercraft:computer_advanced"}}, {pos: [2, 1, 3], state: "minecraft:air"}, {pos: [2, 1, 4], state: "minecraft:air"}, - {pos: [3, 1, 0], state: "mekanism:creative_energy_cube{facing:east,fluid_logged:empty}", nbt: {EnergyContainers: [{Container: 0b, stored: "18446744073709551615.9999"}], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 4, side1: 4, side2: 4, side3: 4, side4: 4, side5: 4}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 15, id: "mekanism:creative_energy_cube", redstone: 0b}}, - {pos: [3, 1, 1], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, energy: "8000", id: "mekanism:basic_universal_cable", redstone: 0b}}, - {pos: [3, 1, 2], state: "advancedperipherals:energy_detector{orientation:north_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[Energy Detector]"}, Items: [], id: "advancedperipherals:energy_detector", rateLimit: 0}}, - {pos: [3, 1, 3], state: "mekanism:basic_universal_cable{fluid_logged:empty}", nbt: {ForgeCaps: {}, connection0: 0, connection1: 0, connection2: 0, connection3: 0, connection4: 0, connection5: 0, id: "mekanism:basic_universal_cable", redstone: 0b}}, - {pos: [3, 1, 4], state: "mekanism:basic_energy_cube{facing:west,fluid_logged:empty}", nbt: {EnergyContainers: [{Container: 0b, stored: "4000000"}], ForgeCaps: {}, Items: [], componentConfig: {config0: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, config6: {side0: 4, side1: 1, side2: 1, side3: 1, side4: 1, side5: 1}, eject0: 1b, eject6: 0b}, componentEjector: {color0: -1, color1: -1, color2: -1, color3: -1, color4: -1, color5: -1, strictInput: 0b}, componentFrequency: {Security: {name: "Security", owner: [I; 940439953, -167562164, -1601161573, -1389718966], publicFreq: 1b}}, componentSecurity: {owner: [I; 940439953, -167562164, -1601161573, -1389718966], securityMode: 0}, controlType: 0, currentRedstone: 15, id: "mekanism:basic_energy_cube", redstone: 0b}}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "minecraft:air"}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, {pos: [4, 1, 0], state: "minecraft:air"}, {pos: [4, 1, 1], state: "minecraft:air"}, {pos: [4, 1, 2], state: "minecraft:air"}, @@ -132,13 +132,10 @@ palette: [ "minecraft:polished_andesite", "minecraft:air", - "mekanism:creative_energy_cube{facing:north,fluid_logged:empty}", - "mekanism:basic_universal_cable{fluid_logged:empty}", + "powah:energy_cell_niotic{waterlogged:false}", + "powah:energy_cable_nitro{down:false,east:false,north:false,south:false,up:false,waterlogged:false,west:false}", "advancedperipherals:energy_detector{orientation:south_up}", - "mekanism:creative_energy_cube{facing:west,fluid_logged:empty}", - "computercraft:computer_advanced{facing:north,state:blinking}", - "mekanism:creative_energy_cube{facing:east,fluid_logged:empty}", - "advancedperipherals:energy_detector{orientation:north_up}", - "mekanism:basic_energy_cube{facing:west,fluid_logged:empty}" + "powah:energy_cell_creative{waterlogged:false}", + "computercraft:computer_advanced{facing:north,state:blinking}" ] } diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt index 8c10cfb87..c3a6101d9 100644 --- a/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt +++ b/src/testMod/resources/data/advancedperipheralstest/structures/peripheraltest.metransfer.snbt @@ -33,14 +33,14 @@ {pos: [0, 1, 3], state: "minecraft:air"}, {pos: [0, 1, 4], state: "minecraft:air"}, {pos: [1, 1, 0], state: "minecraft:air"}, - {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_planks"}, {"#c": "ae2:i", id: "minecraft:oak_log"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 1054L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "empty"}, online: 1b}}}, + {pos: [1, 1, 1], state: "ae2:drive", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:drive", inv: {item0: {Count: 1b, id: "ae2:item_storage_cell_64k", tag: {amts: [L; 256L, 256L], ic: 512L, keys: [{"#c": "ae2:i", id: "minecraft:oak_log"}, {"#c": "ae2:i", id: "minecraft:oak_planks"}]}}, item1: {Count: 1b, id: "ae2:fluid_storage_cell_64k", tag: {}}, item2: {}, item3: {}, item4: {}, item5: {}, item6: {}, item7: {}, item8: {}, item9: {}}, priority: 0, proxy: {g: 1054L, k: -1L, p: 0}, up: "UP", visual: {cell0: {id: "ae2:item_storage_cell_64k", state: "not_empty"}, cell1: {id: "ae2:fluid_storage_cell_64k", state: "empty"}, online: 1b}}}, {pos: [1, 1, 2], state: "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:true,up:true,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, PeirpheralAccess: 1b, PeripheralId: 3, PeripheralType: "computer", id: "computercraft:cable"}}, {pos: [1, 1, 3], state: "computercraft:cable{cable:true,down:false,east:true,modem:none,north:true,south:true,up:false,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, PeirpheralAccess: 0b, id: "computercraft:cable"}}, {pos: [1, 1, 4], state: "computercraft:cable{cable:true,down:false,east:false,modem:none,north:true,south:false,up:true,waterlogged:false,west:false}", nbt: {ForgeCaps: {}, PeirpheralAccess: 0b, id: "computercraft:cable"}}, {pos: [2, 1, 0], state: "minecraft:air"}, {pos: [2, 1, 1], state: "ae2:controller{state:online,type:block}", nbt: {ForgeCaps: {}, id: "ae2:controller", internalCurrentPower: 0.0d, proxy: {g: 1054L, k: -1L, p: 0}, visual: {}}}, {pos: [2, 1, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsNorth: 0, channelsUp: 0, connections: ["up", "north"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, - {pos: [2, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:false,up:true,waterlogged:false,west:true}", nbt: {ForgeCaps: {}, PeirpheralAccess: 1b, PeripheralId: 3, PeripheralType: "meBridge", id: "computercraft:cable"}}, + {pos: [2, 1, 3], state: "computercraft:cable{cable:true,down:false,east:false,modem:up_off_peripheral,north:false,south:false,up:true,waterlogged:false,west:true}", nbt: {ForgeCaps: {}, PeirpheralAccess: 1b, PeripheralId: 20, PeripheralType: "me_bridge", id: "computercraft:cable"}}, {pos: [2, 1, 4], state: "minecraft:air"}, {pos: [3, 1, 0], state: "minecraft:air"}, {pos: [3, 1, 1], state: "ae2:creative_energy_cell", nbt: {ForgeCaps: {}, forward: "NORTH", id: "ae2:creative_energy_cell", proxy: {g: 1054L, k: -1L, p: 0}, up: "UP", visual: {}}}, @@ -61,11 +61,11 @@ {pos: [1, 2, 1], state: "minecraft:air"}, {pos: [1, 2, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 0, ForgeCaps: {}, Label: "peripheraltest.metransfer", On: 1b, id: "computercraft:computer_advanced"}}, {pos: [1, 2, 3], state: "ae2:sky_stone_tank", nbt: {ForgeCaps: {}, forward: "SOUTH", id: "ae2:sky_tank", up: "UP", visual: {}}}, - {pos: [1, 2, 4], state: "computercraft:wired_modem_full{modem:false,peripheral:true}", nbt: {ForgeCaps: {}, PeripheralAccess: 1b, PeripheralId2: 1, PeripheralId5: 2, PeripheralType2: "ae2:sky_tank", PeripheralType5: "minecraft:chest", id: "computercraft:wired_modem_full"}}, + {pos: [1, 2, 4], state: "computercraft:wired_modem_full{modem:false,peripheral:true}", nbt: {ForgeCaps: {}, PeripheralAccess: 1b, PeripheralId1: 19, PeripheralId2: 1, PeripheralId5: 2, PeripheralType1: "me_bridge", PeripheralType2: "ae2:sky_tank", PeripheralType5: "minecraft:chest", id: "computercraft:wired_modem_full"}}, {pos: [2, 2, 0], state: "minecraft:air"}, {pos: [2, 2, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, channelsUp: 0, connections: ["down", "up"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:pattern_encoding_terminal", mode: "CRAFTING", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, substitute: 0b, substituteFluids: 1b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, {pos: [2, 2, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsSouth: 0, channelsUp: 0, connections: ["down", "up", "south"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, - {pos: [2, 2, 3], state: "advancedperipherals:me_bridge{orientation:south_up}", nbt: {ForgeCaps: {}, ForgeData: {CustomName: "[ME Bridge]"}, Items: [], id: "advancedperipherals:me_bridge"}}, + {pos: [2, 2, 3], state: "advancedperipherals:me_bridge{orientation:south_up}", nbt: {ForgeCaps: {}, Items: [], id: "advancedperipherals:me_bridge"}}, {pos: [2, 2, 4], state: "minecraft:chest{facing:south,type:single,waterlogged:false}", nbt: {ForgeCaps: {}, Items: [{Count: 64b, Slot: 26b, id: "minecraft:oak_log"}], id: "minecraft:chest"}}, {pos: [3, 2, 0], state: "minecraft:air"}, {pos: [3, 2, 1], state: "minecraft:air"}, @@ -85,12 +85,12 @@ {pos: [1, 3, 0], state: "minecraft:air"}, {pos: [1, 3, 1], state: "minecraft:air"}, {pos: [1, 3, 2], state: "minecraft:air"}, - {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsEast: 0, connections: ["east"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, {pos: [1, 3, 4], state: "minecraft:air"}, {pos: [2, 3, 0], state: "minecraft:air"}, {pos: [2, 3, 1], state: "ae2:cable_bus{light_level:9,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {filter_type: "ALL", gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:crafting_terminal", sort_by: "NAME", sort_direction: "ASCENDING", spin: 0b, view_mode: "ALL", visual: {missingChannel: 0b, powered: 1b}}, south: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, - {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, connections: ["down"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, - {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsSouth: 0, connections: ["down", "south"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", north: {id: "ae2:cable_anchor", visual: {}}, visual: {}}}, + {pos: [2, 3, 3], state: "ae2:cable_bus{light_level:0,waterlogged:false}", nbt: {ForgeCaps: {}, cable: {gn: {g: 1054L, k: -1L, p: 0}, id: "ae2:white_smart_dense_cable", visual: {channelsDown: 0, channelsNorth: 0, channelsWest: 0, connections: ["down", "north", "west"], missingChannel: 0b, powered: 1b}}, hasRedstone: 2, id: "ae2:cable_bus", visual: {}}}, {pos: [2, 3, 4], state: "minecraft:air"}, {pos: [3, 3, 0], state: "minecraft:air"}, {pos: [3, 3, 1], state: "minecraft:air"}, From 770a76a1752bc511551cea09cf1f8083d5516712 Mon Sep 17 00:00:00 2001 From: endi Date: Tue, 10 Sep 2024 13:19:57 +0200 Subject: [PATCH 59/61] increase the timeoutticks for the energy detector test --- .../kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt index 7f0ffb13c..03cc155b0 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/PeripheralTest.kt @@ -52,7 +52,7 @@ class PeripheralTest { thenComputerOk(); } - @GameTest + @GameTest(timeoutTicks = 300) fun energyDet(context: GameTestHelper) = context.sequence { thenComputerOk(); } From 13d3b8a7d38c02d9478cc99c0859fc7c5c5394d7 Mon Sep 17 00:00:00 2001 From: endi Date: Wed, 11 Sep 2024 15:10:37 +0200 Subject: [PATCH 60/61] Test our `isFluidCrafting` and `getFluid` function --- .../computer/tests/peripheraltest.mecrafting.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua index 465dcc7a2..800f7b3c4 100644 --- a/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua +++ b/src/testMod/resources/data/advancedperipheralstest/computer/tests/peripheraltest.mecrafting.lua @@ -2,6 +2,7 @@ --- Advanced Peripherals ME Bridge crafting tests --- Covers `isConnected`, `getEnergyUsage`, `isItemCrafting`, `isItemCraftable`, --- `getItem`, `craftItem`, `listCraftableFluid`, `craftFluid`, `getCraftingCPUs`, +--- `getFluid`, `isFluidCrafting` --- sleep(4) @@ -54,8 +55,8 @@ stickCount = bridge.getItem(stickFilter).amount test.assert(stickCount == 8, "We should have 8 sticks") -- There is no getFluid function, so we need to do it like this -waterCount = bridge.listCraftableFluids()[1].amount -test.assert(waterCount == 0, "We should not have water") +waterCount = bridge.getFluid({name="minecraft:water"}) +test.assert(waterCount, "We should not have water") craftingSuccessful = bridge.craftFluid(waterFilter) test.assert(craftingSuccessful, "Crafting failed") @@ -64,9 +65,9 @@ test.assert(craftingSuccessful, "Crafting failed") -- We just have the pattern which uses a dummy recipe with one log to craft 1B water. The log ist just transferred to a chest -- But we can test if there is a job --- Well... if we would have a function for that... --- isFluidCrafting = bridge.isItemCrafting(waterFilter) --- test.assert(isFluidCrafting, "There should be a crafting job") +sleep(0.5) +isFluidCrafting = bridge.isFluidCrafting(waterFilter) +test.assert(isFluidCrafting, "There should be a crafting job") cpus = bridge.getCraftingCPUs() test.assert(#cpus == 3, "There should be three CPUs") From dc2e8ead1f78ef13fd2d5bec1c6260a50ae9f980 Mon Sep 17 00:00:00 2001 From: endi Date: Sat, 21 Sep 2024 15:03:49 +0200 Subject: [PATCH 61/61] Mekanism Environment detector radiation test --- .../test/APTestExtension.kt | 28 ++++ .../advancedperipherals/test/ModIntegrTest.kt | 50 ++++++- .../modintegrtest.mekanismradiation.snbt | 139 ++++++++++++++++++ 3 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 src/testMod/kotlin/de/srendi/advancedperipherals/test/APTestExtension.kt create mode 100644 src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.mekanismradiation.snbt diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/APTestExtension.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/APTestExtension.kt new file mode 100644 index 000000000..a0bf1a9e2 --- /dev/null +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/APTestExtension.kt @@ -0,0 +1,28 @@ +package de.srendi.advancedperipherals.test + +import net.minecraft.gametest.framework.GameTestHelper + +fun isInRange(value: Double, start: Double, end: Double): Boolean { + val EPSILON = 1e-7 + + return value >= start - EPSILON && value < end + EPSILON +} + +fun GameTestHelper.assertDoubleInRange(value: Double, start: Double, end: Double, message: String) { + if (!(isInRange(value, start, end))) { + fail("$message, is $value, should be between $start and $end") + } +} + +fun GameTestHelper.assertDoubleIs(value: Double, compare: Double, message: String) { + if (!(isInRange(value, compare, compare))) { + fail("$message, is $value, should be $compare") + } +} + +fun GameTestHelper.assertDoubleIsNot(value: Double, compare: Double, message: String) { + if ((isInRange(value, compare, compare))) { + fail("$message, is $value, should be $compare") + } +} + diff --git a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt index 8ea1206f6..dd4dda8a8 100644 --- a/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt +++ b/src/testMod/kotlin/de/srendi/advancedperipherals/test/ModIntegrTest.kt @@ -1,9 +1,14 @@ package de.srendi.advancedperipherals.test -import dan200.computercraft.gametest.api.* +import dan200.computercraft.gametest.api.GameTestHolder +import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.gametest.api.thenComputerOk +import dan200.computercraft.gametest.api.thenOnComputer import dan200.computercraft.gametest.core.TestEvents +import mekanism.common.lib.radiation.RadiationManager import net.minecraft.core.BlockPos -import net.minecraft.gametest.framework.* +import net.minecraft.gametest.framework.GameTest +import net.minecraft.gametest.framework.GameTestHelper import net.minecraft.world.InteractionHand import net.minecraft.world.entity.EntityType import net.minecraft.world.entity.animal.allay.Allay @@ -76,4 +81,45 @@ class ModIntegrTest { } } + @GameTest(setupTicks = 60) + fun mekanismradiation(context: GameTestHelper) = context.sequence { + RadiationManager.INSTANCE.clearSources() + + var radiation: Array? = null; + var rawRadiation = 0.0; + thenOnComputer { + radiation = callPeripheral("right", "getRadiation") + rawRadiation = callPeripheral("right", "getRadiationRaw")?.get(0) as Double + } + thenWaitUntil { + if (radiation?.get(0) == null) + context.fail("Radiation not set") + val value = (radiation?.get(0) as Map<*, *>)["radiation"] + if (value == null) { + context.fail("Radiation not found") + } + context.assertDoubleIs(value.toString().toDouble(), 99.9999, "Radiation incorrect") + + context.assertDoubleIs(rawRadiation, 1.0E-07, "Raw radiation incorrect") + } + thenExecute { + context.destroyBlock(BlockPos(3,2,2)) + } + thenOnComputer { + radiation = callPeripheral("right", "getRadiation") + rawRadiation = callPeripheral("right", "getRadiationRaw")?.get(0) as Double + } + thenWaitUntil { + if (radiation?.get(0) == null) + context.fail("Radiation not set") + val value = (radiation?.get(0) as Map<*, *>)["radiation"] + if (value == null) { + context.fail("Radiation not found") + } + context.assertDoubleInRange(value.toString().toDouble(), 2.49,2.51,"Radiation incorrect") + + context.assertDoubleInRange(rawRadiation, 2.49,2.51,"Raw radiation incorrect") + RadiationManager.INSTANCE.clearSources() + } + } } \ No newline at end of file diff --git a/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.mekanismradiation.snbt b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.mekanismradiation.snbt new file mode 100644 index 000000000..35eee5557 --- /dev/null +++ b/src/testMod/resources/data/advancedperipheralstest/structures/modintegrtest.mekanismradiation.snbt @@ -0,0 +1,139 @@ +{ + DataVersion: 3120, + size: [5, 5, 5], + data: [ + {pos: [0, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [0, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [1, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [2, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [3, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 0], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 1], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 2], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 3], state: "minecraft:polished_andesite"}, + {pos: [4, 0, 4], state: "minecraft:polished_andesite"}, + {pos: [0, 1, 0], state: "minecraft:air"}, + {pos: [0, 1, 1], state: "minecraft:air"}, + {pos: [0, 1, 2], state: "minecraft:air"}, + {pos: [0, 1, 3], state: "minecraft:air"}, + {pos: [0, 1, 4], state: "minecraft:air"}, + {pos: [1, 1, 0], state: "minecraft:air"}, + {pos: [1, 1, 1], state: "minecraft:air"}, + {pos: [1, 1, 2], state: "advancedperipherals:environment_detector{orientation:north_up}", nbt: {ForgeCaps: {}, Items: [], id: "advancedperipherals:environment_detector"}}, + {pos: [1, 1, 3], state: "minecraft:air"}, + {pos: [1, 1, 4], state: "minecraft:air"}, + {pos: [2, 1, 0], state: "minecraft:air"}, + {pos: [2, 1, 1], state: "minecraft:air"}, + {pos: [2, 1, 2], state: "computercraft:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, ForgeCaps: {}, Label: "modintegrtest.mekanismradiation", On: 1b, id: "computercraft:computer_advanced"}}, + {pos: [2, 1, 3], state: "minecraft:air"}, + {pos: [2, 1, 4], state: "minecraft:air"}, + {pos: [3, 1, 0], state: "minecraft:air"}, + {pos: [3, 1, 1], state: "minecraft:air"}, + {pos: [3, 1, 2], state: "mekanism:radioactive_waste_barrel{active:false,facing:north,fluid_logged:empty}", nbt: {ForgeCaps: {}, GasTanks: [{Tank: 0b, stored: {amount: 1000L, gasName: "mekanism:spent_nuclear_waste"}}], activeState: 0b, componentFrequency: {}, currentRedstone: 14, id: "mekanism:radioactive_waste_barrel", redstone: 0b, updateDelay: 0}}, + {pos: [3, 1, 3], state: "minecraft:air"}, + {pos: [3, 1, 4], state: "minecraft:air"}, + {pos: [4, 1, 0], state: "minecraft:air"}, + {pos: [4, 1, 1], state: "minecraft:air"}, + {pos: [4, 1, 2], state: "minecraft:air"}, + {pos: [4, 1, 3], state: "minecraft:air"}, + {pos: [4, 1, 4], state: "minecraft:air"}, + {pos: [0, 2, 0], state: "minecraft:air"}, + {pos: [0, 2, 1], state: "minecraft:air"}, + {pos: [0, 2, 2], state: "minecraft:air"}, + {pos: [0, 2, 3], state: "minecraft:air"}, + {pos: [0, 2, 4], state: "minecraft:air"}, + {pos: [1, 2, 0], state: "minecraft:air"}, + {pos: [1, 2, 1], state: "minecraft:air"}, + {pos: [1, 2, 2], state: "minecraft:air"}, + {pos: [1, 2, 3], state: "minecraft:air"}, + {pos: [1, 2, 4], state: "minecraft:air"}, + {pos: [2, 2, 0], state: "minecraft:air"}, + {pos: [2, 2, 1], state: "minecraft:air"}, + {pos: [2, 2, 2], state: "minecraft:air"}, + {pos: [2, 2, 3], state: "minecraft:air"}, + {pos: [2, 2, 4], state: "minecraft:air"}, + {pos: [3, 2, 0], state: "minecraft:air"}, + {pos: [3, 2, 1], state: "minecraft:air"}, + {pos: [3, 2, 2], state: "minecraft:air"}, + {pos: [3, 2, 3], state: "minecraft:air"}, + {pos: [3, 2, 4], state: "minecraft:air"}, + {pos: [4, 2, 0], state: "minecraft:air"}, + {pos: [4, 2, 1], state: "minecraft:air"}, + {pos: [4, 2, 2], state: "minecraft:air"}, + {pos: [4, 2, 3], state: "minecraft:air"}, + {pos: [4, 2, 4], state: "minecraft:air"}, + {pos: [0, 3, 0], state: "minecraft:air"}, + {pos: [0, 3, 1], state: "minecraft:air"}, + {pos: [0, 3, 2], state: "minecraft:air"}, + {pos: [0, 3, 3], state: "minecraft:air"}, + {pos: [0, 3, 4], state: "minecraft:air"}, + {pos: [1, 3, 0], state: "minecraft:air"}, + {pos: [1, 3, 1], state: "minecraft:air"}, + {pos: [1, 3, 2], state: "minecraft:air"}, + {pos: [1, 3, 3], state: "minecraft:air"}, + {pos: [1, 3, 4], state: "minecraft:air"}, + {pos: [2, 3, 0], state: "minecraft:air"}, + {pos: [2, 3, 1], state: "minecraft:air"}, + {pos: [2, 3, 2], state: "minecraft:air"}, + {pos: [2, 3, 3], state: "minecraft:air"}, + {pos: [2, 3, 4], state: "minecraft:air"}, + {pos: [3, 3, 0], state: "minecraft:air"}, + {pos: [3, 3, 1], state: "minecraft:air"}, + {pos: [3, 3, 2], state: "minecraft:air"}, + {pos: [3, 3, 3], state: "minecraft:air"}, + {pos: [3, 3, 4], state: "minecraft:air"}, + {pos: [4, 3, 0], state: "minecraft:air"}, + {pos: [4, 3, 1], state: "minecraft:air"}, + {pos: [4, 3, 2], state: "minecraft:air"}, + {pos: [4, 3, 3], state: "minecraft:air"}, + {pos: [4, 3, 4], state: "minecraft:air"}, + {pos: [0, 4, 0], state: "minecraft:air"}, + {pos: [0, 4, 1], state: "minecraft:air"}, + {pos: [0, 4, 2], state: "minecraft:air"}, + {pos: [0, 4, 3], state: "minecraft:air"}, + {pos: [0, 4, 4], state: "minecraft:air"}, + {pos: [1, 4, 0], state: "minecraft:air"}, + {pos: [1, 4, 1], state: "minecraft:air"}, + {pos: [1, 4, 2], state: "minecraft:air"}, + {pos: [1, 4, 3], state: "minecraft:air"}, + {pos: [1, 4, 4], state: "minecraft:air"}, + {pos: [2, 4, 0], state: "minecraft:air"}, + {pos: [2, 4, 1], state: "minecraft:air"}, + {pos: [2, 4, 2], state: "minecraft:air"}, + {pos: [2, 4, 3], state: "minecraft:air"}, + {pos: [2, 4, 4], state: "minecraft:air"}, + {pos: [3, 4, 0], state: "minecraft:air"}, + {pos: [3, 4, 1], state: "minecraft:air"}, + {pos: [3, 4, 2], state: "minecraft:air"}, + {pos: [3, 4, 3], state: "minecraft:air"}, + {pos: [3, 4, 4], state: "minecraft:air"}, + {pos: [4, 4, 0], state: "minecraft:air"}, + {pos: [4, 4, 1], state: "minecraft:air"}, + {pos: [4, 4, 2], state: "minecraft:air"}, + {pos: [4, 4, 3], state: "minecraft:air"}, + {pos: [4, 4, 4], state: "minecraft:air"} + ], + entities: [], + palette: [ + "minecraft:polished_andesite", + "minecraft:air", + "advancedperipherals:environment_detector{orientation:north_up}", + "computercraft:computer_advanced{facing:north,state:blinking}", + "mekanism:radioactive_waste_barrel{active:false,facing:north,fluid_logged:empty}" + ] +}