From a2b9490d5c9787e87e5eb8bca9452c9615b9609c Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 14 Jan 2025 09:38:22 +0000 Subject: [PATCH] Some printer gametests These are a little ugly, but do catch some issues we've seen in the past. Fixes #1682 (for now), and on its birthday too! --- .../printer/PrinterBlockEntity.java | 3 +- .../computercraft/gametest/Printer_Test.kt | 142 +++++++++++++++--- .../computercraft/gametest/Turtle_Test.kt | 63 ++++---- ...tes_state.snbt => printer_test.empty.snbt} | 0 .../printer_test.no_print_when_full.snbt | 137 +++++++++++++++++ 5 files changed, 287 insertions(+), 58 deletions(-) rename projects/common/src/testMod/resources/data/cctest/structures/{printer_test.contents_updates_state.snbt => printer_test.empty.snbt} (100%) create mode 100644 projects/common/src/testMod/resources/data/cctest/structures/printer_test.no_print_when_full.snbt diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java index f6037802a..a593e6836 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterBlockEntity.java @@ -166,8 +166,7 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple } private boolean canInputPage() { - var inkStack = inventory.get(0); - return !inkStack.isEmpty() && isInk(inkStack) && getPaperLevel() > 0; + return getInkLevel() > 0 && getPaperLevel() > 0; } private boolean inputPage() { diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt index fd8577c3e..b86931900 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Printer_Test.kt @@ -4,12 +4,13 @@ package dan200.computercraft.gametest -import dan200.computercraft.gametest.api.assertBlockHas -import dan200.computercraft.gametest.api.assertExactlyItems -import dan200.computercraft.gametest.api.getBlockEntity -import dan200.computercraft.gametest.api.sequence +import dan200.computercraft.api.lua.Coerced +import dan200.computercraft.api.lua.LuaException +import dan200.computercraft.gametest.api.* import dan200.computercraft.shared.ModRegistry +import dan200.computercraft.shared.media.items.PrintoutItem import dan200.computercraft.shared.peripheral.printer.PrinterBlock +import dan200.computercraft.shared.peripheral.printer.PrinterPeripheral import net.minecraft.core.BlockPos import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper @@ -17,10 +18,12 @@ import net.minecraft.network.chat.Component import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import net.minecraft.world.level.block.RedStoneWireBlock +import org.junit.jupiter.api.Assertions.* +import java.util.* class Printer_Test { /** - * Check comparators can read the contents of the disk drive + * Check comparators can read the contents of the printer */ @GameTest fun Comparator(helper: GameTestHelper) = helper.sequence { @@ -29,19 +32,19 @@ class Printer_Test { // Adding items should provide power thenExecute { - val drive = helper.getBlockEntity(printerPos, ModRegistry.BlockEntities.PRINTER.get()) - drive.setItem(0, ItemStack(Items.BLACK_DYE)) - drive.setItem(1, ItemStack(Items.PAPER)) - drive.setChanged() + val printer = helper.getBlockEntity(printerPos, ModRegistry.BlockEntities.PRINTER.get()) + printer.setItem(0, ItemStack(Items.BLACK_DYE)) + printer.setItem(1, ItemStack(Items.PAPER)) + printer.setChanged() } thenIdle(2) thenExecute { helper.assertBlockHas(dustPos, RedStoneWireBlock.POWER, 1) } // And removing them should reset power. thenExecute { - val drive = helper.getBlockEntity(printerPos, ModRegistry.BlockEntities.PRINTER.get()) - drive.clearContent() - drive.setChanged() + val printer = helper.getBlockEntity(printerPos, ModRegistry.BlockEntities.PRINTER.get()) + printer.clearContent() + printer.setChanged() } thenIdle(2) thenExecute { helper.assertBlockHas(dustPos, RedStoneWireBlock.POWER, 0) } @@ -50,35 +53,125 @@ class Printer_Test { /** * Changing the inventory contents updates the block state */ - @GameTest + @GameTest(template = "printer_test.empty") fun Contents_updates_state(helper: GameTestHelper) = helper.sequence { val pos = BlockPos(2, 2, 2) thenExecute { - val drive = helper.getBlockEntity(pos, ModRegistry.BlockEntities.PRINTER.get()) + val printer = helper.getBlockEntity(pos, ModRegistry.BlockEntities.PRINTER.get()) - drive.setItem(1, ItemStack(Items.PAPER)) - drive.setChanged() + printer.setItem(1, ItemStack(Items.PAPER)) + printer.setChanged() helper.assertBlockHas(pos, PrinterBlock.TOP, true, message = "One item in the top row") helper.assertBlockHas(pos, PrinterBlock.BOTTOM, false, message = "One item in the top row") - drive.setItem(7, ItemStack(Items.PAPER)) - drive.setChanged() + printer.setItem(7, ItemStack(Items.PAPER)) + printer.setChanged() helper.assertBlockHas(pos, PrinterBlock.TOP, true, message = "One item in each row") helper.assertBlockHas(pos, PrinterBlock.BOTTOM, true, message = "One item in each row") - drive.setItem(1, ItemStack.EMPTY) - drive.setChanged() + printer.setItem(1, ItemStack.EMPTY) + printer.setChanged() helper.assertBlockHas(pos, PrinterBlock.TOP, false, message = "One item in the bottom") helper.assertBlockHas(pos, PrinterBlock.BOTTOM, true, message = "One item in the bottom row") - drive.setItem(7, ItemStack.EMPTY) - drive.setChanged() + printer.setItem(7, ItemStack.EMPTY) + printer.setChanged() helper.assertBlockHas(pos, PrinterBlock.TOP, false, message = "Empty") helper.assertBlockHas(pos, PrinterBlock.BOTTOM, false, message = "Empty") } } + /** + * Printing a page + */ + @GameTest(template = "printer_test.empty") + fun Print_page(helper: GameTestHelper) = helper.sequence { + val pos = BlockPos(2, 2, 2) + + thenExecute { + val printer = helper.getBlockEntity(pos, ModRegistry.BlockEntities.PRINTER.get()) + val peripheral = printer.peripheral() as PrinterPeripheral + + // Try to print with no pages + assertFalse(peripheral.newPage(), "newPage fails with no items") + + // Try to print with just ink + printer.setItem(0, ItemStack(Items.BLUE_DYE)) + printer.setChanged() + assertFalse(peripheral.newPage(), "newPage fails with no paper") + + printer.clearContent() + + // Try to print with just paper + printer.setItem(1, ItemStack(Items.PAPER)) + printer.setChanged() + assertFalse(peripheral.newPage(), "newPage fails with no ink") + + printer.clearContent() + + // Try to print with both items + printer.setItem(0, ItemStack(Items.BLUE_DYE)) + printer.setItem(1, ItemStack(Items.PAPER)) + printer.setChanged() + assertTrue(peripheral.newPage(), "newPage succeeds") + + // newPage() should consume both items and update the block state + helper.assertContainerEmpty(pos) + helper.assertBlockHas(pos, PrinterBlock.TOP, false, message = "Empty") + helper.assertBlockHas(pos, PrinterBlock.BOTTOM, false, message = "Empty") + + assertFalse(peripheral.newPage(), "Cannot start a page when already printing") + + peripheral.setPageTitle(Optional.of("New Page")) + peripheral.write(Coerced("Hello, world!")) + peripheral.setCursorPos(5, 2) + peripheral.write(Coerced("Second line")) + + // Try to finish the page + assertTrue(peripheral.endPage(), "endPage prints item") + + // endPage() should + helper.assertBlockHas(pos, PrinterBlock.TOP, false, message = "Empty") + helper.assertBlockHas(pos, PrinterBlock.BOTTOM, true, message = "Has pages") + + // And check the inventory matches + val lines = createPageOf(' ') + lines[0] = "Hello, world! " + lines[1] = " Second line " + helper.assertContainerExactly( + pos, + listOf( + // Ink + ItemStack.EMPTY, + // Paper + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + // Pages + PrintoutItem.createSingleFromTitleAndText("New Page", lines, createPageOf('b')), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ), + ) + + val error = assertThrows(LuaException::class.java) { peripheral.endPage() } + assertEquals("Page not started", error.message) + } + } + + /** + * Can't print when full. + */ + @GameTest + fun No_print_when_full(helper: GameTestHelper) = helper.sequence { + val pos = BlockPos(2, 2, 2) + + thenExecute { + val printer = helper.getBlockEntity(pos, ModRegistry.BlockEntities.PRINTER.get()) + val peripheral = printer.peripheral() as PrinterPeripheral + assertTrue(peripheral.newPage()) + assertFalse(peripheral.endPage(), "Cannot print when full") + } + } + /** * When the block is broken, we drop the contents and an optionally named stack. */ @@ -94,4 +187,9 @@ class Printer_Test { ) } } + + private fun createPageOf(c: Char): Array { + val line = c.toString().repeat(PrintoutItem.LINE_MAX_LENGTH) + return Array(PrintoutItem.LINES_PER_PAGE) { line } + } } diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt index 1b1f58ade..69b113f0b 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt @@ -29,7 +29,6 @@ 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 dan200.computercraft.test.shared.ItemStackMatcher.isStack import net.minecraft.core.BlockPos import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper @@ -46,7 +45,8 @@ import net.minecraft.world.level.block.FenceBlock import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.properties.BlockStateProperties import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.* +import org.hamcrest.Matchers.array +import org.hamcrest.Matchers.instanceOf import org.junit.jupiter.api.Assertions.* import java.util.* import java.util.concurrent.CopyOnWriteArrayList @@ -138,7 +138,7 @@ class Turtle_Test { ) } thenExecute { - helper.assertBlockIs(BlockPos(2, 2, 2)) { it.block == Blocks.COMPOSTER && it.getValue(ComposterBlock.LEVEL) == 2 } + helper.assertBlockHas(BlockPos(2, 2, 2), ComposterBlock.LEVEL, 2) } } @@ -154,7 +154,7 @@ class Turtle_Test { .assertArrayEquals(false, "Cannot place item here", message = "Failed to place item") } thenExecute { - helper.assertBlockIs(BlockPos(2, 2, 3)) { it.block == Blocks.COMPOSTER && it.getValue(ComposterBlock.LEVEL) == 0 } + helper.assertBlockHas(BlockPos(2, 2, 3), ComposterBlock.LEVEL, 0) } } @@ -175,7 +175,7 @@ class Turtle_Test { ) } thenExecute { - helper.assertBlockIs(BlockPos(2, 2, 2)) { it.block == Blocks.BEEHIVE && it.getValue(BeehiveBlock.HONEY_LEVEL) == 0 } + helper.assertBlockHas(BlockPos(2, 2, 2), BeehiveBlock.HONEY_LEVEL, 0) } } @@ -765,15 +765,13 @@ class Turtle_Test { callPeripheral("left", "craft", 1).assertArrayEquals(true) } thenExecute { - val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()) - assertThat( - "Inventory is as expected.", - turtle.contents, - contains( - isStack(Items.DIAMOND, 1), isStack(Items.DIAMOND, 1), isStack(Items.DIAMOND, 1), isStack(Items.DIAMOND_PICKAXE, 1), - isStack(ItemStack.EMPTY), isStack(Items.STICK, 1), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(Items.STICK, 1), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), + helper.assertContainerExactly( + BlockPos(2, 2, 2), + listOf( + ItemStack(Items.DIAMOND), ItemStack(Items.DIAMOND), ItemStack(Items.DIAMOND), ItemStack(Items.DIAMOND_PICKAXE), + ItemStack.EMPTY, ItemStack(Items.STICK), ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack(Items.STICK), ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ), ) } @@ -786,23 +784,20 @@ class Turtle_Test { */ @GameTest fun Craft_remainder(helper: GameTestHelper) = helper.sequence { - thenOnComputer { - callPeripheral("left", "craft", 1).assertArrayEquals(true) - } thenExecute { val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()) + assertTrue(TurtleCraftCommand(1).execute(turtle.access).isSuccess, "Crafting succeeded") val turtleStack = ItemStack(ModRegistry.Items.TURTLE_NORMAL.get()) turtleStack.orCreateTag - assertThat( - "Inventory is as expected.", - turtle.contents, - contains( - isStack(turtleStack), isStack(Items.WET_SPONGE, 1), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), + helper.assertContainerExactly( + BlockPos(2, 2, 2), + listOf( + turtleStack, ItemStack(Items.WET_SPONGE), ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ), ) } @@ -817,7 +812,8 @@ class Turtle_Test { fun Craft_offset(helper: GameTestHelper) = helper.sequence { for (offset in listOf(0, 1, 4, 5)) { thenExecute { - val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()) + val turtlePos = BlockPos(2, 2, 2) + val turtle = helper.getBlockEntity(turtlePos, ModRegistry.BlockEntities.TURTLE_NORMAL.get()) // Set up turtle inventory turtle.clearContent() @@ -831,14 +827,13 @@ class Turtle_Test { assertTrue(TurtleCraftCommand(1).execute(turtle.access).isSuccess, "Crafting succeeded") // And check item was crafted - assertThat( - "Inventory is as expected.", - turtle.contents, - contains( - isStack(Items.STONE_PICKAXE, 1), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), - isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), isStack(ItemStack.EMPTY), + helper.assertContainerExactly( + turtlePos, + listOf( + ItemStack(Items.STONE_PICKAXE), ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, ), ) } diff --git a/projects/common/src/testMod/resources/data/cctest/structures/printer_test.contents_updates_state.snbt b/projects/common/src/testMod/resources/data/cctest/structures/printer_test.empty.snbt similarity index 100% rename from projects/common/src/testMod/resources/data/cctest/structures/printer_test.contents_updates_state.snbt rename to projects/common/src/testMod/resources/data/cctest/structures/printer_test.empty.snbt diff --git a/projects/common/src/testMod/resources/data/cctest/structures/printer_test.no_print_when_full.snbt b/projects/common/src/testMod/resources/data/cctest/structures/printer_test.no_print_when_full.snbt new file mode 100644 index 000000000..7a742b2fc --- /dev/null +++ b/projects/common/src/testMod/resources/data/cctest/structures/printer_test.no_print_when_full.snbt @@ -0,0 +1,137 @@ +{ + DataVersion: 3465, + 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:printer{bottom:true,facing:north,top:true}", nbt: {Items: [{Count: 1b, Slot: 0b, id: "minecraft:black_dye"}, {Count: 1b, Slot: 1b, id: "minecraft:paper"}, {Count: 1b, Slot: 7b, 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: " ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: ""}}, {Count: 1b, Slot: 8b, 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: " ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: ""}}, {Count: 1b, Slot: 9b, 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: " ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: ""}}, {Count: 1b, Slot: 10b, 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: " ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: ""}}, {Count: 1b, Slot: 11b, 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: " ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: ""}}, {Count: 1b, Slot: 12b, 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: " ", Text1: " ", Text10: " ", Text11: " ", Text12: " ", Text13: " ", Text14: " ", Text15: " ", Text16: " ", Text17: " ", Text18: " ", Text19: " ", Text2: " ", Text20: " ", Text3: " ", Text4: " ", Text5: " ", Text6: " ", Text7: " ", Text8: " ", Text9: " ", Title: ""}}], 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: 15, term_textColour_0: "fffffffffffffffffffffffff", term_textColour_1: "fffffffffffffffffffffffff", term_textColour_10: "fffffffffffffffffffffffff", term_textColour_11: "fffffffffffffffffffffffff", term_textColour_12: "fffffffffffffffffffffffff", term_textColour_13: "fffffffffffffffffffffffff", term_textColour_14: "fffffffffffffffffffffffff", term_textColour_15: "fffffffffffffffffffffffff", term_textColour_16: "fffffffffffffffffffffffff", term_textColour_17: "fffffffffffffffffffffffff", term_textColour_18: "fffffffffffffffffffffffff", term_textColour_19: "fffffffffffffffffffffffff", term_textColour_2: "fffffffffffffffffffffffff", term_textColour_20: "fffffffffffffffffffffffff", term_textColour_3: "fffffffffffffffffffffffff", term_textColour_4: "fffffffffffffffffffffffff", term_textColour_5: "fffffffffffffffffffffffff", term_textColour_6: "fffffffffffffffffffffffff", term_textColour_7: "fffffffffffffffffffffffff", term_textColour_8: "fffffffffffffffffffffffff", term_textColour_9: "fffffffffffffffffffffffff", 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: [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:printer{bottom:true,facing:north,top:true}" + ] +}